xref: /illumos-gate/usr/src/uts/common/io/hme/hme.c (revision e8717ca234d52a19424cf76f49488e8a2f6f3e14)
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 /*
22*e8717ca2SGarrett D'Amore  * 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 /*
287c478bd9Sstevel@tonic-gate  * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include	<sys/types.h>
327c478bd9Sstevel@tonic-gate #include	<sys/debug.h>
337c478bd9Sstevel@tonic-gate #include	<sys/stream.h>
347c478bd9Sstevel@tonic-gate #include	<sys/cmn_err.h>
357c478bd9Sstevel@tonic-gate #include	<sys/kmem.h>
367c478bd9Sstevel@tonic-gate #include	<sys/crc32.h>
3785025c03Sgd #include	<sys/modctl.h>
3885025c03Sgd #include	<sys/conf.h>
397c478bd9Sstevel@tonic-gate #include	<sys/strsun.h>
407c478bd9Sstevel@tonic-gate #include	<sys/kstat.h>
4185025c03Sgd #include	<sys/pattr.h>
427c478bd9Sstevel@tonic-gate #include	<sys/dlpi.h>
4385025c03Sgd #include	<sys/strsubr.h>
44da14cebeSEric Cheng #include	<sys/mac_provider.h>
4585025c03Sgd #include	<sys/mac_ether.h>
4606673d9bSGarrett D'Amore #include	<sys/mii.h>
477c478bd9Sstevel@tonic-gate #include	<sys/ethernet.h>
48d62bc4baSyz #include	<sys/vlan.h>
4985025c03Sgd #include	<sys/pci.h>
5085025c03Sgd #include	<sys/policy.h>
5185025c03Sgd #include	<sys/ddi.h>
5285025c03Sgd #include	<sys/sunddi.h>
530219346bSGarrett D'Amore #include	"hme_phy.h"
540219346bSGarrett D'Amore #include	"hme_mac.h"
550219346bSGarrett D'Amore #include	"hme.h"
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate typedef void	(*fptrv_t)();
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate typedef enum {
607c478bd9Sstevel@tonic-gate 	NO_MSG		= 0,
6106673d9bSGarrett D'Amore 	AUTOCONFIG_MSG,
6206673d9bSGarrett D'Amore 	DISPLAY_MSG,
6306673d9bSGarrett D'Amore 	INIT_MSG,
6406673d9bSGarrett D'Amore 	UNINIT_MSG,
6506673d9bSGarrett D'Amore 	CONFIG_MSG,
6606673d9bSGarrett D'Amore 	MII_MSG,
6706673d9bSGarrett D'Amore 	FATAL_ERR_MSG,
6806673d9bSGarrett D'Amore 	NFATAL_ERR_MSG,
6906673d9bSGarrett D'Amore 	XCVR_MSG,
7006673d9bSGarrett D'Amore 	NOXCVR_MSG,
7106673d9bSGarrett D'Amore 	ERX_MSG,
7206673d9bSGarrett D'Amore 	DDI_MSG,
737c478bd9Sstevel@tonic-gate } msg_t;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate msg_t	hme_debug_level =	NO_MSG;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static char	*msg_string[] = {
787c478bd9Sstevel@tonic-gate 	"NONE       ",
797c478bd9Sstevel@tonic-gate 	"AUTOCONFIG ",
8006673d9bSGarrett D'Amore 	"DISPLAY	"
817c478bd9Sstevel@tonic-gate 	"INIT       ",
827c478bd9Sstevel@tonic-gate 	"UNINIT		",
837c478bd9Sstevel@tonic-gate 	"CONFIG	",
8406673d9bSGarrett D'Amore 	"MII	",
857c478bd9Sstevel@tonic-gate 	"FATAL_ERR	",
867c478bd9Sstevel@tonic-gate 	"NFATAL_ERR	",
877c478bd9Sstevel@tonic-gate 	"XCVR	",
887c478bd9Sstevel@tonic-gate 	"NOXCVR	",
897c478bd9Sstevel@tonic-gate 	"ERX	",
907c478bd9Sstevel@tonic-gate 	"DDI	",
917c478bd9Sstevel@tonic-gate };
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	SEVERITY_NONE	0
947c478bd9Sstevel@tonic-gate #define	SEVERITY_LOW	0
957c478bd9Sstevel@tonic-gate #define	SEVERITY_MID	1
967c478bd9Sstevel@tonic-gate #define	SEVERITY_HIGH	2
977c478bd9Sstevel@tonic-gate #define	SEVERITY_UNKNOWN 99
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate #define	FEPS_URUN_BUG
1007c478bd9Sstevel@tonic-gate #define	HME_CODEVIOL_BUG
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #define	KIOIP	KSTAT_INTR_PTR(hmep->hme_intrstats)
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * The following variables are used for checking fixes in Sbus/FEPS 2.0
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate static	int	hme_urun_fix = 0;	/* Bug fixed in Sbus/FEPS 2.0 */
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * The following variables are used for configuring various features
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate static	int	hme_64bit_enable =	1;	/* Use 64-bit sbus transfers */
1137c478bd9Sstevel@tonic-gate static	int	hme_reject_own =	1;	/* Reject packets with own SA */
11406673d9bSGarrett D'Amore static	int	hme_ngu_enable =	0;	/* Never Give Up mode */
1157c478bd9Sstevel@tonic-gate 
11606673d9bSGarrett D'Amore mac_priv_prop_t hme_priv_prop[] = {
11706673d9bSGarrett D'Amore 	{	"_ipg0",	MAC_PROP_PERM_RW	},
11806673d9bSGarrett D'Amore 	{	"_ipg1",	MAC_PROP_PERM_RW	},
11906673d9bSGarrett D'Amore 	{	"_ipg2",	MAC_PROP_PERM_RW	},
12006673d9bSGarrett D'Amore 	{	"_lance_mode",	MAC_PROP_PERM_RW	},
12106673d9bSGarrett D'Amore };
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static	int	hme_lance_mode =	1;	/* to enable lance mode */
1247c478bd9Sstevel@tonic-gate static	int	hme_ipg0 =		16;
1257c478bd9Sstevel@tonic-gate static	int	hme_ipg1 =		8;
1267c478bd9Sstevel@tonic-gate static	int	hme_ipg2 =		4;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate  * The following parameters may be configured by the user. If they are not
1307c478bd9Sstevel@tonic-gate  * configured by the user, the values will be based on the capabilities of
1317c478bd9Sstevel@tonic-gate  * the transceiver.
1327c478bd9Sstevel@tonic-gate  * The value "HME_NOTUSR" is ORed with the parameter value to indicate values
1337c478bd9Sstevel@tonic-gate  * which are NOT configured by the user.
1347c478bd9Sstevel@tonic-gate  */
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate #define	HME_NOTUSR	0x0f000000
1377c478bd9Sstevel@tonic-gate #define	HME_MASK_1BIT	0x1
1387c478bd9Sstevel@tonic-gate #define	HME_MASK_5BIT	0x1f
1397c478bd9Sstevel@tonic-gate #define	HME_MASK_8BIT	0xff
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * All strings used by hme messaging functions
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate static	char *no_xcvr_msg =
1467c478bd9Sstevel@tonic-gate 	"No transceiver found.";
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate static	char *burst_size_msg =
1497c478bd9Sstevel@tonic-gate 	"Could not identify the burst size";
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static	char *unk_rx_ringsz_msg =
1527c478bd9Sstevel@tonic-gate 	"Unknown receive RINGSZ";
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static  char *add_intr_fail_msg =
1557c478bd9Sstevel@tonic-gate 	"ddi_add_intr(9F) failed";
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate static  char *mregs_4global_reg_fail_msg =
1587c478bd9Sstevel@tonic-gate 	"ddi_regs_map_setup(9F) for global reg failed";
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate static	char *mregs_4etx_reg_fail_msg =
1617c478bd9Sstevel@tonic-gate 	"ddi_map_regs for etx reg failed";
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate static	char *mregs_4erx_reg_fail_msg =
1647c478bd9Sstevel@tonic-gate 	"ddi_map_regs for erx reg failed";
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static	char *mregs_4bmac_reg_fail_msg =
1677c478bd9Sstevel@tonic-gate 	"ddi_map_regs for bmac reg failed";
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static	char *mregs_4mif_reg_fail_msg =
1707c478bd9Sstevel@tonic-gate 	"ddi_map_regs for mif reg failed";
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate static	char *init_fail_gen_msg =
1737c478bd9Sstevel@tonic-gate 	"Failed to initialize hardware/driver";
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate static	char *ddi_nregs_fail_msg =
1767c478bd9Sstevel@tonic-gate 	"ddi_dev_nregs failed(9F), returned %d";
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate static	char *bad_num_regs_msg =
1797c478bd9Sstevel@tonic-gate 	"Invalid number of registers.";
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /* FATAL ERR msgs */
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * Function prototypes.
1857c478bd9Sstevel@tonic-gate  */
186f2cd0f02Sgd /* these two are global so that qfe can use them */
187f2cd0f02Sgd int hmeattach(dev_info_t *, ddi_attach_cmd_t);
188f2cd0f02Sgd int hmedetach(dev_info_t *, ddi_detach_cmd_t);
1890219346bSGarrett D'Amore int hmequiesce(dev_info_t *);
19085025c03Sgd static	boolean_t hmeinit_xfer_params(struct hme *);
1917c478bd9Sstevel@tonic-gate static	uint_t hmestop(struct hme *);
1927c478bd9Sstevel@tonic-gate static	void hmestatinit(struct hme *);
1937c478bd9Sstevel@tonic-gate static	int hmeallocthings(struct hme *);
1940219346bSGarrett D'Amore static	void hmefreethings(struct hme *);
1950219346bSGarrett D'Amore static	int hmeallocbuf(struct hme *, hmebuf_t *, int);
1960219346bSGarrett D'Amore static	int hmeallocbufs(struct hme *);
1977c478bd9Sstevel@tonic-gate static	void hmefreebufs(struct hme *);
1987c478bd9Sstevel@tonic-gate static	void hmeget_hm_rev_property(struct hme *);
19985025c03Sgd static	boolean_t hmestart(struct hme *, mblk_t *);
20085025c03Sgd static	uint_t hmeintr(caddr_t);
2017c478bd9Sstevel@tonic-gate static	void hmereclaim(struct hme *);
2027c478bd9Sstevel@tonic-gate static	int hmeinit(struct hme *);
2037c478bd9Sstevel@tonic-gate static	void hmeuninit(struct hme *hmep);
2040219346bSGarrett D'Amore static 	mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t);
2057c478bd9Sstevel@tonic-gate static	void hmesavecntrs(struct hme *);
2067c478bd9Sstevel@tonic-gate static	void hme_fatal_err(struct hme *, uint_t);
2077c478bd9Sstevel@tonic-gate static	void hme_nonfatal_err(struct hme *, uint_t);
2087c478bd9Sstevel@tonic-gate static	int hmeburstsizes(struct hme *);
20906673d9bSGarrett D'Amore static	void send_bit(struct hme *, uint16_t);
21006673d9bSGarrett D'Amore static	uint16_t get_bit_std(uint8_t, struct hme *);
21106673d9bSGarrett D'Amore static	uint16_t hme_bb_mii_read(struct hme *, uint8_t, uint8_t);
21206673d9bSGarrett D'Amore static	void hme_bb_mii_write(struct hme *, uint8_t, uint8_t, uint16_t);
2137c478bd9Sstevel@tonic-gate static	void hme_bb_force_idle(struct hme *);
21406673d9bSGarrett D'Amore static	uint16_t hme_mii_read(void *, uint8_t, uint8_t);
21506673d9bSGarrett D'Amore static	void hme_mii_write(void *, uint8_t, uint8_t, uint16_t);
2167c478bd9Sstevel@tonic-gate static	void hme_setup_mac_address(struct hme *, dev_info_t *);
21706673d9bSGarrett D'Amore static	void hme_mii_notify(void *, link_state_t);
2187c478bd9Sstevel@tonic-gate 
2190219346bSGarrett D'Amore static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate static void hme_check_acc_handle(char *, uint_t, struct hme *,
22285025c03Sgd     ddi_acc_handle_t);
2237c478bd9Sstevel@tonic-gate 
22485025c03Sgd /*
22585025c03Sgd  * Nemo (GLDv3) Functions.
22685025c03Sgd  */
22785025c03Sgd static int	hme_m_stat(void *, uint_t, uint64_t *);
22885025c03Sgd static int	hme_m_start(void *);
22985025c03Sgd static void	hme_m_stop(void *);
23085025c03Sgd static int	hme_m_promisc(void *, boolean_t);
23185025c03Sgd static int	hme_m_multicst(void *, boolean_t, const uint8_t *);
23285025c03Sgd static int	hme_m_unicst(void *, const uint8_t *);
23385025c03Sgd static mblk_t	*hme_m_tx(void *, mblk_t *);
23485025c03Sgd static boolean_t	hme_m_getcapab(void *, mac_capab_t, void *);
23506673d9bSGarrett D'Amore static int hme_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
23606673d9bSGarrett D'Amore     uint_t, void *, uint_t *);
23706673d9bSGarrett D'Amore static int hme_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
23806673d9bSGarrett D'Amore     const void *);
23906673d9bSGarrett D'Amore 
24006673d9bSGarrett D'Amore static mii_ops_t hme_mii_ops = {
24106673d9bSGarrett D'Amore 	MII_OPS_VERSION,
24206673d9bSGarrett D'Amore 	hme_mii_read,
24306673d9bSGarrett D'Amore 	hme_mii_write,
24406673d9bSGarrett D'Amore 	hme_mii_notify,
24506673d9bSGarrett D'Amore 	NULL
24606673d9bSGarrett D'Amore };
24785025c03Sgd 
24885025c03Sgd static mac_callbacks_t hme_m_callbacks = {
24906673d9bSGarrett D'Amore 	MC_GETCAPAB | MC_SETPROP | MC_GETPROP,
25085025c03Sgd 	hme_m_stat,
25185025c03Sgd 	hme_m_start,
25285025c03Sgd 	hme_m_stop,
25385025c03Sgd 	hme_m_promisc,
25485025c03Sgd 	hme_m_multicst,
25585025c03Sgd 	hme_m_unicst,
25685025c03Sgd 	hme_m_tx,
25706673d9bSGarrett D'Amore 	NULL,
25885025c03Sgd 	hme_m_getcapab,
25906673d9bSGarrett D'Amore 	NULL,
26006673d9bSGarrett D'Amore 	NULL,
26106673d9bSGarrett D'Amore 	hme_m_setprop,
26206673d9bSGarrett D'Amore 	hme_m_getprop,
26385025c03Sgd };
26485025c03Sgd 
26585025c03Sgd DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach,
2660219346bSGarrett D'Amore     nodev, NULL, D_MP, NULL, hmequiesce);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG1(p, s, t, f) \
2690219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f));
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG2(p, s, t, f, a) \
2720219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f), (a));
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG3(p, s, t, f, a, b) \
2750219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f), (a), (b));
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG4(p, s, t, f, a, b, c) \
2780219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f), (a), (b), (c));
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate #define	CHECK_MIFREG() \
2817c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh)
2827c478bd9Sstevel@tonic-gate #define	CHECK_ETXREG() \
2837c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh)
2847c478bd9Sstevel@tonic-gate #define	CHECK_ERXREG() \
2857c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh)
2867c478bd9Sstevel@tonic-gate #define	CHECK_MACREG() \
2877c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh)
2887c478bd9Sstevel@tonic-gate #define	CHECK_GLOBREG() \
2897c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh)
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate  * Claim the device is ultra-capable of burst in the beginning.  Use
2937c478bd9Sstevel@tonic-gate  * the value returned by ddi_dma_burstsizes() to actually set the HME
2947c478bd9Sstevel@tonic-gate  * global configuration register later.
2957c478bd9Sstevel@tonic-gate  *
2967c478bd9Sstevel@tonic-gate  * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports
2977c478bd9Sstevel@tonic-gate  * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains
2987c478bd9Sstevel@tonic-gate  * the the burstsizes in both the lo and hi words.
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate #define	HMELIMADDRLO	((uint64_t)0x00000000)
3017c478bd9Sstevel@tonic-gate #define	HMELIMADDRHI	((uint64_t)0xffffffff)
3027c478bd9Sstevel@tonic-gate 
3030219346bSGarrett D'Amore /*
3040219346bSGarrett D'Amore  * Note that rx and tx data buffers can be arbitrarily aligned, but
3050219346bSGarrett D'Amore  * that the descriptor rings need to be aligned on 2K boundaries, per
3060219346bSGarrett D'Amore  * the spec.
3070219346bSGarrett D'Amore  */
3087c478bd9Sstevel@tonic-gate static ddi_dma_attr_t hme_dma_attr = {
3097c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* version number. */
3107c478bd9Sstevel@tonic-gate 	(uint64_t)HMELIMADDRLO,	/* low address */
3117c478bd9Sstevel@tonic-gate 	(uint64_t)HMELIMADDRHI,	/* high address */
3127c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* address counter max */
3130219346bSGarrett D'Amore 	(uint64_t)HME_HMDALIGN,	/* alignment */
3147c478bd9Sstevel@tonic-gate 	(uint_t)0x00700070,	/* dlim_burstsizes for 32 and 64 bit xfers */
3157c478bd9Sstevel@tonic-gate 	(uint32_t)0x1,		/* minimum transfer size */
3167c478bd9Sstevel@tonic-gate 	(uint64_t)0x7fffffff,	/* maximum transfer size */
3177c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* maximum segment size */
3187c478bd9Sstevel@tonic-gate 	1,			/* scatter/gather list length */
3197c478bd9Sstevel@tonic-gate 	512,			/* granularity */
3207c478bd9Sstevel@tonic-gate 	0			/* attribute flags */
3217c478bd9Sstevel@tonic-gate };
3227c478bd9Sstevel@tonic-gate 
3230219346bSGarrett D'Amore static ddi_device_acc_attr_t hme_buf_attr = {
3240219346bSGarrett D'Amore 	DDI_DEVICE_ATTR_V0,
3250219346bSGarrett D'Amore 	DDI_NEVERSWAP_ACC,
3260219346bSGarrett D'Amore 	DDI_STRICTORDER_ACC,	/* probably could allow merging & caching */
3270219346bSGarrett D'Amore 	DDI_DEFAULT_ACC,
3287c478bd9Sstevel@tonic-gate };
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate static uchar_t pci_latency_timer = 0;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
3367c478bd9Sstevel@tonic-gate 	&mod_driverops,	/* Type of module.  This one is a driver */
33785025c03Sgd 	"Sun HME 10/100 Mb Ethernet",
33885025c03Sgd 	&hme_dev_ops,	/* driver ops */
3397c478bd9Sstevel@tonic-gate };
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
3427c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
3437c478bd9Sstevel@tonic-gate };
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<  Register operations >>>>>>>>>>>>>>>>>>>>> */
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate #define	GET_MIFREG(reg) \
3487c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg)
3497c478bd9Sstevel@tonic-gate #define	PUT_MIFREG(reg, value) \
3507c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value)
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate #define	GET_ETXREG(reg) \
3537c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg)
3547c478bd9Sstevel@tonic-gate #define	PUT_ETXREG(reg, value) \
3557c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value)
3567c478bd9Sstevel@tonic-gate #define	GET_ERXREG(reg) \
3577c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg)
3587c478bd9Sstevel@tonic-gate #define	PUT_ERXREG(reg, value) \
3597c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value)
3607c478bd9Sstevel@tonic-gate #define	GET_MACREG(reg) \
3617c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg)
3627c478bd9Sstevel@tonic-gate #define	PUT_MACREG(reg, value) \
3637c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_bmacregh, \
3647c478bd9Sstevel@tonic-gate 		(uint32_t *)&hmep->hme_bmacregp->reg, value)
3657c478bd9Sstevel@tonic-gate #define	GET_GLOBREG(reg) \
3667c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg)
3677c478bd9Sstevel@tonic-gate #define	PUT_GLOBREG(reg, value) \
3687c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_globregh, \
3697c478bd9Sstevel@tonic-gate 		(uint32_t *)&hmep->hme_globregp->reg, value)
3700219346bSGarrett D'Amore #define	PUT_TMD(ptr, paddr, len, flags)					\
3710219346bSGarrett D'Amore 	ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \
3720219346bSGarrett D'Amore 	ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags,	\
3730219346bSGarrett D'Amore 	    len | flags)
3740219346bSGarrett D'Amore #define	GET_TMD_FLAGS(ptr)					\
3750219346bSGarrett D'Amore 	ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags)
3760219346bSGarrett D'Amore #define	PUT_RMD(ptr, paddr) \
3770219346bSGarrett D'Amore 	ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \
3780219346bSGarrett D'Amore 	ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags,	\
3790219346bSGarrett D'Amore 	    (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN)
3800219346bSGarrett D'Amore #define	GET_RMD_FLAGS(ptr)					\
3810219346bSGarrett D'Amore 	ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags)
3820219346bSGarrett D'Amore 
3837c478bd9Sstevel@tonic-gate #define	GET_ROM8(offset) \
3847c478bd9Sstevel@tonic-gate 	ddi_get8((hmep->hme_romh), (offset))
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate /*
3877c478bd9Sstevel@tonic-gate  * Ether_copy is not endian-correct. Define an endian-correct version.
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate #define	ether_bcopy(a, b) (bcopy(a, b, 6))
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate  * Ether-type is specifically big-endian, but data region is unknown endian
3937c478bd9Sstevel@tonic-gate  */
39485025c03Sgd #define	get_ether_type(ptr) \
39585025c03Sgd 	(((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13])))
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<  Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate #define	BMAC_DEFAULT_JAMSIZE	(0x04)		/* jamsize equals 4 */
4007c478bd9Sstevel@tonic-gate #define	BMAC_LONG_JAMSIZE	(0x10)		/* jamsize equals 0x10 */
4017c478bd9Sstevel@tonic-gate static	int 	jamsize = BMAC_DEFAULT_JAMSIZE;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate /*
4057c478bd9Sstevel@tonic-gate  * Calculate the bit in the multicast address filter that selects the given
4067c478bd9Sstevel@tonic-gate  * address.
4077c478bd9Sstevel@tonic-gate  */
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate static uint32_t
41085025c03Sgd hmeladrf_bit(const uint8_t *addr)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	uint32_t crc;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/*
4177c478bd9Sstevel@tonic-gate 	 * Just want the 6 most significant bits.
4187c478bd9Sstevel@tonic-gate 	 */
4197c478bd9Sstevel@tonic-gate 	return (crc >> 26);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<  Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate static void
42506673d9bSGarrett D'Amore send_bit(struct hme *hmep, uint16_t x)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbdata, x);
4287c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
4297c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate /*
4347c478bd9Sstevel@tonic-gate  * To read the MII register bits according to the IEEE Standard
4357c478bd9Sstevel@tonic-gate  */
43606673d9bSGarrett D'Amore static uint16_t
43706673d9bSGarrett D'Amore get_bit_std(uint8_t phyad, struct hme *hmep)
4387c478bd9Sstevel@tonic-gate {
43906673d9bSGarrett D'Amore 	uint16_t	x;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
4427c478bd9Sstevel@tonic-gate 	drv_usecwait(1);	/* wait for  >330 ns for stable data */
44306673d9bSGarrett D'Amore 	if (phyad == HME_INTERNAL_PHYAD)
4447c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0;
4457c478bd9Sstevel@tonic-gate 	else
4467c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0;
4477c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
4487c478bd9Sstevel@tonic-gate 	return (x);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate #define	SEND_BIT(x)		send_bit(hmep, x)
45206673d9bSGarrett D'Amore #define	GET_BIT_STD(phyad, x)	x = get_bit_std(phyad, hmep)
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate static void
45606673d9bSGarrett D'Amore hme_bb_mii_write(struct hme *hmep, uint8_t phyad, uint8_t regad, uint16_t data)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate 	int	i;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
4617c478bd9Sstevel@tonic-gate 	(void) hme_bb_force_idle(hmep);
4627c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
4637c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <OP> */
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
4667c478bd9Sstevel@tonic-gate 		SEND_BIT((phyad >> i) & 1);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
4707c478bd9Sstevel@tonic-gate 		SEND_BIT((regad >> i) & 1);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	SEND_BIT(1); SEND_BIT(0);	/* <TA> */
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
4767c478bd9Sstevel@tonic-gate 		SEND_BIT((data >> i) & 1);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
4807c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
48406673d9bSGarrett D'Amore static uint16_t
48506673d9bSGarrett D'Amore hme_bb_mii_read(struct hme *hmep, uint8_t phyad, uint8_t regad)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	int		i;
4887c478bd9Sstevel@tonic-gate 	uint32_t	x;
48906673d9bSGarrett D'Amore 	uint16_t	data = 0;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
4927c478bd9Sstevel@tonic-gate 	(void) hme_bb_force_idle(hmep);
4937c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
4947c478bd9Sstevel@tonic-gate 	SEND_BIT(1); SEND_BIT(0);	/* <OP> */
4957c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
4967c478bd9Sstevel@tonic-gate 		SEND_BIT((phyad >> i) & 1);
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
4997c478bd9Sstevel@tonic-gate 		SEND_BIT((regad >> i) & 1);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
5037c478bd9Sstevel@tonic-gate 
50406673d9bSGarrett D'Amore 	GET_BIT_STD(phyad, x);
50506673d9bSGarrett D'Amore 	GET_BIT_STD(phyad, x);		/* <TA> */
50606673d9bSGarrett D'Amore 	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
50706673d9bSGarrett D'Amore 		GET_BIT_STD(phyad, x);
50806673d9bSGarrett D'Amore 		data += (x << i);
5097c478bd9Sstevel@tonic-gate 	}
51006673d9bSGarrett D'Amore 	/*
51106673d9bSGarrett D'Amore 	 * Kludge to get the Transceiver out of hung mode
51206673d9bSGarrett D'Amore 	 */
51306673d9bSGarrett D'Amore 	GET_BIT_STD(phyad, x);
51406673d9bSGarrett D'Amore 	GET_BIT_STD(phyad, x);
51506673d9bSGarrett D'Amore 	GET_BIT_STD(phyad, x);
5167c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
51706673d9bSGarrett D'Amore 	return (data);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate static void
5227c478bd9Sstevel@tonic-gate hme_bb_force_idle(struct hme *hmep)
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	int	i;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	for (i = 0; i < 33; i++) {
5277c478bd9Sstevel@tonic-gate 		SEND_BIT(1);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
53706673d9bSGarrett D'Amore static uint16_t
53806673d9bSGarrett D'Amore hme_mii_read(void *arg, uint8_t phyad, uint8_t regad)
5397c478bd9Sstevel@tonic-gate {
54006673d9bSGarrett D'Amore 	struct hme	*hmep = arg;
5417c478bd9Sstevel@tonic-gate 	uint32_t	frame;
542*e8717ca2SGarrett D'Amore 	uint32_t	tmp_mif;
543*e8717ca2SGarrett D'Amore 	uint32_t	tmp_xif;
5447c478bd9Sstevel@tonic-gate 
545*e8717ca2SGarrett D'Amore 	tmp_mif = GET_MIFREG(mif_cfg);
546*e8717ca2SGarrett D'Amore 	tmp_xif = GET_MACREG(xifc);
547*e8717ca2SGarrett D'Amore 
548*e8717ca2SGarrett D'Amore 	switch (phyad) {
549*e8717ca2SGarrett D'Amore 	case HME_EXTERNAL_PHYAD:
550*e8717ca2SGarrett D'Amore 		PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
551*e8717ca2SGarrett D'Amore 		PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
552*e8717ca2SGarrett D'Amore 		break;
553*e8717ca2SGarrett D'Amore 	case HME_INTERNAL_PHYAD:
554*e8717ca2SGarrett D'Amore 		PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
555*e8717ca2SGarrett D'Amore 		PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
556*e8717ca2SGarrett D'Amore 		break;
557*e8717ca2SGarrett D'Amore 	default:
558*e8717ca2SGarrett D'Amore 		return (0xffff);
559*e8717ca2SGarrett D'Amore 	}
560*e8717ca2SGarrett D'Amore 
561*e8717ca2SGarrett D'Amore 	if (!hmep->hme_frame_enable) {
562*e8717ca2SGarrett D'Amore 		frame = (hme_bb_mii_read(hmep, phyad, regad));
563*e8717ca2SGarrett D'Amore 		PUT_MACREG(xifc, tmp_xif);
564*e8717ca2SGarrett D'Amore 		PUT_MIFREG(mif_cfg, tmp_mif);
565*e8717ca2SGarrett D'Amore 		return (frame & 0xffff);
566*e8717ca2SGarrett D'Amore 	}
5677c478bd9Sstevel@tonic-gate 
5680219346bSGarrett D'Amore 	PUT_MIFREG(mif_frame,
5690219346bSGarrett D'Amore 	    HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) |
5700219346bSGarrett D'Amore 	    (regad << HME_MIF_FRREGAD_SHIFT));
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate  *	HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
5737c478bd9Sstevel@tonic-gate  */
5740219346bSGarrett D'Amore 	HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
5750219346bSGarrett D'Amore 	frame = GET_MIFREG(mif_frame);
5767c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
577*e8717ca2SGarrett D'Amore 
578*e8717ca2SGarrett D'Amore 	PUT_MACREG(xifc, tmp_xif);
579*e8717ca2SGarrett D'Amore 	PUT_MIFREG(mif_cfg, tmp_mif);
580*e8717ca2SGarrett D'Amore 
5817c478bd9Sstevel@tonic-gate 	if ((frame & HME_MIF_FRTA0) == 0) {
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 
58406673d9bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, MII_MSG,
5850219346bSGarrett D'Amore 		    "MIF Read failure");
58606673d9bSGarrett D'Amore 		return (0xffff);
5877c478bd9Sstevel@tonic-gate 	}
58806673d9bSGarrett D'Amore 	return ((uint16_t)(frame & HME_MIF_FRDATA));
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate static void
59206673d9bSGarrett D'Amore hme_mii_write(void *arg, uint8_t phyad, uint8_t regad, uint16_t data)
5937c478bd9Sstevel@tonic-gate {
59406673d9bSGarrett D'Amore 	struct hme *hmep = arg;
5957c478bd9Sstevel@tonic-gate 	uint32_t frame;
596*e8717ca2SGarrett D'Amore 	uint32_t tmp_mif;
597*e8717ca2SGarrett D'Amore 	uint32_t tmp_xif;
598*e8717ca2SGarrett D'Amore 
599*e8717ca2SGarrett D'Amore 	tmp_mif = GET_MIFREG(mif_cfg);
600*e8717ca2SGarrett D'Amore 	tmp_xif = GET_MACREG(xifc);
601*e8717ca2SGarrett D'Amore 
602*e8717ca2SGarrett D'Amore 	switch (phyad) {
603*e8717ca2SGarrett D'Amore 	case HME_EXTERNAL_PHYAD:
604*e8717ca2SGarrett D'Amore 		PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
605*e8717ca2SGarrett D'Amore 		PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
606*e8717ca2SGarrett D'Amore 		break;
607*e8717ca2SGarrett D'Amore 	case HME_INTERNAL_PHYAD:
608*e8717ca2SGarrett D'Amore 		PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
609*e8717ca2SGarrett D'Amore 		PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
610*e8717ca2SGarrett D'Amore 		break;
611*e8717ca2SGarrett D'Amore 	default:
612*e8717ca2SGarrett D'Amore 		return;
613*e8717ca2SGarrett D'Amore 	}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	if (!hmep->hme_frame_enable) {
61606673d9bSGarrett D'Amore 		hme_bb_mii_write(hmep, phyad, regad, data);
617*e8717ca2SGarrett D'Amore 		PUT_MACREG(xifc, tmp_xif);
618*e8717ca2SGarrett D'Amore 		PUT_MIFREG(mif_cfg, tmp_mif);
6197c478bd9Sstevel@tonic-gate 		return;
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6220219346bSGarrett D'Amore 	PUT_MIFREG(mif_frame,
6230219346bSGarrett D'Amore 	    HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) |
6240219346bSGarrett D'Amore 	    (regad << HME_MIF_FRREGAD_SHIFT) | data);
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate  *	HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
6277c478bd9Sstevel@tonic-gate  */
6280219346bSGarrett D'Amore 	HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
6290219346bSGarrett D'Amore 	frame = GET_MIFREG(mif_frame);
630*e8717ca2SGarrett D'Amore 	PUT_MACREG(xifc, tmp_xif);
631*e8717ca2SGarrett D'Amore 	PUT_MIFREG(mif_cfg, tmp_mif);
6327c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
6337c478bd9Sstevel@tonic-gate 	if ((frame & HME_MIF_FRTA0) == 0) {
63406673d9bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_MID, MII_MSG,
6350219346bSGarrett D'Amore 		    "MIF Write failure");
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate static void
64006673d9bSGarrett D'Amore hme_mii_notify(void *arg, link_state_t link)
6417c478bd9Sstevel@tonic-gate {
6427c478bd9Sstevel@tonic-gate 	struct hme *hmep = arg;
6437c478bd9Sstevel@tonic-gate 
64406673d9bSGarrett D'Amore 	if (link == LINK_STATE_UP) {
64506673d9bSGarrett D'Amore 		(void) hmeinit(hmep);
6467c478bd9Sstevel@tonic-gate 	}
64706673d9bSGarrett D'Amore 	mac_link_update(hmep->hme_mh, link);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<<<<  LOADABLE ENTRIES  >>>>>>>>>>>>>>>>>>>>>>> */
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate int
6537c478bd9Sstevel@tonic-gate _init(void)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate 	int	status;
6567c478bd9Sstevel@tonic-gate 
65785025c03Sgd 	mac_init_ops(&hme_dev_ops, "hme");
65885025c03Sgd 	if ((status = mod_install(&modlinkage)) != 0) {
65985025c03Sgd 		mac_fini_ops(&hme_dev_ops);
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 	return (status);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate int
6657c478bd9Sstevel@tonic-gate _fini(void)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	int	status;
6687c478bd9Sstevel@tonic-gate 
66985025c03Sgd 	if ((status = mod_remove(&modlinkage)) == 0) {
67085025c03Sgd 		mac_fini_ops(&hme_dev_ops);
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 	return (status);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate int
6767c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate /*
6827c478bd9Sstevel@tonic-gate  * ddi_dma_sync() a TMD or RMD descriptor.
6837c478bd9Sstevel@tonic-gate  */
6840219346bSGarrett D'Amore #define	HMESYNCRMD(num, who)				\
6850219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_rmd_dmah,		\
6860219346bSGarrett D'Amore 	    (num * sizeof (struct hme_rmd)),		\
6870219346bSGarrett D'Amore 	    sizeof (struct hme_rmd),			\
6880219346bSGarrett D'Amore 	    who)
6890219346bSGarrett D'Amore 
6900219346bSGarrett D'Amore #define	HMESYNCTMD(num, who)				\
6910219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_tmd_dmah,		\
6920219346bSGarrett D'Amore 	    (num * sizeof (struct hme_tmd)),		\
6930219346bSGarrett D'Amore 	    sizeof (struct hme_tmd),			\
6940219346bSGarrett D'Amore 	    who)
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate  * Ethernet broadcast address definition.
6987c478bd9Sstevel@tonic-gate  */
6997c478bd9Sstevel@tonic-gate static	struct ether_addr	etherbroadcastaddr = {
7007c478bd9Sstevel@tonic-gate 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
7017c478bd9Sstevel@tonic-gate };
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate /*
7047c478bd9Sstevel@tonic-gate  * MIB II broadcast/multicast packets
7057c478bd9Sstevel@tonic-gate  */
70685025c03Sgd #define	IS_BROADCAST(pkt) (bcmp(pkt, &etherbroadcastaddr, ETHERADDRL) == 0)
70785025c03Sgd #define	IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
70885025c03Sgd #define	BUMP_InNUcast(hmep, pkt) \
7090219346bSGarrett D'Amore 	if (IS_MULTICAST(pkt)) {			       \
7100219346bSGarrett D'Amore 		if (IS_BROADCAST(pkt)) {		       \
7110219346bSGarrett D'Amore 			hmep->hme_brdcstrcv++;		       \
7120219346bSGarrett D'Amore 		} else {				       \
7130219346bSGarrett D'Amore 			hmep->hme_multircv++;		       \
7140219346bSGarrett D'Amore 		}					       \
7150219346bSGarrett D'Amore 	}
71685025c03Sgd #define	BUMP_OutNUcast(hmep, pkt) \
7170219346bSGarrett D'Amore 	if (IS_MULTICAST(pkt)) {			       \
7180219346bSGarrett D'Amore 		if (IS_BROADCAST(pkt)) {		       \
7190219346bSGarrett D'Amore 			hmep->hme_brdcstxmt++;		       \
7200219346bSGarrett D'Amore 		} else {				       \
7210219346bSGarrett D'Amore 			hmep->hme_multixmt++;		       \
7220219346bSGarrett D'Amore 		}					       \
7230219346bSGarrett D'Amore 	}
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate static int
7267c478bd9Sstevel@tonic-gate hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr)
7277c478bd9Sstevel@tonic-gate {
7287c478bd9Sstevel@tonic-gate 	char propstr[80];
7297c478bd9Sstevel@tonic-gate 	int i, needprop = 0;
7307c478bd9Sstevel@tonic-gate 	struct ether_addr local_mac;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (strcmp(vpdname, "NA") == 0) {
7337c478bd9Sstevel@tonic-gate 		(void) strcpy(propstr, "local-mac-address");
7347c478bd9Sstevel@tonic-gate 		needprop = 1;
7357c478bd9Sstevel@tonic-gate 	} else if (strcmp(vpdname, "Z0") == 0) {
7367c478bd9Sstevel@tonic-gate 		(void) strcpy(propstr, "model");
7377c478bd9Sstevel@tonic-gate 		needprop = 1;
7387c478bd9Sstevel@tonic-gate 	} else if (strcmp(vpdname, "Z1") == 0) {
7397c478bd9Sstevel@tonic-gate 		(void) strcpy(propstr, "board-model");
7407c478bd9Sstevel@tonic-gate 		needprop = 1;
7417c478bd9Sstevel@tonic-gate 	}
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	if (needprop == 1) {
7440219346bSGarrett D'Amore 
7457c478bd9Sstevel@tonic-gate 		if (strcmp(propstr, "local-mac-address") == 0) {
7467c478bd9Sstevel@tonic-gate 			for (i = 0; i < ETHERADDRL; i++)
7477c478bd9Sstevel@tonic-gate 				local_mac.ether_addr_octet[i] =
74885025c03Sgd 				    (uchar_t)vpdstr[i];
7497c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
75085025c03Sgd 			    DDI_PROP_CANSLEEP, propstr,
75185025c03Sgd 			    (char *)local_mac.ether_addr_octet, ETHERADDRL)
75285025c03Sgd 			    != DDI_SUCCESS) {
7537c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
7547c478bd9Sstevel@tonic-gate 			}
7557c478bd9Sstevel@tonic-gate 		} else {
7567c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
75785025c03Sgd 			    DDI_PROP_CANSLEEP, propstr, vpdstr,
75885025c03Sgd 			    strlen(vpdstr)+1) != DDI_SUCCESS) {
7597c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
7607c478bd9Sstevel@tonic-gate 			}
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 	return (0);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /*
7677c478bd9Sstevel@tonic-gate  * Get properties from old VPD
7687c478bd9Sstevel@tonic-gate  * for PCI cards
7697c478bd9Sstevel@tonic-gate  */
7707c478bd9Sstevel@tonic-gate static int
7717c478bd9Sstevel@tonic-gate hme_get_oldvpd_props(dev_info_t *dip, int vpd_base)
7727c478bd9Sstevel@tonic-gate {
7737c478bd9Sstevel@tonic-gate 	struct hme *hmep;
7747c478bd9Sstevel@tonic-gate 	int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
7757c478bd9Sstevel@tonic-gate 	char kw_namestr[3];
7767c478bd9Sstevel@tonic-gate 	char kw_fieldstr[256];
7777c478bd9Sstevel@tonic-gate 	int i;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	vpd_start = vpd_base;
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
7847c478bd9Sstevel@tonic-gate 		return (1); /* error */
7857c478bd9Sstevel@tonic-gate 	} else {
7867c478bd9Sstevel@tonic-gate 		vpd_len = 9;
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	/* Get local-mac-address */
7907c478bd9Sstevel@tonic-gate 	kw_start = vpd_start + 3; /* Location of 1st keyword */
7917c478bd9Sstevel@tonic-gate 	kw_ptr = kw_start;
7927c478bd9Sstevel@tonic-gate 	while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
7937c478bd9Sstevel@tonic-gate 		kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
7947c478bd9Sstevel@tonic-gate 		kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
7957c478bd9Sstevel@tonic-gate 		kw_namestr[2] = '\0';
7967c478bd9Sstevel@tonic-gate 		kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
7977c478bd9Sstevel@tonic-gate 		for (i = 0, kw_ptr += 3; i < kw_len; i++)
7987c478bd9Sstevel@tonic-gate 			kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
7997c478bd9Sstevel@tonic-gate 		kw_fieldstr[i] = '\0';
8007c478bd9Sstevel@tonic-gate 		if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) {
8017c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8027c478bd9Sstevel@tonic-gate 		}
8037c478bd9Sstevel@tonic-gate 		kw_ptr += kw_len;
8047c478bd9Sstevel@tonic-gate 	} /* next keyword */
8057c478bd9Sstevel@tonic-gate 
80685025c03Sgd 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model",
80785025c03Sgd 	    "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) {
8087c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 	return (0);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate /*
8157c478bd9Sstevel@tonic-gate  * Get properties from new VPD
8167c478bd9Sstevel@tonic-gate  * for CompactPCI cards
8177c478bd9Sstevel@tonic-gate  */
8187c478bd9Sstevel@tonic-gate static int
8197c478bd9Sstevel@tonic-gate hme_get_newvpd_props(dev_info_t *dip, int vpd_base)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate 	struct hme *hmep;
8227c478bd9Sstevel@tonic-gate 	int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
8237c478bd9Sstevel@tonic-gate 	char kw_namestr[3];
8247c478bd9Sstevel@tonic-gate 	char kw_fieldstr[256];
8257c478bd9Sstevel@tonic-gate 	int maxvpdsize, i;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	maxvpdsize = 1024; /* Real size not known until after it is read */
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) |
83285025c03Sgd 	    ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3;
8337c478bd9Sstevel@tonic-gate 	vpd_start = vpd_base + vpd_start;
8347c478bd9Sstevel@tonic-gate 	while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */
8357c478bd9Sstevel@tonic-gate 		if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
8367c478bd9Sstevel@tonic-gate 			break; /* no VPD found */
8377c478bd9Sstevel@tonic-gate 		} else {
8387c478bd9Sstevel@tonic-gate 			vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start
83985025c03Sgd 			    + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start
84085025c03Sgd 			    + 2]) & 0xff) << 8);
8417c478bd9Sstevel@tonic-gate 		}
8427c478bd9Sstevel@tonic-gate 		/* Get all keywords in this VPD */
8437c478bd9Sstevel@tonic-gate 		kw_start = vpd_start + 3; /* Location of 1st keyword */
8447c478bd9Sstevel@tonic-gate 		kw_ptr = kw_start;
8457c478bd9Sstevel@tonic-gate 		while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
8467c478bd9Sstevel@tonic-gate 			kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
8477c478bd9Sstevel@tonic-gate 			kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
8487c478bd9Sstevel@tonic-gate 			kw_namestr[2] = '\0';
84985025c03Sgd 			kw_len =
85085025c03Sgd 			    (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
8517c478bd9Sstevel@tonic-gate 			for (i = 0, kw_ptr += 3; i < kw_len; i++)
85285025c03Sgd 				kw_fieldstr[i] =
85385025c03Sgd 				    GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
8547c478bd9Sstevel@tonic-gate 			kw_fieldstr[i] = '\0';
8557c478bd9Sstevel@tonic-gate 			if (hme_create_prop_from_kw(dip, kw_namestr,
85685025c03Sgd 			    kw_fieldstr)) {
8577c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
8587c478bd9Sstevel@tonic-gate 			}
8597c478bd9Sstevel@tonic-gate 			kw_ptr += kw_len;
8607c478bd9Sstevel@tonic-gate 		} /* next keyword */
8617c478bd9Sstevel@tonic-gate 		vpd_start += (vpd_len + 3);
8627c478bd9Sstevel@tonic-gate 	} /* next VPD */
8637c478bd9Sstevel@tonic-gate 	return (0);
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate /*
8687c478bd9Sstevel@tonic-gate  * Get properties from VPD
8697c478bd9Sstevel@tonic-gate  */
8707c478bd9Sstevel@tonic-gate static int
8717c478bd9Sstevel@tonic-gate hme_get_vpd_props(dev_info_t *dip)
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate 	struct hme *hmep;
8747c478bd9Sstevel@tonic-gate 	int v0, v1, vpd_base;
8757c478bd9Sstevel@tonic-gate 	int i, epromsrchlimit;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	v0 = (int)(GET_ROM8(&(hmep->hme_romp[0])));
8817c478bd9Sstevel@tonic-gate 	v1 = (int)(GET_ROM8(&(hmep->hme_romp[1])));
8827c478bd9Sstevel@tonic-gate 	v0 = ((v0 & 0xff) << 8 | v1);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	if ((v0 & 0xffff) != 0x55aa) {
8857c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, " Valid pci prom not found \n");
8867c478bd9Sstevel@tonic-gate 		return (1);
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	epromsrchlimit = 4096;
8907c478bd9Sstevel@tonic-gate 	for (i = 2; i < epromsrchlimit; i++) {
89185025c03Sgd 		/* "PCIR" */
89285025c03Sgd 		if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') &&
89385025c03Sgd 		    ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') &&
89485025c03Sgd 		    ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') &&
89585025c03Sgd 		    ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) {
89685025c03Sgd 			vpd_base =
89785025c03Sgd 			    (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) |
89885025c03Sgd 			    (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8);
8997c478bd9Sstevel@tonic-gate 			break; /* VPD pointer found */
9007c478bd9Sstevel@tonic-gate 		}
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/* No VPD found */
9047c478bd9Sstevel@tonic-gate 	if (vpd_base == 0) {
9057c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, " Vital Product Data pointer not found \n");
9067c478bd9Sstevel@tonic-gate 		return (1);
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base])));
9107c478bd9Sstevel@tonic-gate 	if (v0 == 0x82) {
9117c478bd9Sstevel@tonic-gate 		if (hme_get_newvpd_props(dip, vpd_base))
9127c478bd9Sstevel@tonic-gate 			return (1);
9137c478bd9Sstevel@tonic-gate 		return (0);
9147c478bd9Sstevel@tonic-gate 	} else if (v0 == 0x90) {
9150219346bSGarrett D'Amore 		/* If we are are SUNW,qfe card, look for the Nth "NA" descr */
9160219346bSGarrett D'Amore 		if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12])  != 0x79) &&
9170219346bSGarrett D'Amore 		    GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) {
9180219346bSGarrett D'Amore 			vpd_base += hmep->hme_devno * 12;
9190219346bSGarrett D'Amore 		}
9207c478bd9Sstevel@tonic-gate 		if (hme_get_oldvpd_props(dip, vpd_base))
9217c478bd9Sstevel@tonic-gate 			return (1);
9227c478bd9Sstevel@tonic-gate 		return (0);
9237c478bd9Sstevel@tonic-gate 	} else
9247c478bd9Sstevel@tonic-gate 		return (1);	/* unknown start byte in VPD */
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9270219346bSGarrett D'Amore /*
9280219346bSGarrett D'Amore  * For x86, the BIOS doesn't map the PCI Rom register for the qfe
9290219346bSGarrett D'Amore  * cards, so we have to extract it from the ebus bridge that is
9300219346bSGarrett D'Amore  * function zero of the same device.  This is a bit of an ugly hack.
9310219346bSGarrett D'Amore  * (The ebus bridge leaves the entire ROM mapped at base address
9320219346bSGarrett D'Amore  * register 0x10.)
9330219346bSGarrett D'Amore  */
9340219346bSGarrett D'Amore 
9350219346bSGarrett D'Amore typedef struct {
9360219346bSGarrett D'Amore 	struct hme 		*hmep;
9370219346bSGarrett D'Amore 	dev_info_t		*parent;
9380219346bSGarrett D'Amore 	uint8_t			bus, dev;
9390219346bSGarrett D'Amore 	ddi_acc_handle_t	acch;
9400219346bSGarrett D'Amore 	caddr_t			romp;
9410219346bSGarrett D'Amore } ebus_rom_t;
9420219346bSGarrett D'Amore 
9430219346bSGarrett D'Amore static int
9440219346bSGarrett D'Amore hme_mapebusrom(dev_info_t *dip, void *arg)
9450219346bSGarrett D'Amore {
9460219346bSGarrett D'Amore 	int		*regs;
9470219346bSGarrett D'Amore 	unsigned	nregs;
9480219346bSGarrett D'Amore 	int		reg;
9490219346bSGarrett D'Amore 	ebus_rom_t	*rom = arg;
9500219346bSGarrett D'Amore 	struct hme	*hmep = rom->hmep;
9510219346bSGarrett D'Amore 
9520219346bSGarrett D'Amore 	/*
9530219346bSGarrett D'Amore 	 * We only want to look at our peers.  Skip our parent.
9540219346bSGarrett D'Amore 	 */
9550219346bSGarrett D'Amore 	if (dip == rom->parent) {
9560219346bSGarrett D'Amore 		return (DDI_WALK_PRUNESIB);
9570219346bSGarrett D'Amore 	}
9580219346bSGarrett D'Amore 
95906673d9bSGarrett D'Amore 	if (ddi_get_parent(dip) != rom->parent)
96006673d9bSGarrett D'Amore 		return (DDI_WALK_CONTINUE);
96106673d9bSGarrett D'Amore 
9620219346bSGarrett D'Amore 	if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
9630219346bSGarrett D'Amore 	    "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
9640219346bSGarrett D'Amore 		return (DDI_WALK_PRUNECHILD);
9650219346bSGarrett D'Amore 	}
9660219346bSGarrett D'Amore 
9670219346bSGarrett D'Amore 	if (nregs < 1) {
9680219346bSGarrett D'Amore 		ddi_prop_free(regs);
9690219346bSGarrett D'Amore 		return (DDI_WALK_PRUNECHILD);
9700219346bSGarrett D'Amore 	}
9710219346bSGarrett D'Amore 	reg = regs[0];
9720219346bSGarrett D'Amore 	ddi_prop_free(regs);
9730219346bSGarrett D'Amore 
9740219346bSGarrett D'Amore 	/*
9750219346bSGarrett D'Amore 	 * Look for function 0 on our bus and device.  If the device doesn't
9760219346bSGarrett D'Amore 	 * match, it might be an alternate peer, in which case we don't want
9770219346bSGarrett D'Amore 	 * to examine any of its children.
9780219346bSGarrett D'Amore 	 */
9790219346bSGarrett D'Amore 	if ((PCI_REG_BUS_G(reg) != rom->bus) ||
9800219346bSGarrett D'Amore 	    (PCI_REG_DEV_G(reg) != rom->dev) ||
9810219346bSGarrett D'Amore 	    (PCI_REG_FUNC_G(reg) != 0)) {
9820219346bSGarrett D'Amore 		return (DDI_WALK_PRUNECHILD);
9830219346bSGarrett D'Amore 	}
9840219346bSGarrett D'Amore 
9850219346bSGarrett D'Amore 	(void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr,
9860219346bSGarrett D'Amore 	    &rom->acch);
9870219346bSGarrett D'Amore 	/*
9880219346bSGarrett D'Amore 	 * If we can't map the registers, the caller will notice that
9890219346bSGarrett D'Amore 	 * the acch is NULL.
9900219346bSGarrett D'Amore 	 */
9910219346bSGarrett D'Amore 	return (DDI_WALK_TERMINATE);
9920219346bSGarrett D'Amore }
9930219346bSGarrett D'Amore 
9940219346bSGarrett D'Amore static int
9950219346bSGarrett D'Amore hmeget_promebus(dev_info_t *dip)
9960219346bSGarrett D'Amore {
9970219346bSGarrett D'Amore 	ebus_rom_t	rom;
9980219346bSGarrett D'Amore 	int		*regs;
9990219346bSGarrett D'Amore 	unsigned	nregs;
10000219346bSGarrett D'Amore 	struct hme	*hmep;
10010219346bSGarrett D'Amore 
10020219346bSGarrett D'Amore 	hmep = ddi_get_driver_private(dip);
10030219346bSGarrett D'Amore 
10040219346bSGarrett D'Amore 	bzero(&rom, sizeof (rom));
10050219346bSGarrett D'Amore 
10060219346bSGarrett D'Amore 	/*
10070219346bSGarrett D'Amore 	 * For x86, the BIOS doesn't map the PCI Rom register for the qfe
10080219346bSGarrett D'Amore 	 * cards, so we have to extract it from the eBus bridge that is
10090219346bSGarrett D'Amore 	 * function zero.  This is a bit of an ugly hack.
10100219346bSGarrett D'Amore 	 */
10110219346bSGarrett D'Amore 	if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
10120219346bSGarrett D'Amore 	    "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
10130219346bSGarrett D'Amore 		return (DDI_FAILURE);
10140219346bSGarrett D'Amore 	}
10150219346bSGarrett D'Amore 
10160219346bSGarrett D'Amore 	if (nregs < 5) {
10170219346bSGarrett D'Amore 		ddi_prop_free(regs);
10180219346bSGarrett D'Amore 		return (DDI_FAILURE);
10190219346bSGarrett D'Amore 	}
10200219346bSGarrett D'Amore 	rom.hmep = hmep;
10210219346bSGarrett D'Amore 	rom.bus = PCI_REG_BUS_G(regs[0]);
10220219346bSGarrett D'Amore 	rom.dev = PCI_REG_DEV_G(regs[0]);
10230219346bSGarrett D'Amore 	hmep->hme_devno = rom.dev;
10240219346bSGarrett D'Amore 	rom.parent = ddi_get_parent(dip);
10250219346bSGarrett D'Amore 
10260219346bSGarrett D'Amore 	/*
10270219346bSGarrett D'Amore 	 * The implementation of ddi_walk_devs says that we must not
102806673d9bSGarrett D'Amore 	 * be called during autoconfiguration.  However, it turns out
102906673d9bSGarrett D'Amore 	 * that it is safe to call this during our attach routine,
103006673d9bSGarrett D'Amore 	 * because we are not a nexus device.
10310219346bSGarrett D'Amore 	 *
103206673d9bSGarrett D'Amore 	 * Previously we rooted our search at our immediate parent,
103306673d9bSGarrett D'Amore 	 * but this triggered an assertion panic in debug kernels.
10340219346bSGarrett D'Amore 	 */
103506673d9bSGarrett D'Amore 	ddi_walk_devs(ddi_root_node(), hme_mapebusrom, &rom);
10360219346bSGarrett D'Amore 
10370219346bSGarrett D'Amore 	if (rom.acch) {
10380219346bSGarrett D'Amore 		hmep->hme_romh = rom.acch;
10390219346bSGarrett D'Amore 		hmep->hme_romp = (unsigned char *)rom.romp;
10400219346bSGarrett D'Amore 		return (DDI_SUCCESS);
10410219346bSGarrett D'Amore 	}
10420219346bSGarrett D'Amore 	return (DDI_FAILURE);
10430219346bSGarrett D'Amore }
10440219346bSGarrett D'Amore 
10457c478bd9Sstevel@tonic-gate static int
10467c478bd9Sstevel@tonic-gate hmeget_promprops(dev_info_t *dip)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate 	struct hme *hmep;
10497c478bd9Sstevel@tonic-gate 	int rom_bar;
10507c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t cfg_handle;
10517c478bd9Sstevel@tonic-gate 	struct {
10527c478bd9Sstevel@tonic-gate 		uint16_t vendorid;
10537c478bd9Sstevel@tonic-gate 		uint16_t devid;
10547c478bd9Sstevel@tonic-gate 		uint16_t command;
10557c478bd9Sstevel@tonic-gate 		uint16_t status;
10567c478bd9Sstevel@tonic-gate 		uint32_t junk1;
10577c478bd9Sstevel@tonic-gate 		uint8_t cache_line;
10587c478bd9Sstevel@tonic-gate 		uint8_t latency;
10597c478bd9Sstevel@tonic-gate 		uint8_t header;
10607c478bd9Sstevel@tonic-gate 		uint8_t bist;
10617c478bd9Sstevel@tonic-gate 		uint32_t base;
10627c478bd9Sstevel@tonic-gate 		uint32_t base14;
10637c478bd9Sstevel@tonic-gate 		uint32_t base18;
10647c478bd9Sstevel@tonic-gate 		uint32_t base1c;
10657c478bd9Sstevel@tonic-gate 		uint32_t base20;
10667c478bd9Sstevel@tonic-gate 		uint32_t base24;
10677c478bd9Sstevel@tonic-gate 		uint32_t base28;
10687c478bd9Sstevel@tonic-gate 		uint32_t base2c;
10697c478bd9Sstevel@tonic-gate 		uint32_t base30;
10707c478bd9Sstevel@tonic-gate 	} *cfg_ptr;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/*
10767c478bd9Sstevel@tonic-gate 	 * map configuration space
10777c478bd9Sstevel@tonic-gate 	 */
10787c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
107985025c03Sgd 	    0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
10807c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	/*
10847c478bd9Sstevel@tonic-gate 	 * Enable bus-master and memory accesses
10857c478bd9Sstevel@tonic-gate 	 */
10867c478bd9Sstevel@tonic-gate 	ddi_put16(cfg_handle, &cfg_ptr->command,
108785025c03Sgd 	    PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT |
108885025c03Sgd 	    PCI_COMM_MAE | PCI_COMM_ME);
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	/*
10917c478bd9Sstevel@tonic-gate 	 * Enable rom accesses
10927c478bd9Sstevel@tonic-gate 	 */
10937c478bd9Sstevel@tonic-gate 	rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30);
10947c478bd9Sstevel@tonic-gate 	ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1);
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 
10970219346bSGarrett D'Amore 	if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0,
10980219346bSGarrett D'Amore 	    &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) &&
10990219346bSGarrett D'Amore 	    (hmeget_promebus(dip) != DDI_SUCCESS)) {
11000219346bSGarrett D'Amore 
11017c478bd9Sstevel@tonic-gate 		if (cfg_ptr)
11027c478bd9Sstevel@tonic-gate 			ddi_regs_map_free(&cfg_handle);
11037c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11047c478bd9Sstevel@tonic-gate 	} else {
11057c478bd9Sstevel@tonic-gate 		if (hme_get_vpd_props(dip))
11060219346bSGarrett D'Amore 			return (DDI_FAILURE);
11077c478bd9Sstevel@tonic-gate 	}
11087c478bd9Sstevel@tonic-gate 	if (hmep->hme_romp)
11097c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&hmep->hme_romh);
11107c478bd9Sstevel@tonic-gate 	if (cfg_ptr)
11117c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&cfg_handle);
11120219346bSGarrett D'Amore 	return (DDI_SUCCESS);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate static void
11177c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(struct hme *hmep)
11187c478bd9Sstevel@tonic-gate {
11197c478bd9Sstevel@tonic-gate 	int	hm_rev;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	hm_rev = hmep->asic_rev;
11237c478bd9Sstevel@tonic-gate 	switch (hm_rev) {
11247c478bd9Sstevel@tonic-gate 	case HME_2P1_REVID:
11257c478bd9Sstevel@tonic-gate 	case HME_2P1_REVID_OBP:
11267c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
112785025c03Sgd 		    "SBus 2.1 Found (Rev Id = %x)", hm_rev);
11287c478bd9Sstevel@tonic-gate 		hmep->hme_frame_enable = 1;
11297c478bd9Sstevel@tonic-gate 		break;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	case HME_2P0_REVID:
11327c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
113385025c03Sgd 		    "SBus 2.0 Found (Rev Id = %x)", hm_rev);
11347c478bd9Sstevel@tonic-gate 		break;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	case HME_1C0_REVID:
11377c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
113885025c03Sgd 		    "PCI IO 1.0 Found (Rev Id = %x)", hm_rev);
11397c478bd9Sstevel@tonic-gate 		break;
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	default:
114206673d9bSGarrett D'Amore 		HME_FAULT_MSG3(hmep, SEVERITY_NONE, DISPLAY_MSG,
114385025c03Sgd 		    "%s (Rev Id = %x) Found",
114485025c03Sgd 		    (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev);
11457c478bd9Sstevel@tonic-gate 		hmep->hme_frame_enable = 1;
11467c478bd9Sstevel@tonic-gate 		hmep->hme_lance_mode_enable = 1;
11477c478bd9Sstevel@tonic-gate 		hmep->hme_rxcv_enable = 1;
11487c478bd9Sstevel@tonic-gate 		break;
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate /*
11537c478bd9Sstevel@tonic-gate  * Interface exists: make available by filling in network interface
11547c478bd9Sstevel@tonic-gate  * record.  System will initialize the interface when it is ready
11557c478bd9Sstevel@tonic-gate  * to accept packets.
11567c478bd9Sstevel@tonic-gate  */
1157f2cd0f02Sgd int
11587c478bd9Sstevel@tonic-gate hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	struct hme *hmep;
116185025c03Sgd 	mac_register_t *macp = NULL;
11627c478bd9Sstevel@tonic-gate 	int 	regno;
11637c478bd9Sstevel@tonic-gate 	int hm_rev = 0;
11647c478bd9Sstevel@tonic-gate 	int prop_len = sizeof (int);
11657c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t cfg_handle;
11667c478bd9Sstevel@tonic-gate 	struct {
11677c478bd9Sstevel@tonic-gate 		uint16_t vendorid;
11687c478bd9Sstevel@tonic-gate 		uint16_t devid;
11697c478bd9Sstevel@tonic-gate 		uint16_t command;
11707c478bd9Sstevel@tonic-gate 		uint16_t status;
11717c478bd9Sstevel@tonic-gate 		uint8_t revid;
11727c478bd9Sstevel@tonic-gate 		uint8_t j1;
11737c478bd9Sstevel@tonic-gate 		uint16_t j2;
11747c478bd9Sstevel@tonic-gate 	} *cfg_ptr;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	switch (cmd) {
11777c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
11787c478bd9Sstevel@tonic-gate 		break;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
11817c478bd9Sstevel@tonic-gate 		if ((hmep = ddi_get_driver_private(dip)) == NULL)
118285025c03Sgd 			return (DDI_FAILURE);
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 		hmep->hme_flags &= ~HMESUSPENDED;
118506673d9bSGarrett D'Amore 
118606673d9bSGarrett D'Amore 		mii_resume(hmep->hme_mii);
118785025c03Sgd 
1188228fdff0Sgd 		if (hmep->hme_started)
118985025c03Sgd 			(void) hmeinit(hmep);
11907c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	default:
11937c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	/*
11977c478bd9Sstevel@tonic-gate 	 * Allocate soft device data structure
11987c478bd9Sstevel@tonic-gate 	 */
11990219346bSGarrett D'Amore 	hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP);
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	/*
12027c478bd9Sstevel@tonic-gate 	 * Might as well set up elements of data structure
12037c478bd9Sstevel@tonic-gate 	 */
12047c478bd9Sstevel@tonic-gate 	hmep->dip =		dip;
12057c478bd9Sstevel@tonic-gate 	hmep->instance = 	ddi_get_instance(dip);
12067c478bd9Sstevel@tonic-gate 	hmep->pagesize =	ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	/*
12097c478bd9Sstevel@tonic-gate 	 *  Might as well setup the driver private
12107c478bd9Sstevel@tonic-gate 	 * structure as part of the dip.
12117c478bd9Sstevel@tonic-gate 	 */
12127c478bd9Sstevel@tonic-gate 	ddi_set_driver_private(dip, hmep);
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	/*
12157c478bd9Sstevel@tonic-gate 	 * Reject this device if it's in a slave-only slot.
12167c478bd9Sstevel@tonic-gate 	 */
12177c478bd9Sstevel@tonic-gate 	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
12187c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
12190219346bSGarrett D'Amore 		    "Dev not used - dev in slave only slot");
12207c478bd9Sstevel@tonic-gate 		goto error_state;
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	/*
12247c478bd9Sstevel@tonic-gate 	 * Map in the device registers.
12257c478bd9Sstevel@tonic-gate 	 *
12267c478bd9Sstevel@tonic-gate 	 * Reg # 0 is the Global register set
12277c478bd9Sstevel@tonic-gate 	 * Reg # 1 is the ETX register set
12287c478bd9Sstevel@tonic-gate 	 * Reg # 2 is the ERX register set
12297c478bd9Sstevel@tonic-gate 	 * Reg # 3 is the BigMAC register set.
12307c478bd9Sstevel@tonic-gate 	 * Reg # 4 is the MIF register set
12317c478bd9Sstevel@tonic-gate 	 */
12327c478bd9Sstevel@tonic-gate 	if (ddi_dev_nregs(dip, &regno) != (DDI_SUCCESS)) {
12337c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG,
123485025c03Sgd 		    ddi_nregs_fail_msg, regno);
12357c478bd9Sstevel@tonic-gate 		goto error_state;
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	switch (regno) {
12397c478bd9Sstevel@tonic-gate 	case 5:
12407c478bd9Sstevel@tonic-gate 		hmep->hme_cheerio_mode = 0;
12417c478bd9Sstevel@tonic-gate 		break;
12427c478bd9Sstevel@tonic-gate 	case 2:
12437c478bd9Sstevel@tonic-gate 	case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */
12447c478bd9Sstevel@tonic-gate 		hmep->hme_cheerio_mode = 1;
12457c478bd9Sstevel@tonic-gate 		break;
12467c478bd9Sstevel@tonic-gate 	default:
124785025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
124885025c03Sgd 		    bad_num_regs_msg);
12497c478bd9Sstevel@tonic-gate 		goto error_state;
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	/* Initialize device attributes structure */
12537c478bd9Sstevel@tonic-gate 	hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode)
125685025c03Sgd 		hmep->hme_dev_attr.devacc_attr_endian_flags =
125785025c03Sgd 		    DDI_STRUCTURE_LE_ACC;
12587c478bd9Sstevel@tonic-gate 	else
125985025c03Sgd 		hmep->hme_dev_attr.devacc_attr_endian_flags =
126085025c03Sgd 		    DDI_STRUCTURE_BE_ACC;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode) {
12657c478bd9Sstevel@tonic-gate 		uint8_t		oldLT;
12667c478bd9Sstevel@tonic-gate 		uint8_t		newLT = 0;
12677c478bd9Sstevel@tonic-gate 		dev_info_t	*pdip;
12687c478bd9Sstevel@tonic-gate 		const char	*pdrvname;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 		/*
12717c478bd9Sstevel@tonic-gate 		 * Map the PCI config space
12727c478bd9Sstevel@tonic-gate 		 */
12737c478bd9Sstevel@tonic-gate 		if (pci_config_setup(dip, &hmep->pci_config_handle) !=
127485025c03Sgd 		    DDI_SUCCESS) {
12757c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
127685025c03Sgd 			    "pci_config_setup() failed..");
12777c478bd9Sstevel@tonic-gate 			goto error_state;
12787c478bd9Sstevel@tonic-gate 		}
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1,
128185025c03Sgd 		    (caddr_t *)&(hmep->hme_globregp), 0, 0,
128285025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_globregh)) {
12837c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
128485025c03Sgd 			    mregs_4global_reg_fail_msg);
12857c478bd9Sstevel@tonic-gate 			goto error_unmap;
12867c478bd9Sstevel@tonic-gate 		}
12877c478bd9Sstevel@tonic-gate 		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
12887c478bd9Sstevel@tonic-gate 		    hmep->hme_mifregh = hmep->hme_globregh;
12897c478bd9Sstevel@tonic-gate 
129085025c03Sgd 		hmep->hme_etxregp =
129185025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x2000);
129285025c03Sgd 		hmep->hme_erxregp =
129385025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x4000);
129485025c03Sgd 		hmep->hme_bmacregp =
129585025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x6000);
129685025c03Sgd 		hmep->hme_mifregp =
129785025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x7000);
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 		/*
13007c478bd9Sstevel@tonic-gate 		 * Get parent pci bridge info.
13017c478bd9Sstevel@tonic-gate 		 */
13027c478bd9Sstevel@tonic-gate 		pdip = ddi_get_parent(dip);
13037c478bd9Sstevel@tonic-gate 		pdrvname = ddi_driver_name(pdip);
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 		oldLT = pci_config_get8(hmep->pci_config_handle,
130685025c03Sgd 		    PCI_CONF_LATENCY_TIMER);
13077c478bd9Sstevel@tonic-gate 		/*
13087c478bd9Sstevel@tonic-gate 		 * Honor value set in /etc/system
13097c478bd9Sstevel@tonic-gate 		 * "set hme:pci_latency_timer=0xYY"
13107c478bd9Sstevel@tonic-gate 		 */
13117c478bd9Sstevel@tonic-gate 		if (pci_latency_timer)
13127c478bd9Sstevel@tonic-gate 			newLT = pci_latency_timer;
13137c478bd9Sstevel@tonic-gate 		/*
13147c478bd9Sstevel@tonic-gate 		 * Modify LT for simba
13157c478bd9Sstevel@tonic-gate 		 */
13167c478bd9Sstevel@tonic-gate 		else if (strcmp("simba", pdrvname) == 0)
13177c478bd9Sstevel@tonic-gate 			newLT = 0xf0;
13187c478bd9Sstevel@tonic-gate 		/*
13197c478bd9Sstevel@tonic-gate 		 * Ensure minimum cheerio latency timer of 0x50
13207c478bd9Sstevel@tonic-gate 		 * Usually OBP or pci bridge should set this value
13217c478bd9Sstevel@tonic-gate 		 * based on cheerio
13227c478bd9Sstevel@tonic-gate 		 * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8
13237c478bd9Sstevel@tonic-gate 		 * Some system set cheerio LT at 0x40
13247c478bd9Sstevel@tonic-gate 		 */
13257c478bd9Sstevel@tonic-gate 		else if (oldLT < 0x40)
13267c478bd9Sstevel@tonic-gate 			newLT = 0x50;
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 		/*
13297c478bd9Sstevel@tonic-gate 		 * Now program cheerio's pci latency timer with newLT
13307c478bd9Sstevel@tonic-gate 		 */
13317c478bd9Sstevel@tonic-gate 		if (newLT)
13327c478bd9Sstevel@tonic-gate 			pci_config_put8(hmep->pci_config_handle,
133385025c03Sgd 			    PCI_CONF_LATENCY_TIMER, (uchar_t)newLT);
13347c478bd9Sstevel@tonic-gate 	} else { /* Map register sets */
13357c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 0,
133685025c03Sgd 		    (caddr_t *)&(hmep->hme_globregp), 0, 0,
133785025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_globregh)) {
13387c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
133985025c03Sgd 			    mregs_4global_reg_fail_msg);
13407c478bd9Sstevel@tonic-gate 			goto error_state;
13417c478bd9Sstevel@tonic-gate 		}
13427c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1,
134385025c03Sgd 		    (caddr_t *)&(hmep->hme_etxregp), 0, 0,
134485025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_etxregh)) {
13457c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
134685025c03Sgd 			    mregs_4etx_reg_fail_msg);
13477c478bd9Sstevel@tonic-gate 			goto error_unmap;
13487c478bd9Sstevel@tonic-gate 		}
13497c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 2,
135085025c03Sgd 		    (caddr_t *)&(hmep->hme_erxregp), 0, 0,
135185025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_erxregh)) {
13527c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
135385025c03Sgd 			    mregs_4erx_reg_fail_msg);
13547c478bd9Sstevel@tonic-gate 			goto error_unmap;
13557c478bd9Sstevel@tonic-gate 		}
13567c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 3,
135785025c03Sgd 		    (caddr_t *)&(hmep->hme_bmacregp), 0, 0,
135885025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_bmacregh)) {
13597c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
136085025c03Sgd 			    mregs_4bmac_reg_fail_msg);
13617c478bd9Sstevel@tonic-gate 			goto error_unmap;
13627c478bd9Sstevel@tonic-gate 		}
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 4,
136585025c03Sgd 		    (caddr_t *)&(hmep->hme_mifregp), 0, 0,
136685025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_mifregh)) {
13677c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
136885025c03Sgd 			    mregs_4mif_reg_fail_msg);
13697c478bd9Sstevel@tonic-gate 			goto error_unmap;
13707c478bd9Sstevel@tonic-gate 		}
13717c478bd9Sstevel@tonic-gate 	} /* Endif cheerio_mode */
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	/*
13747c478bd9Sstevel@tonic-gate 	 * Based on the hm-rev, set some capabilities
13757c478bd9Sstevel@tonic-gate 	 * Set up default capabilities for HM 2.0
13767c478bd9Sstevel@tonic-gate 	 */
13777c478bd9Sstevel@tonic-gate 	hmep->hme_frame_enable = 0;
13787c478bd9Sstevel@tonic-gate 	hmep->hme_lance_mode_enable = 0;
13797c478bd9Sstevel@tonic-gate 	hmep->hme_rxcv_enable = 0;
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	/* NEW routine to get the properties */
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev",
138485025c03Sgd 	    (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) {
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 		hmep->asic_rev = hm_rev;
13877c478bd9Sstevel@tonic-gate 		hmeget_hm_rev_property(hmep);
13887c478bd9Sstevel@tonic-gate 	} else {
13897c478bd9Sstevel@tonic-gate 		/*
13907c478bd9Sstevel@tonic-gate 		 * hm_rev property not found so, this is
13917c478bd9Sstevel@tonic-gate 		 * case of hot insertion of card without interpreting fcode.
13927c478bd9Sstevel@tonic-gate 		 * Get it from revid in config space after mapping it.
13937c478bd9Sstevel@tonic-gate 		 */
13947c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
139585025c03Sgd 		    0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
13967c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
13977c478bd9Sstevel@tonic-gate 		}
13987c478bd9Sstevel@tonic-gate 		/*
13997c478bd9Sstevel@tonic-gate 		 * Since this is cheerio-based PCI card, we write 0xC in the
14007c478bd9Sstevel@tonic-gate 		 * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits
14017c478bd9Sstevel@tonic-gate 		 * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1)
14027c478bd9Sstevel@tonic-gate 		 */
14037c478bd9Sstevel@tonic-gate 		hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid);
14047c478bd9Sstevel@tonic-gate 		hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK);
14057c478bd9Sstevel@tonic-gate 		hmep->asic_rev = hm_rev;
14067c478bd9Sstevel@tonic-gate 		if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
140785025c03Sgd 		    "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) !=
140885025c03Sgd 		    DDI_SUCCESS) {
14097c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
141006673d9bSGarrett D'Amore 			    "ddi_prop_create error for hm_rev");
14117c478bd9Sstevel@tonic-gate 		}
14127c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&cfg_handle);
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 		hmeget_hm_rev_property(hmep);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 		/* get info via VPD */
14170219346bSGarrett D'Amore 		if (hmeget_promprops(dip) != DDI_SUCCESS) {
14187c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
141906673d9bSGarrett D'Amore 			    "no promprops");
14207c478bd9Sstevel@tonic-gate 		}
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	if (ddi_intr_hilevel(dip, 0)) {
14247c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG,
142585025c03Sgd 		    " high-level interrupts are not supported");
14267c478bd9Sstevel@tonic-gate 		goto error_unmap;
14277c478bd9Sstevel@tonic-gate 	}
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 	/*
14307c478bd9Sstevel@tonic-gate 	 * Get intr. block cookie so that mutex locks can be initialized.
14317c478bd9Sstevel@tonic-gate 	 */
14327c478bd9Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS)
14337c478bd9Sstevel@tonic-gate 		goto error_unmap;
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	/*
14367c478bd9Sstevel@tonic-gate 	 * Initialize mutex's for this device.
14377c478bd9Sstevel@tonic-gate 	 */
143885025c03Sgd 	mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
143985025c03Sgd 	mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	/*
14427c478bd9Sstevel@tonic-gate 	 * Quiesce the hardware.
14437c478bd9Sstevel@tonic-gate 	 */
14447c478bd9Sstevel@tonic-gate 	(void) hmestop(hmep);
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	/*
14477c478bd9Sstevel@tonic-gate 	 * Add interrupt to system
14487c478bd9Sstevel@tonic-gate 	 */
14497c478bd9Sstevel@tonic-gate 	if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL,
14507c478bd9Sstevel@tonic-gate 	    (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) {
14517c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
145285025c03Sgd 		    add_intr_fail_msg);
14537c478bd9Sstevel@tonic-gate 		goto error_mutex;
14547c478bd9Sstevel@tonic-gate 	}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	/*
14577c478bd9Sstevel@tonic-gate 	 * Set up the ethernet mac address.
14587c478bd9Sstevel@tonic-gate 	 */
14597c478bd9Sstevel@tonic-gate 	hme_setup_mac_address(hmep, dip);
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	if (!hmeinit_xfer_params(hmep))
146285025c03Sgd 		goto error_intr;
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	if (hmeburstsizes(hmep) == DDI_FAILURE) {
14657c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg);
146685025c03Sgd 		goto error_intr;
14677c478bd9Sstevel@tonic-gate 	}
14687c478bd9Sstevel@tonic-gate 
14690219346bSGarrett D'Amore 	if (hmeallocthings(hmep) != DDI_SUCCESS) {
14700219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
14710219346bSGarrett D'Amore 		    "resource allocation failed");
14720219346bSGarrett D'Amore 		goto error_intr;
14730219346bSGarrett D'Amore 	}
14740219346bSGarrett D'Amore 
14750219346bSGarrett D'Amore 	if (hmeallocbufs(hmep) != DDI_SUCCESS) {
14760219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
14770219346bSGarrett D'Amore 		    "buffer allocation failed");
14780219346bSGarrett D'Amore 		goto error_intr;
14790219346bSGarrett D'Amore 	}
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	hmestatinit(hmep);
148285025c03Sgd 
1483*e8717ca2SGarrett D'Amore 	/* our external (preferred) PHY is at address 0 */
1484*e8717ca2SGarrett D'Amore 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "first-phy", 0);
1485*e8717ca2SGarrett D'Amore 
148606673d9bSGarrett D'Amore 	hmep->hme_mii = mii_alloc(hmep, dip, &hme_mii_ops);
148706673d9bSGarrett D'Amore 	if (hmep->hme_mii == NULL) {
148806673d9bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
148906673d9bSGarrett D'Amore 		    "mii_alloc failed");
149006673d9bSGarrett D'Amore 		goto error_intr;
149106673d9bSGarrett D'Amore 	}
149206673d9bSGarrett D'Amore 	/* force a probe for the PHY */
149306673d9bSGarrett D'Amore 	mii_probe(hmep->hme_mii);
149406673d9bSGarrett D'Amore 
149585025c03Sgd 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
149685025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
149785025c03Sgd 		    "mac_alloc failed");
149885025c03Sgd 		goto error_intr;
149985025c03Sgd 	}
150085025c03Sgd 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
150185025c03Sgd 	macp->m_driver = hmep;
150285025c03Sgd 	macp->m_dip = dip;
150385025c03Sgd 	macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet;
150485025c03Sgd 	macp->m_callbacks = &hme_m_callbacks;
150585025c03Sgd 	macp->m_min_sdu = 0;
150685025c03Sgd 	macp->m_max_sdu = ETHERMTU;
1507d62bc4baSyz 	macp->m_margin = VLAN_TAGSZ;
150806673d9bSGarrett D'Amore 	macp->m_priv_props = hme_priv_prop;
150906673d9bSGarrett D'Amore 	macp->m_priv_prop_count =
151006673d9bSGarrett D'Amore 	    sizeof (hme_priv_prop) / sizeof (hme_priv_prop[0]);
151185025c03Sgd 	if (mac_register(macp, &hmep->hme_mh) != 0) {
151285025c03Sgd 		mac_free(macp);
151385025c03Sgd 		goto error_intr;
151485025c03Sgd 	}
151585025c03Sgd 
151685025c03Sgd 	mac_free(macp);
151785025c03Sgd 
15187c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
15197c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	/*
15227c478bd9Sstevel@tonic-gate 	 * Failure Exit
15237c478bd9Sstevel@tonic-gate 	 */
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate error_intr:
15267c478bd9Sstevel@tonic-gate 	if (hmep->hme_cookie)
15277c478bd9Sstevel@tonic-gate 		ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
15287c478bd9Sstevel@tonic-gate 
152906673d9bSGarrett D'Amore 	if (hmep->hme_mii)
153006673d9bSGarrett D'Amore 		mii_free(hmep->hme_mii);
153106673d9bSGarrett D'Amore 
15327c478bd9Sstevel@tonic-gate error_mutex:
15337c478bd9Sstevel@tonic-gate 	mutex_destroy(&hmep->hme_xmitlock);
15347c478bd9Sstevel@tonic-gate 	mutex_destroy(&hmep->hme_intrlock);
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate error_unmap:
15377c478bd9Sstevel@tonic-gate 	if (hmep->hme_globregh)
153885025c03Sgd 		ddi_regs_map_free(&hmep->hme_globregh);
15397c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode == 0) {
15407c478bd9Sstevel@tonic-gate 		if (hmep->hme_etxregh)
154185025c03Sgd 			ddi_regs_map_free(&hmep->hme_etxregh);
15427c478bd9Sstevel@tonic-gate 		if (hmep->hme_erxregh)
154385025c03Sgd 			ddi_regs_map_free(&hmep->hme_erxregh);
15447c478bd9Sstevel@tonic-gate 		if (hmep->hme_bmacregh)
154585025c03Sgd 			ddi_regs_map_free(&hmep->hme_bmacregh);
15467c478bd9Sstevel@tonic-gate 		if (hmep->hme_mifregh)
154785025c03Sgd 			ddi_regs_map_free(&hmep->hme_mifregh);
15487c478bd9Sstevel@tonic-gate 	} else {
15497c478bd9Sstevel@tonic-gate 		if (hmep->pci_config_handle)
15507c478bd9Sstevel@tonic-gate 			(void) pci_config_teardown(&hmep->pci_config_handle);
15517c478bd9Sstevel@tonic-gate 		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
15527c478bd9Sstevel@tonic-gate 		    hmep->hme_mifregh = hmep->hme_globregh = NULL;
15537c478bd9Sstevel@tonic-gate 	}
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate error_state:
15560219346bSGarrett D'Amore 	hmefreethings(hmep);
15570219346bSGarrett D'Amore 	hmefreebufs(hmep);
15580219346bSGarrett D'Amore 
15597c478bd9Sstevel@tonic-gate 	if (hmep) {
15607c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)hmep, sizeof (*hmep));
15617c478bd9Sstevel@tonic-gate 		ddi_set_driver_private(dip, NULL);
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
15657c478bd9Sstevel@tonic-gate }
15667c478bd9Sstevel@tonic-gate 
1567f2cd0f02Sgd int
15687c478bd9Sstevel@tonic-gate hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
15697c478bd9Sstevel@tonic-gate {
157085025c03Sgd 	struct hme *hmep;
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	if ((hmep = ddi_get_driver_private(dip)) == NULL)
15737c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	switch (cmd) {
15767c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
15777c478bd9Sstevel@tonic-gate 		break;
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
158006673d9bSGarrett D'Amore 		mii_suspend(hmep->hme_mii);
15817c478bd9Sstevel@tonic-gate 		hmep->hme_flags |= HMESUSPENDED;
15827c478bd9Sstevel@tonic-gate 		hmeuninit(hmep);
15837c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	default:
158685025c03Sgd 		return (DDI_FAILURE);
158785025c03Sgd 	}
158885025c03Sgd 
158985025c03Sgd 
159085025c03Sgd 	if (mac_unregister(hmep->hme_mh) != 0) {
15917c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	/*
15957c478bd9Sstevel@tonic-gate 	 * Make driver quiescent, we don't want to prevent the
15964dd87b61Sgd 	 * detach on failure.  Note that this should be redundant,
15974dd87b61Sgd 	 * since mac_stop should already have called hmeuninit().
15987c478bd9Sstevel@tonic-gate 	 */
15994dd87b61Sgd 	if (!(hmep->hme_flags & HMESUSPENDED)) {
16004dd87b61Sgd 		(void) hmestop(hmep);
16014dd87b61Sgd 	}
16027c478bd9Sstevel@tonic-gate 
160306673d9bSGarrett D'Amore 	if (hmep->hme_mii)
160406673d9bSGarrett D'Amore 		mii_free(hmep->hme_mii);
160506673d9bSGarrett D'Amore 
16067c478bd9Sstevel@tonic-gate 	/*
16077c478bd9Sstevel@tonic-gate 	 * Remove instance of the intr
16087c478bd9Sstevel@tonic-gate 	 */
16097c478bd9Sstevel@tonic-gate 	ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
16107c478bd9Sstevel@tonic-gate 
161185025c03Sgd 	/*
161285025c03Sgd 	 * Unregister kstats.
161385025c03Sgd 	 */
161485025c03Sgd 	if (hmep->hme_ksp != NULL)
161585025c03Sgd 		kstat_delete(hmep->hme_ksp);
161685025c03Sgd 	if (hmep->hme_intrstats != NULL)
161785025c03Sgd 		kstat_delete(hmep->hme_intrstats);
161885025c03Sgd 
161906673d9bSGarrett D'Amore 	hmep->hme_ksp = NULL;
162006673d9bSGarrett D'Amore 	hmep->hme_intrstats = NULL;
162185025c03Sgd 
16227c478bd9Sstevel@tonic-gate 	/*
16237c478bd9Sstevel@tonic-gate 	 * Destroy all mutexes and data structures allocated during
16247c478bd9Sstevel@tonic-gate 	 * attach time.
162585025c03Sgd 	 *
162685025c03Sgd 	 * Note: at this time we should be the only thread accessing
162785025c03Sgd 	 * the structures for this instance.
16287c478bd9Sstevel@tonic-gate 	 */
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	if (hmep->hme_globregh)
16317c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&hmep->hme_globregh);
16327c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode == 0) {
16337c478bd9Sstevel@tonic-gate 		if (hmep->hme_etxregh)
163485025c03Sgd 			ddi_regs_map_free(&hmep->hme_etxregh);
16357c478bd9Sstevel@tonic-gate 		if (hmep->hme_erxregh)
163685025c03Sgd 			ddi_regs_map_free(&hmep->hme_erxregh);
16377c478bd9Sstevel@tonic-gate 		if (hmep->hme_bmacregh)
163885025c03Sgd 			ddi_regs_map_free(&hmep->hme_bmacregh);
16397c478bd9Sstevel@tonic-gate 		if (hmep->hme_mifregh)
164085025c03Sgd 			ddi_regs_map_free(&hmep->hme_mifregh);
16417c478bd9Sstevel@tonic-gate 	} else {
16427c478bd9Sstevel@tonic-gate 		if (hmep->pci_config_handle)
16437c478bd9Sstevel@tonic-gate 			(void) pci_config_teardown(&hmep->pci_config_handle);
16447c478bd9Sstevel@tonic-gate 		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
16457c478bd9Sstevel@tonic-gate 		    hmep->hme_mifregh = hmep->hme_globregh = NULL;
16467c478bd9Sstevel@tonic-gate 	}
16477c478bd9Sstevel@tonic-gate 
164885025c03Sgd 	mutex_destroy(&hmep->hme_xmitlock);
164985025c03Sgd 	mutex_destroy(&hmep->hme_intrlock);
16507c478bd9Sstevel@tonic-gate 
16510219346bSGarrett D'Amore 	hmefreethings(hmep);
165285025c03Sgd 	hmefreebufs(hmep);
16537c478bd9Sstevel@tonic-gate 
165485025c03Sgd 	ddi_set_driver_private(dip, NULL);
165585025c03Sgd 	kmem_free(hmep, sizeof (struct hme));
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
16587c478bd9Sstevel@tonic-gate }
16597c478bd9Sstevel@tonic-gate 
16600219346bSGarrett D'Amore int
16610219346bSGarrett D'Amore hmequiesce(dev_info_t *dip)
16620219346bSGarrett D'Amore {
16630219346bSGarrett D'Amore 	struct hme *hmep;
16640219346bSGarrett D'Amore 
16650219346bSGarrett D'Amore 	if ((hmep = ddi_get_driver_private(dip)) == NULL)
16660219346bSGarrett D'Amore 		return (DDI_FAILURE);
16670219346bSGarrett D'Amore 
16680219346bSGarrett D'Amore 	(void) hmestop(hmep);
16690219346bSGarrett D'Amore 	return (DDI_SUCCESS);
16700219346bSGarrett D'Amore }
16710219346bSGarrett D'Amore 
167285025c03Sgd static boolean_t
16737c478bd9Sstevel@tonic-gate hmeinit_xfer_params(struct hme *hmep)
16747c478bd9Sstevel@tonic-gate {
16757c478bd9Sstevel@tonic-gate 	int hme_ipg1_conf, hme_ipg2_conf;
16767c478bd9Sstevel@tonic-gate 	int hme_ipg0_conf, hme_lance_mode_conf;
16777c478bd9Sstevel@tonic-gate 	int prop_len = sizeof (int);
16787c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	dip = hmep->dip;
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	/*
16837c478bd9Sstevel@tonic-gate 	 * Set up the start-up values for user-configurable parameters
16847c478bd9Sstevel@tonic-gate 	 * Get the values from the global variables first.
16857c478bd9Sstevel@tonic-gate 	 * Use the MASK to limit the value to allowed maximum.
16867c478bd9Sstevel@tonic-gate 	 */
168706673d9bSGarrett D'Amore 	hmep->hme_ipg1 = hme_ipg1 & HME_MASK_8BIT;
168806673d9bSGarrett D'Amore 	hmep->hme_ipg2 = hme_ipg2 & HME_MASK_8BIT;
168906673d9bSGarrett D'Amore 	hmep->hme_ipg0 = hme_ipg0 & HME_MASK_5BIT;
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	/*
16927c478bd9Sstevel@tonic-gate 	 * Get the parameter values configured in .conf file.
16937c478bd9Sstevel@tonic-gate 	 */
16947c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1",
169585025c03Sgd 	    (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) {
169606673d9bSGarrett D'Amore 		hmep->hme_ipg1 = hme_ipg1_conf & HME_MASK_8BIT;
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2",
170085025c03Sgd 	    (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) {
170106673d9bSGarrett D'Amore 		hmep->hme_ipg2 = hme_ipg2_conf & HME_MASK_8BIT;
17027c478bd9Sstevel@tonic-gate 	}
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0",
170585025c03Sgd 	    (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) {
170606673d9bSGarrett D'Amore 		hmep->hme_ipg0 = hme_ipg0_conf & HME_MASK_5BIT;
17077c478bd9Sstevel@tonic-gate 	}
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode",
171085025c03Sgd 	    (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) {
171106673d9bSGarrett D'Amore 		hmep->hme_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT;
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	return (B_TRUE);
17157c478bd9Sstevel@tonic-gate }
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate /*
17187c478bd9Sstevel@tonic-gate  * Return 0 upon success, 1 on failure.
17197c478bd9Sstevel@tonic-gate  */
17207c478bd9Sstevel@tonic-gate static uint_t
17217c478bd9Sstevel@tonic-gate hmestop(struct hme *hmep)
17227c478bd9Sstevel@tonic-gate {
17237c478bd9Sstevel@tonic-gate 	/*
17247c478bd9Sstevel@tonic-gate 	 * Disable the Tx dma engine.
17257c478bd9Sstevel@tonic-gate 	 */
17267c478bd9Sstevel@tonic-gate 	PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN));
17277c478bd9Sstevel@tonic-gate 	HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY);
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	/*
17307c478bd9Sstevel@tonic-gate 	 * Disable the Rx dma engine.
17317c478bd9Sstevel@tonic-gate 	 */
17327c478bd9Sstevel@tonic-gate 	PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN));
17337c478bd9Sstevel@tonic-gate 	HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY);
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	/*
17367c478bd9Sstevel@tonic-gate 	 * By this time all things should be quiet, so hit the
17377c478bd9Sstevel@tonic-gate 	 * chip with a reset.
17387c478bd9Sstevel@tonic-gate 	 */
17397c478bd9Sstevel@tonic-gate 	PUT_GLOBREG(reset, HMEG_RESET_GLOBAL);
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY);
17427c478bd9Sstevel@tonic-gate 	if (GET_GLOBREG(reset)) {
17437c478bd9Sstevel@tonic-gate 		return (1);
17447c478bd9Sstevel@tonic-gate 	}
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
17477c478bd9Sstevel@tonic-gate 	return (0);
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate static int
17517c478bd9Sstevel@tonic-gate hmestat_kstat_update(kstat_t *ksp, int rw)
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate 	struct hme *hmep;
17547c478bd9Sstevel@tonic-gate 	struct hmekstat *hkp;
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	hmep = (struct hme *)ksp->ks_private;
17577c478bd9Sstevel@tonic-gate 	hkp = (struct hmekstat *)ksp->ks_data;
17587c478bd9Sstevel@tonic-gate 
175985025c03Sgd 	if (rw != KSTAT_READ)
176085025c03Sgd 		return (EACCES);
176185025c03Sgd 
17627c478bd9Sstevel@tonic-gate 	/*
17637c478bd9Sstevel@tonic-gate 	 * Update all the stats by reading all the counter registers.
17647c478bd9Sstevel@tonic-gate 	 * Counter register stats are not updated till they overflow
17657c478bd9Sstevel@tonic-gate 	 * and interrupt.
17667c478bd9Sstevel@tonic-gate 	 */
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
17694dd87b61Sgd 	if (hmep->hme_flags & HMERUNNING) {
17707c478bd9Sstevel@tonic-gate 		hmereclaim(hmep);
17714dd87b61Sgd 		hmesavecntrs(hmep);
17724dd87b61Sgd 	}
17737c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
17747c478bd9Sstevel@tonic-gate 
177585025c03Sgd 	hkp->hk_cvc.value.ul		= hmep->hme_cvc;
177685025c03Sgd 	hkp->hk_lenerr.value.ul		= hmep->hme_lenerr;
177785025c03Sgd 	hkp->hk_buff.value.ul		= hmep->hme_buff;
177885025c03Sgd 	hkp->hk_missed.value.ul		= hmep->hme_missed;
177985025c03Sgd 	hkp->hk_allocbfail.value.ul	= hmep->hme_allocbfail;
178085025c03Sgd 	hkp->hk_babl.value.ul		= hmep->hme_babl;
178185025c03Sgd 	hkp->hk_tmder.value.ul		= hmep->hme_tmder;
178285025c03Sgd 	hkp->hk_txlaterr.value.ul	= hmep->hme_txlaterr;
178385025c03Sgd 	hkp->hk_rxlaterr.value.ul	= hmep->hme_rxlaterr;
178485025c03Sgd 	hkp->hk_slvparerr.value.ul	= hmep->hme_slvparerr;
178585025c03Sgd 	hkp->hk_txparerr.value.ul	= hmep->hme_txparerr;
178685025c03Sgd 	hkp->hk_rxparerr.value.ul	= hmep->hme_rxparerr;
178785025c03Sgd 	hkp->hk_slverrack.value.ul	= hmep->hme_slverrack;
178885025c03Sgd 	hkp->hk_txerrack.value.ul	= hmep->hme_txerrack;
178985025c03Sgd 	hkp->hk_rxerrack.value.ul	= hmep->hme_rxerrack;
179085025c03Sgd 	hkp->hk_txtagerr.value.ul	= hmep->hme_txtagerr;
179185025c03Sgd 	hkp->hk_rxtagerr.value.ul	= hmep->hme_rxtagerr;
179285025c03Sgd 	hkp->hk_eoperr.value.ul		= hmep->hme_eoperr;
179385025c03Sgd 	hkp->hk_notmds.value.ul		= hmep->hme_notmds;
179485025c03Sgd 	hkp->hk_notbufs.value.ul	= hmep->hme_notbufs;
179585025c03Sgd 	hkp->hk_norbufs.value.ul	= hmep->hme_norbufs;
17967c478bd9Sstevel@tonic-gate 
179785025c03Sgd 	/*
179885025c03Sgd 	 * Debug kstats
179985025c03Sgd 	 */
180085025c03Sgd 	hkp->hk_inits.value.ul		= hmep->inits;
180185025c03Sgd 	hkp->hk_phyfail.value.ul	= hmep->phyfail;
18027c478bd9Sstevel@tonic-gate 
180385025c03Sgd 	/*
180485025c03Sgd 	 * xcvr kstats
180585025c03Sgd 	 */
180685025c03Sgd 	hkp->hk_asic_rev.value.ul	= hmep->asic_rev;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	return (0);
18097c478bd9Sstevel@tonic-gate }
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate static void
18127c478bd9Sstevel@tonic-gate hmestatinit(struct hme *hmep)
18137c478bd9Sstevel@tonic-gate {
18147c478bd9Sstevel@tonic-gate 	struct	kstat	*ksp;
18157c478bd9Sstevel@tonic-gate 	struct	hmekstat	*hkp;
1816f2cd0f02Sgd 	const char *driver;
18177c478bd9Sstevel@tonic-gate 	int	instance;
18187c478bd9Sstevel@tonic-gate 	char	buf[16];
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	instance = hmep->instance;
1821f2cd0f02Sgd 	driver = ddi_driver_name(hmep->dip);
18227c478bd9Sstevel@tonic-gate 
1823f2cd0f02Sgd 	if ((ksp = kstat_create(driver, instance,
182485025c03Sgd 	    "driver_info", "net", KSTAT_TYPE_NAMED,
18257c478bd9Sstevel@tonic-gate 	    sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) {
18267c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG,
18270219346bSGarrett D'Amore 		    "kstat_create failed");
18287c478bd9Sstevel@tonic-gate 		return;
18297c478bd9Sstevel@tonic-gate 	}
18307c478bd9Sstevel@tonic-gate 
1831f2cd0f02Sgd 	(void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance);
1832f2cd0f02Sgd 	hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller",
183385025c03Sgd 	    KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
18347c478bd9Sstevel@tonic-gate 	if (hmep->hme_intrstats)
18357c478bd9Sstevel@tonic-gate 		kstat_install(hmep->hme_intrstats);
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	hmep->hme_ksp = ksp;
18387c478bd9Sstevel@tonic-gate 	hkp = (struct hmekstat *)ksp->ks_data;
18397c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_cvc,			"code_violations",
184085025c03Sgd 	    KSTAT_DATA_ULONG);
18417c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_lenerr,		"len_errors",
184285025c03Sgd 	    KSTAT_DATA_ULONG);
18437c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_buff,			"buff",
184485025c03Sgd 	    KSTAT_DATA_ULONG);
18457c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_missed,		"missed",
184685025c03Sgd 	    KSTAT_DATA_ULONG);
18477c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_nocanput,		"nocanput",
184885025c03Sgd 	    KSTAT_DATA_ULONG);
18497c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_allocbfail,		"allocbfail",
185085025c03Sgd 	    KSTAT_DATA_ULONG);
18517c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_babl,			"babble",
185285025c03Sgd 	    KSTAT_DATA_ULONG);
18537c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_tmder,		"tmd_error",
185485025c03Sgd 	    KSTAT_DATA_ULONG);
18557c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txlaterr,		"tx_late_error",
185685025c03Sgd 	    KSTAT_DATA_ULONG);
18577c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxlaterr,		"rx_late_error",
185885025c03Sgd 	    KSTAT_DATA_ULONG);
18597c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_slvparerr,		"slv_parity_error",
186085025c03Sgd 	    KSTAT_DATA_ULONG);
18617c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txparerr,		"tx_parity_error",
186285025c03Sgd 	    KSTAT_DATA_ULONG);
18637c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxparerr,		"rx_parity_error",
186485025c03Sgd 	    KSTAT_DATA_ULONG);
18657c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_slverrack,		"slv_error_ack",
186685025c03Sgd 	    KSTAT_DATA_ULONG);
18677c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txerrack,		"tx_error_ack",
186885025c03Sgd 	    KSTAT_DATA_ULONG);
18697c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxerrack,		"rx_error_ack",
187085025c03Sgd 	    KSTAT_DATA_ULONG);
18717c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txtagerr,		"tx_tag_error",
187285025c03Sgd 	    KSTAT_DATA_ULONG);
18737c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxtagerr,		"rx_tag_error",
187485025c03Sgd 	    KSTAT_DATA_ULONG);
18757c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_eoperr,		"eop_error",
187685025c03Sgd 	    KSTAT_DATA_ULONG);
18777c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_notmds,		"no_tmds",
187885025c03Sgd 	    KSTAT_DATA_ULONG);
18797c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_notbufs,		"no_tbufs",
188085025c03Sgd 	    KSTAT_DATA_ULONG);
18817c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_norbufs,		"no_rbufs",
188285025c03Sgd 	    KSTAT_DATA_ULONG);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	/*
18857c478bd9Sstevel@tonic-gate 	 * Debugging kstats
18867c478bd9Sstevel@tonic-gate 	 */
18877c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_inits,		"inits",
188885025c03Sgd 	    KSTAT_DATA_ULONG);
18897c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_phyfail,		"phy_failures",
189085025c03Sgd 	    KSTAT_DATA_ULONG);
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	/*
18937c478bd9Sstevel@tonic-gate 	 * xcvr kstats
18947c478bd9Sstevel@tonic-gate 	 */
18957c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_asic_rev,		"asic_rev",
189685025c03Sgd 	    KSTAT_DATA_ULONG);
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	ksp->ks_update = hmestat_kstat_update;
18997c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *) hmep;
19007c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
19017c478bd9Sstevel@tonic-gate }
19027c478bd9Sstevel@tonic-gate 
190306673d9bSGarrett D'Amore int
190406673d9bSGarrett D'Amore hme_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags,
190506673d9bSGarrett D'Amore     uint_t sz, void *val, uint_t *perm)
19067c478bd9Sstevel@tonic-gate {
190706673d9bSGarrett D'Amore 	struct hme *hmep = arg;
190806673d9bSGarrett D'Amore 	int value;
190906673d9bSGarrett D'Amore 	boolean_t is_default;
191006673d9bSGarrett D'Amore 	int rv;
191106673d9bSGarrett D'Amore 
191206673d9bSGarrett D'Amore 	rv = mii_m_getprop(hmep->hme_mii, name, num, flags, sz, val, perm);
191306673d9bSGarrett D'Amore 	if (rv != ENOTSUP)
191406673d9bSGarrett D'Amore 		return (rv);
191506673d9bSGarrett D'Amore 
191606673d9bSGarrett D'Amore 	switch (num) {
191706673d9bSGarrett D'Amore 	case MAC_PROP_PRIVATE:
191806673d9bSGarrett D'Amore 		break;
191906673d9bSGarrett D'Amore 	default:
192006673d9bSGarrett D'Amore 		return (ENOTSUP);
192106673d9bSGarrett D'Amore 	}
192206673d9bSGarrett D'Amore 
192306673d9bSGarrett D'Amore 	*perm = MAC_PROP_PERM_RW;
192406673d9bSGarrett D'Amore 
192506673d9bSGarrett D'Amore 	is_default = (flags & MAC_PROP_DEFAULT) ? B_TRUE : B_FALSE;
192606673d9bSGarrett D'Amore 	if (strcmp(name, "_ipg0") == 0) {
192706673d9bSGarrett D'Amore 		value = is_default ? hme_ipg0 : hmep->hme_ipg0;
192806673d9bSGarrett D'Amore 
192906673d9bSGarrett D'Amore 	} else if (strcmp(name, "_ipg1") == 0) {
193006673d9bSGarrett D'Amore 		value = is_default ? hme_ipg1 : hmep->hme_ipg1;
193106673d9bSGarrett D'Amore 	} else if (strcmp(name, "_ipg2") == 0) {
193206673d9bSGarrett D'Amore 		value = is_default ? hme_ipg2 : hmep->hme_ipg2;
193306673d9bSGarrett D'Amore 	} else if (strcmp(name, "_lance_mode") == 0) {
193406673d9bSGarrett D'Amore 		value = is_default ? hme_lance_mode : hmep->hme_lance_mode;
193506673d9bSGarrett D'Amore 	} else {
193606673d9bSGarrett D'Amore 		return (ENOTSUP);
193706673d9bSGarrett D'Amore 	}
193806673d9bSGarrett D'Amore 	(void) snprintf(val, sz, "%d", value);
193906673d9bSGarrett D'Amore 	return (0);
194006673d9bSGarrett D'Amore }
194106673d9bSGarrett D'Amore 
194206673d9bSGarrett D'Amore int
194306673d9bSGarrett D'Amore hme_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
194406673d9bSGarrett D'Amore     const void *val)
194506673d9bSGarrett D'Amore {
194606673d9bSGarrett D'Amore 	struct hme *hmep = arg;
194706673d9bSGarrett D'Amore 	int rv;
194806673d9bSGarrett D'Amore 	long lval;
194906673d9bSGarrett D'Amore 	boolean_t init = B_FALSE;
195006673d9bSGarrett D'Amore 
195106673d9bSGarrett D'Amore 	rv = mii_m_setprop(hmep->hme_mii, name, num, sz, val);
195206673d9bSGarrett D'Amore 	if (rv != ENOTSUP)
195306673d9bSGarrett D'Amore 		return (rv);
195406673d9bSGarrett D'Amore 	rv = 0;
195506673d9bSGarrett D'Amore 
195606673d9bSGarrett D'Amore 	switch (num) {
195706673d9bSGarrett D'Amore 	case MAC_PROP_PRIVATE:
195885025c03Sgd 		break;
195906673d9bSGarrett D'Amore 	default:
196006673d9bSGarrett D'Amore 		return (ENOTSUP);
196106673d9bSGarrett D'Amore 	}
19627c478bd9Sstevel@tonic-gate 
196306673d9bSGarrett D'Amore 	(void) ddi_strtol(val, NULL, 0, &lval);
196406673d9bSGarrett D'Amore 
196506673d9bSGarrett D'Amore 	if (strcmp(name, "_ipg1") == 0) {
196606673d9bSGarrett D'Amore 		if ((lval >= 0) && (lval <= 255)) {
196706673d9bSGarrett D'Amore 			hmep->hme_ipg1 = lval & 0xff;
196806673d9bSGarrett D'Amore 			init = B_TRUE;
196906673d9bSGarrett D'Amore 		} else {
197006673d9bSGarrett D'Amore 			return (EINVAL);
197185025c03Sgd 		}
19727c478bd9Sstevel@tonic-gate 
197306673d9bSGarrett D'Amore 	} else if (strcmp(name, "_ipg2") == 0) {
197406673d9bSGarrett D'Amore 		if ((lval >= 0) && (lval <= 255)) {
197506673d9bSGarrett D'Amore 			hmep->hme_ipg2 = lval & 0xff;
197606673d9bSGarrett D'Amore 			init = B_TRUE;
197706673d9bSGarrett D'Amore 		} else {
197806673d9bSGarrett D'Amore 			return (EINVAL);
197906673d9bSGarrett D'Amore 		}
19807c478bd9Sstevel@tonic-gate 
198106673d9bSGarrett D'Amore 	} else if (strcmp(name, "_ipg0") == 0) {
198206673d9bSGarrett D'Amore 		if ((lval >= 0) && (lval <= 31)) {
198306673d9bSGarrett D'Amore 			hmep->hme_ipg0 = lval & 0xff;
198406673d9bSGarrett D'Amore 			init = B_TRUE;
198585025c03Sgd 		} else {
198606673d9bSGarrett D'Amore 			return (EINVAL);
198706673d9bSGarrett D'Amore 		}
198806673d9bSGarrett D'Amore 	} else if (strcmp(name, "_lance_mode") == 0) {
198906673d9bSGarrett D'Amore 		if ((lval >= 0) && (lval <= 1)) {
199006673d9bSGarrett D'Amore 			hmep->hme_lance_mode = lval & 0xff;
199106673d9bSGarrett D'Amore 			init = B_TRUE;
199206673d9bSGarrett D'Amore 		} else {
199306673d9bSGarrett D'Amore 			return (EINVAL);
19947c478bd9Sstevel@tonic-gate 		}
19957c478bd9Sstevel@tonic-gate 
199606673d9bSGarrett D'Amore 	} else {
199706673d9bSGarrett D'Amore 		rv = ENOTSUP;
199806673d9bSGarrett D'Amore 	}
199906673d9bSGarrett D'Amore 
200006673d9bSGarrett D'Amore 	if (init) {
200106673d9bSGarrett D'Amore 		(void) hmeinit(hmep);
20027c478bd9Sstevel@tonic-gate 	}
200306673d9bSGarrett D'Amore 	return (rv);
20047c478bd9Sstevel@tonic-gate }
20057c478bd9Sstevel@tonic-gate 
200606673d9bSGarrett D'Amore 
200785025c03Sgd /*ARGSUSED*/
200885025c03Sgd static boolean_t
200985025c03Sgd hme_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
20107c478bd9Sstevel@tonic-gate {
201185025c03Sgd 	switch (cap) {
201285025c03Sgd 	case MAC_CAPAB_HCKSUM:
201385025c03Sgd 		*(uint32_t *)cap_data = HCKSUM_INET_PARTIAL;
201485025c03Sgd 		return (B_TRUE);
201585025c03Sgd 	default:
201685025c03Sgd 		return (B_FALSE);
20177c478bd9Sstevel@tonic-gate 	}
201885025c03Sgd }
20197c478bd9Sstevel@tonic-gate 
202085025c03Sgd static int
202185025c03Sgd hme_m_promisc(void *arg, boolean_t on)
202285025c03Sgd {
202385025c03Sgd 	struct hme *hmep = arg;
20247c478bd9Sstevel@tonic-gate 
202585025c03Sgd 	hmep->hme_promisc = on;
202685025c03Sgd 	(void) hmeinit(hmep);
202785025c03Sgd 	return (0);
202885025c03Sgd }
20297c478bd9Sstevel@tonic-gate 
203085025c03Sgd static int
203185025c03Sgd hme_m_unicst(void *arg, const uint8_t *macaddr)
203285025c03Sgd {
203385025c03Sgd 	struct hme *hmep = arg;
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	/*
20367c478bd9Sstevel@tonic-gate 	 * Set new interface local address and re-init device.
20377c478bd9Sstevel@tonic-gate 	 * This is destructive to any other streams attached
20387c478bd9Sstevel@tonic-gate 	 * to this device.
20397c478bd9Sstevel@tonic-gate 	 */
204085025c03Sgd 	mutex_enter(&hmep->hme_intrlock);
204185025c03Sgd 	bcopy(macaddr, &hmep->hme_ouraddr, ETHERADDRL);
204285025c03Sgd 	mutex_exit(&hmep->hme_intrlock);
204385025c03Sgd 	(void) hmeinit(hmep);
204485025c03Sgd 	return (0);
20457c478bd9Sstevel@tonic-gate }
20467c478bd9Sstevel@tonic-gate 
204785025c03Sgd static int
204885025c03Sgd hme_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
20497c478bd9Sstevel@tonic-gate {
205085025c03Sgd 	struct hme	*hmep = arg;
205185025c03Sgd 	uint32_t	ladrf_bit;
205285025c03Sgd 	boolean_t	doinit = B_FALSE;
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 	/*
205585025c03Sgd 	 * If this address's bit was not already set in the local address
205685025c03Sgd 	 * filter, add it and re-initialize the Hardware.
20577c478bd9Sstevel@tonic-gate 	 */
205885025c03Sgd 	ladrf_bit = hmeladrf_bit(macaddr);
20597c478bd9Sstevel@tonic-gate 
206085025c03Sgd 	mutex_enter(&hmep->hme_intrlock);
206185025c03Sgd 	if (add) {
206285025c03Sgd 		hmep->hme_ladrf_refcnt[ladrf_bit]++;
206385025c03Sgd 		if (hmep->hme_ladrf_refcnt[ladrf_bit] == 1) {
206485025c03Sgd 			hmep->hme_ladrf[ladrf_bit >> 4] |=
206585025c03Sgd 			    1 << (ladrf_bit & 0xf);
206685025c03Sgd 			hmep->hme_multi++;
206785025c03Sgd 			doinit = B_TRUE;
206885025c03Sgd 		}
20697c478bd9Sstevel@tonic-gate 	} else {
207085025c03Sgd 		hmep->hme_ladrf_refcnt[ladrf_bit]--;
207185025c03Sgd 		if (hmep->hme_ladrf_refcnt[ladrf_bit] == 0) {
207285025c03Sgd 			hmep->hme_ladrf[ladrf_bit >> 4] &=
207385025c03Sgd 			    ~(1 << (ladrf_bit & 0xf));
207485025c03Sgd 			doinit = B_TRUE;
20757c478bd9Sstevel@tonic-gate 		}
20767c478bd9Sstevel@tonic-gate 	}
207785025c03Sgd 	mutex_exit(&hmep->hme_intrlock);
20787c478bd9Sstevel@tonic-gate 
20790219346bSGarrett D'Amore 	if (doinit) {
208085025c03Sgd 		(void) hmeinit(hmep);
20810219346bSGarrett D'Amore 	}
20827c478bd9Sstevel@tonic-gate 
208385025c03Sgd 	return (0);
20847c478bd9Sstevel@tonic-gate }
20857c478bd9Sstevel@tonic-gate 
208685025c03Sgd static int
208785025c03Sgd hme_m_start(void *arg)
20887c478bd9Sstevel@tonic-gate {
208985025c03Sgd 	struct hme *hmep = arg;
20907c478bd9Sstevel@tonic-gate 
2091228fdff0Sgd 	if (hmeinit(hmep) != 0) {
2092228fdff0Sgd 		/* initialization failed -- really want DL_INITFAILED */
2093228fdff0Sgd 		return (EIO);
2094228fdff0Sgd 	} else {
2095228fdff0Sgd 		hmep->hme_started = B_TRUE;
209606673d9bSGarrett D'Amore 		mii_start(hmep->hme_mii);
2097228fdff0Sgd 		return (0);
2098228fdff0Sgd 	}
209985025c03Sgd }
21007c478bd9Sstevel@tonic-gate 
210185025c03Sgd static void
210285025c03Sgd hme_m_stop(void *arg)
210385025c03Sgd {
210485025c03Sgd 	struct hme *hmep = arg;
21057c478bd9Sstevel@tonic-gate 
210606673d9bSGarrett D'Amore 	mii_stop(hmep->hme_mii);
2107228fdff0Sgd 	hmep->hme_started = B_FALSE;
210885025c03Sgd 	hmeuninit(hmep);
210985025c03Sgd }
21107c478bd9Sstevel@tonic-gate 
211185025c03Sgd static int
211285025c03Sgd hme_m_stat(void *arg, uint_t stat, uint64_t *val)
211385025c03Sgd {
211485025c03Sgd 	struct hme	*hmep = arg;
21157c478bd9Sstevel@tonic-gate 
211685025c03Sgd 	mutex_enter(&hmep->hme_xmitlock);
21174dd87b61Sgd 	if (hmep->hme_flags & HMERUNNING) {
211885025c03Sgd 		hmereclaim(hmep);
21194dd87b61Sgd 		hmesavecntrs(hmep);
21204dd87b61Sgd 	}
212185025c03Sgd 	mutex_exit(&hmep->hme_xmitlock);
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 
212406673d9bSGarrett D'Amore 	if (mii_m_getstat(hmep->hme_mii, stat, val) == 0) {
212506673d9bSGarrett D'Amore 		return (0);
212606673d9bSGarrett D'Amore 	}
212785025c03Sgd 	switch (stat) {
212885025c03Sgd 	case MAC_STAT_IPACKETS:
212985025c03Sgd 		*val = hmep->hme_ipackets;
213085025c03Sgd 		break;
213185025c03Sgd 	case MAC_STAT_RBYTES:
213285025c03Sgd 		*val = hmep->hme_rbytes;
213385025c03Sgd 		break;
213485025c03Sgd 	case MAC_STAT_IERRORS:
213585025c03Sgd 		*val = hmep->hme_ierrors;
213685025c03Sgd 		break;
213785025c03Sgd 	case MAC_STAT_OPACKETS:
213885025c03Sgd 		*val = hmep->hme_opackets;
213985025c03Sgd 		break;
214085025c03Sgd 	case MAC_STAT_OBYTES:
214185025c03Sgd 		*val = hmep->hme_obytes;
214285025c03Sgd 		break;
214385025c03Sgd 	case MAC_STAT_OERRORS:
214485025c03Sgd 		*val = hmep->hme_oerrors;
214585025c03Sgd 		break;
214685025c03Sgd 	case MAC_STAT_MULTIRCV:
214785025c03Sgd 		*val = hmep->hme_multircv;
214885025c03Sgd 		break;
214985025c03Sgd 	case MAC_STAT_MULTIXMT:
215085025c03Sgd 		*val = hmep->hme_multixmt;
215185025c03Sgd 		break;
215285025c03Sgd 	case MAC_STAT_BRDCSTRCV:
215385025c03Sgd 		*val = hmep->hme_brdcstrcv;
215485025c03Sgd 		break;
215585025c03Sgd 	case MAC_STAT_BRDCSTXMT:
215685025c03Sgd 		*val = hmep->hme_brdcstxmt;
215785025c03Sgd 		break;
215885025c03Sgd 	case MAC_STAT_UNDERFLOWS:
215985025c03Sgd 		*val = hmep->hme_uflo;
216085025c03Sgd 		break;
216185025c03Sgd 	case MAC_STAT_OVERFLOWS:
216285025c03Sgd 		*val = hmep->hme_oflo;
216385025c03Sgd 		break;
216485025c03Sgd 	case MAC_STAT_COLLISIONS:
216585025c03Sgd 		*val = hmep->hme_coll;
216685025c03Sgd 		break;
216785025c03Sgd 	case MAC_STAT_NORCVBUF:
216885025c03Sgd 		*val = hmep->hme_norcvbuf;
216985025c03Sgd 		break;
217085025c03Sgd 	case MAC_STAT_NOXMTBUF:
217185025c03Sgd 		*val = hmep->hme_noxmtbuf;
217285025c03Sgd 		break;
217385025c03Sgd 	case ETHER_STAT_LINK_DUPLEX:
217485025c03Sgd 		*val = hmep->hme_duplex;
217585025c03Sgd 		break;
217685025c03Sgd 	case ETHER_STAT_ALIGN_ERRORS:
217785025c03Sgd 		*val = hmep->hme_align_errors;
217885025c03Sgd 		break;
217985025c03Sgd 	case ETHER_STAT_FCS_ERRORS:
218085025c03Sgd 		*val = hmep->hme_fcs_errors;
218185025c03Sgd 		break;
218285025c03Sgd 	case ETHER_STAT_EX_COLLISIONS:
218385025c03Sgd 		*val = hmep->hme_excol;
218485025c03Sgd 		break;
218585025c03Sgd 	case ETHER_STAT_DEFER_XMTS:
218685025c03Sgd 		*val = hmep->hme_defer_xmts;
218785025c03Sgd 		break;
218885025c03Sgd 	case ETHER_STAT_SQE_ERRORS:
218985025c03Sgd 		*val = hmep->hme_sqe_errors;
219085025c03Sgd 		break;
219185025c03Sgd 	case ETHER_STAT_FIRST_COLLISIONS:
219285025c03Sgd 		*val = hmep->hme_fstcol;
219385025c03Sgd 		break;
219485025c03Sgd 	case ETHER_STAT_TX_LATE_COLLISIONS:
219585025c03Sgd 		*val = hmep->hme_tlcol;
219685025c03Sgd 		break;
219785025c03Sgd 	case ETHER_STAT_TOOLONG_ERRORS:
219885025c03Sgd 		*val = hmep->hme_toolong_errors;
219985025c03Sgd 		break;
220085025c03Sgd 	case ETHER_STAT_TOOSHORT_ERRORS:
220185025c03Sgd 		*val = hmep->hme_runt;
220285025c03Sgd 		break;
22034dd87b61Sgd 	case ETHER_STAT_CARRIER_ERRORS:
22044dd87b61Sgd 		*val = hmep->hme_carrier_errors;
22054dd87b61Sgd 		break;
220685025c03Sgd 	default:
220785025c03Sgd 		return (EINVAL);
22087c478bd9Sstevel@tonic-gate 	}
220985025c03Sgd 	return (0);
22107c478bd9Sstevel@tonic-gate }
22117c478bd9Sstevel@tonic-gate 
221285025c03Sgd static mblk_t *
221385025c03Sgd hme_m_tx(void *arg, mblk_t *mp)
22147c478bd9Sstevel@tonic-gate {
221585025c03Sgd 	struct hme *hmep = arg;
221685025c03Sgd 	mblk_t *next;
22177c478bd9Sstevel@tonic-gate 
221885025c03Sgd 	while (mp != NULL) {
221985025c03Sgd 		next = mp->b_next;
222085025c03Sgd 		mp->b_next = NULL;
222185025c03Sgd 		if (!hmestart(hmep, mp)) {
222285025c03Sgd 			mp->b_next = next;
222385025c03Sgd 			break;
22247c478bd9Sstevel@tonic-gate 		}
222585025c03Sgd 		mp = next;
22267c478bd9Sstevel@tonic-gate 	}
222785025c03Sgd 	return (mp);
22287c478bd9Sstevel@tonic-gate }
22297c478bd9Sstevel@tonic-gate 
2230eb7b3d20Sgd /*
2231eb7b3d20Sgd  * Software IP checksum, for the edge cases that the
2232eb7b3d20Sgd  * hardware can't handle.  See hmestart for more info.
2233eb7b3d20Sgd  */
2234eb7b3d20Sgd static uint16_t
2235eb7b3d20Sgd hme_cksum(void *data, int len)
2236eb7b3d20Sgd {
2237eb7b3d20Sgd 	uint16_t	*words = data;
2238eb7b3d20Sgd 	int		i, nwords = len / 2;
2239eb7b3d20Sgd 	uint32_t	sum = 0;
2240eb7b3d20Sgd 
2241eb7b3d20Sgd 	/* just add up the words */
2242eb7b3d20Sgd 	for (i = 0; i < nwords; i++) {
2243eb7b3d20Sgd 		sum += *words++;
2244eb7b3d20Sgd 	}
2245eb7b3d20Sgd 
2246eb7b3d20Sgd 	/* pick up residual byte ... assume even half-word allocations */
2247eb7b3d20Sgd 	if (len % 2) {
22480219346bSGarrett D'Amore 		sum += (*words & htons(0xff00));
2249eb7b3d20Sgd 	}
2250eb7b3d20Sgd 
2251eb7b3d20Sgd 	sum = (sum >> 16) + (sum & 0xffff);
2252eb7b3d20Sgd 	sum = (sum >> 16) + (sum & 0xffff);
2253eb7b3d20Sgd 
2254eb7b3d20Sgd 	return (~(sum & 0xffff));
2255eb7b3d20Sgd }
2256eb7b3d20Sgd 
225785025c03Sgd static boolean_t
22580219346bSGarrett D'Amore hmestart(struct hme *hmep, mblk_t *mp)
22597c478bd9Sstevel@tonic-gate {
22600219346bSGarrett D'Amore 	uint32_t	len;
22610219346bSGarrett D'Amore 	boolean_t	retval = B_TRUE;
22620219346bSGarrett D'Amore 	hmebuf_t	*tbuf;
22630219346bSGarrett D'Amore 	uint32_t	txptr;
22647c478bd9Sstevel@tonic-gate 
226585025c03Sgd 	uint32_t	csflags = 0;
226685025c03Sgd 	uint32_t	flags;
226785025c03Sgd 	uint32_t	start_offset;
226885025c03Sgd 	uint32_t	stuff_offset;
22697c478bd9Sstevel@tonic-gate 
227085025c03Sgd 	hcksum_retrieve(mp, NULL, NULL, &start_offset, &stuff_offset,
227185025c03Sgd 	    NULL, NULL, &flags);
22727c478bd9Sstevel@tonic-gate 
227385025c03Sgd 	if (flags & HCK_PARTIALCKSUM) {
227485025c03Sgd 		if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) {
227585025c03Sgd 			start_offset += sizeof (struct ether_header) + 4;
227685025c03Sgd 			stuff_offset += sizeof (struct ether_header) + 4;
227785025c03Sgd 		} else {
227885025c03Sgd 			start_offset += sizeof (struct ether_header);
227985025c03Sgd 			stuff_offset += sizeof (struct ether_header);
22807c478bd9Sstevel@tonic-gate 		}
228185025c03Sgd 		csflags = HMETMD_CSENABL |
228285025c03Sgd 		    (start_offset << HMETMD_CSSTART_SHIFT) |
228385025c03Sgd 		    (stuff_offset << HMETMD_CSSTUFF_SHIFT);
228485025c03Sgd 	}
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
22877c478bd9Sstevel@tonic-gate 
22884dd87b61Sgd 	if (hmep->hme_flags & HMESUSPENDED) {
22894dd87b61Sgd 		hmep->hme_carrier_errors++;
22904dd87b61Sgd 		hmep->hme_oerrors++;
22914dd87b61Sgd 		goto bad;
22924dd87b61Sgd 	}
22934dd87b61Sgd 
22940219346bSGarrett D'Amore 	if (hmep->hme_txindex != hmep->hme_txreclaim) {
22950219346bSGarrett D'Amore 		hmereclaim(hmep);
22967c478bd9Sstevel@tonic-gate 	}
22970219346bSGarrett D'Amore 	if ((hmep->hme_txindex - HME_TMDMAX) == hmep->hme_txreclaim)
22987c478bd9Sstevel@tonic-gate 		goto notmds;
22990219346bSGarrett D'Amore 	txptr = hmep->hme_txindex % HME_TMDMAX;
23000219346bSGarrett D'Amore 	tbuf = &hmep->hme_tbuf[txptr];
23017c478bd9Sstevel@tonic-gate 
2302eb7b3d20Sgd 	/*
2303eb7b3d20Sgd 	 * Note that for checksum offload, the hardware cannot
2304eb7b3d20Sgd 	 * generate correct checksums if the packet is smaller than
2305eb7b3d20Sgd 	 * 64-bytes.  In such a case, we bcopy the packet and use
2306eb7b3d20Sgd 	 * a software checksum.
2307eb7b3d20Sgd 	 */
2308eb7b3d20Sgd 
23090219346bSGarrett D'Amore 	len = msgsize(mp);
23100219346bSGarrett D'Amore 	if (len < 64) {
23110219346bSGarrett D'Amore 		/* zero fill the padding */
23120219346bSGarrett D'Amore 		bzero(tbuf->kaddr, 64);
23137c478bd9Sstevel@tonic-gate 	}
23140219346bSGarrett D'Amore 	mcopymsg(mp, tbuf->kaddr);
23157c478bd9Sstevel@tonic-gate 
23160219346bSGarrett D'Amore 	if ((csflags != 0) && (len < 64)) {
23170219346bSGarrett D'Amore 		uint16_t sum;
23180219346bSGarrett D'Amore 		sum = hme_cksum(tbuf->kaddr + start_offset,
23190219346bSGarrett D'Amore 		    len - start_offset);
23200219346bSGarrett D'Amore 		bcopy(&sum, tbuf->kaddr + stuff_offset, sizeof (sum));
23210219346bSGarrett D'Amore 		csflags = 0;
23227c478bd9Sstevel@tonic-gate 	}
23237c478bd9Sstevel@tonic-gate 
23240219346bSGarrett D'Amore 	if (ddi_dma_sync(tbuf->dmah, 0, len, DDI_DMA_SYNC_FORDEV) ==
23250219346bSGarrett D'Amore 	    DDI_FAILURE) {
23267c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, DDI_MSG,
232785025c03Sgd 		    "ddi_dma_sync failed");
23287c478bd9Sstevel@tonic-gate 	}
23297c478bd9Sstevel@tonic-gate 
23300219346bSGarrett D'Amore 	/*
23310219346bSGarrett D'Amore 	 * update MIB II statistics
23320219346bSGarrett D'Amore 	 */
23330219346bSGarrett D'Amore 	BUMP_OutNUcast(hmep, tbuf->kaddr);
23340219346bSGarrett D'Amore 
23350219346bSGarrett D'Amore 	PUT_TMD(txptr, tbuf->paddr, len,
23360219346bSGarrett D'Amore 	    HMETMD_OWN | HMETMD_SOP | HMETMD_EOP | csflags);
23377c478bd9Sstevel@tonic-gate 
23380219346bSGarrett D'Amore 	HMESYNCTMD(txptr, DDI_DMA_SYNC_FORDEV);
23390219346bSGarrett D'Amore 	hmep->hme_txindex++;
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 	PUT_ETXREG(txpend, HMET_TXPEND_TDMD);
23427c478bd9Sstevel@tonic-gate 	CHECK_ETXREG();
23437c478bd9Sstevel@tonic-gate 
23447c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	hmep->hme_starts++;
234785025c03Sgd 	return (B_TRUE);
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate bad:
23507c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
23517c478bd9Sstevel@tonic-gate 	freemsg(mp);
235285025c03Sgd 	return (B_TRUE);
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate notmds:
23557c478bd9Sstevel@tonic-gate 	hmep->hme_notmds++;
235685025c03Sgd 	hmep->hme_wantw = B_TRUE;
23577c478bd9Sstevel@tonic-gate 	hmereclaim(hmep);
235885025c03Sgd 	retval = B_FALSE;
23597c478bd9Sstevel@tonic-gate done:
23607c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
23617c478bd9Sstevel@tonic-gate 
236285025c03Sgd 	return (retval);
23637c478bd9Sstevel@tonic-gate }
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate /*
23667c478bd9Sstevel@tonic-gate  * Initialize channel.
23677c478bd9Sstevel@tonic-gate  * Return 0 on success, nonzero on error.
23687c478bd9Sstevel@tonic-gate  *
23697c478bd9Sstevel@tonic-gate  * The recommended sequence for initialization is:
23707c478bd9Sstevel@tonic-gate  * 1. Issue a Global Reset command to the Ethernet Channel.
23717c478bd9Sstevel@tonic-gate  * 2. Poll the Global_Reset bits until the execution of the reset has been
23727c478bd9Sstevel@tonic-gate  *    completed.
23737c478bd9Sstevel@tonic-gate  * 2(a). Use the MIF Frame/Output register to reset the transceiver.
23747c478bd9Sstevel@tonic-gate  *	 Poll Register 0 to till the Resetbit is 0.
23757c478bd9Sstevel@tonic-gate  * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op,
23767c478bd9Sstevel@tonic-gate  *	 100Mbps and Non-Isolated mode. The main point here is to bring the
23777c478bd9Sstevel@tonic-gate  *	 PHY out of Isolate mode so that it can generate the rx_clk and tx_clk
23787c478bd9Sstevel@tonic-gate  *	 to the MII interface so that the Bigmac core can correctly reset
23797c478bd9Sstevel@tonic-gate  *	 upon a software reset.
23807c478bd9Sstevel@tonic-gate  * 2(c).  Issue another Global Reset command to the Ethernet Channel and poll
23817c478bd9Sstevel@tonic-gate  *	  the Global_Reset bits till completion.
23827c478bd9Sstevel@tonic-gate  * 3. Set up all the data structures in the host memory.
23837c478bd9Sstevel@tonic-gate  * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration
23847c478bd9Sstevel@tonic-gate  *    Register).
23857c478bd9Sstevel@tonic-gate  * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration
23867c478bd9Sstevel@tonic-gate  *    Register).
23877c478bd9Sstevel@tonic-gate  * 6. Program the Transmit Descriptor Ring Base Address in the ETX.
23887c478bd9Sstevel@tonic-gate  * 7. Program the Receive Descriptor Ring Base Address in the ERX.
23897c478bd9Sstevel@tonic-gate  * 8. Program the Global Configuration and the Global Interrupt Mask Registers.
23907c478bd9Sstevel@tonic-gate  * 9. Program the ETX Configuration register (enable the Transmit DMA channel).
23917c478bd9Sstevel@tonic-gate  * 10. Program the ERX Configuration register (enable the Receive DMA channel).
23927c478bd9Sstevel@tonic-gate  * 11. Program the XIF Configuration Register (enable the XIF).
23937c478bd9Sstevel@tonic-gate  * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC).
23947c478bd9Sstevel@tonic-gate  * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC).
23957c478bd9Sstevel@tonic-gate  */
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 
23987c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG
23997c478bd9Sstevel@tonic-gate static int hme_palen = 32;
24007c478bd9Sstevel@tonic-gate #endif
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate static int
24037c478bd9Sstevel@tonic-gate hmeinit(struct hme *hmep)
24047c478bd9Sstevel@tonic-gate {
24050219346bSGarrett D'Amore 	uint32_t		i;
24060219346bSGarrett D'Amore 	int			ret;
240706673d9bSGarrett D'Amore 	boolean_t		fdx;
240806673d9bSGarrett D'Amore 	int			phyad;
24097c478bd9Sstevel@tonic-gate 
241085025c03Sgd 	/*
241185025c03Sgd 	 * Lock sequence:
241285025c03Sgd 	 *	hme_intrlock, hme_xmitlock.
241385025c03Sgd 	 */
241485025c03Sgd 	mutex_enter(&hmep->hme_intrlock);
24157c478bd9Sstevel@tonic-gate 
24167c478bd9Sstevel@tonic-gate 	/*
241785025c03Sgd 	 * Don't touch the hardware if we are suspended.  But don't
241885025c03Sgd 	 * fail either.  Some time later we may be resumed, and then
241985025c03Sgd 	 * we'll be back here to program the device using the settings
242085025c03Sgd 	 * in the soft state.
24217c478bd9Sstevel@tonic-gate 	 */
242285025c03Sgd 	if (hmep->hme_flags & HMESUSPENDED) {
242385025c03Sgd 		mutex_exit(&hmep->hme_intrlock);
242485025c03Sgd 		return (0);
242585025c03Sgd 	}
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	/*
242885025c03Sgd 	 * This should prevent us from clearing any interrupts that
242985025c03Sgd 	 * may occur by temporarily stopping interrupts from occurring
243085025c03Sgd 	 * for a short time.  We need to update the interrupt mask
243185025c03Sgd 	 * later in this function.
24327c478bd9Sstevel@tonic-gate 	 */
243385025c03Sgd 	PUT_GLOBREG(intmask, ~HMEG_MASK_MIF_INTR);
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	/*
24377c478bd9Sstevel@tonic-gate 	 * Rearranged the mutex acquisition order to solve the deadlock
24387c478bd9Sstevel@tonic-gate 	 * situation as described in bug ID 4065896.
24397c478bd9Sstevel@tonic-gate 	 */
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	hmep->hme_flags = 0;
244485025c03Sgd 	hmep->hme_wantw = B_FALSE;
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 	if (hmep->inits)
24477c478bd9Sstevel@tonic-gate 		hmesavecntrs(hmep);
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 	/*
24507c478bd9Sstevel@tonic-gate 	 * Perform Global reset of the Sbus/FEPS ENET channel.
24517c478bd9Sstevel@tonic-gate 	 */
24527c478bd9Sstevel@tonic-gate 	(void) hmestop(hmep);
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	/*
24557c478bd9Sstevel@tonic-gate 	 * Clear all descriptors.
24567c478bd9Sstevel@tonic-gate 	 */
24577c478bd9Sstevel@tonic-gate 	bzero(hmep->hme_rmdp, HME_RMDMAX * sizeof (struct hme_rmd));
24587c478bd9Sstevel@tonic-gate 	bzero(hmep->hme_tmdp, HME_TMDMAX * sizeof (struct hme_tmd));
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate 	/*
24617c478bd9Sstevel@tonic-gate 	 * Hang out receive buffers.
24627c478bd9Sstevel@tonic-gate 	 */
24630219346bSGarrett D'Amore 	for (i = 0; i < HME_RMDMAX; i++) {
24640219346bSGarrett D'Amore 		PUT_RMD(i, hmep->hme_rbuf[i].paddr);
24657c478bd9Sstevel@tonic-gate 	}
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	/*
24687c478bd9Sstevel@tonic-gate 	 * DMA sync descriptors.
24697c478bd9Sstevel@tonic-gate 	 */
24700219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_rmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
24710219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_tmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	/*
24747c478bd9Sstevel@tonic-gate 	 * Reset RMD and TMD 'walking' pointers.
24757c478bd9Sstevel@tonic-gate 	 */
24760219346bSGarrett D'Amore 	hmep->hme_rxindex = 0;
24770219346bSGarrett D'Amore 	hmep->hme_txindex = hmep->hme_txreclaim = 0;
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	/*
24807c478bd9Sstevel@tonic-gate 	 * This is the right place to initialize MIF !!!
24817c478bd9Sstevel@tonic-gate 	 */
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_imask, HME_MIF_INTMASK);	/* mask all interrupts */
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 	if (!hmep->hme_frame_enable)
24867c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) | HME_MIF_CFGBB);
24877c478bd9Sstevel@tonic-gate 	else
24887c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) & ~HME_MIF_CFGBB);
24897c478bd9Sstevel@tonic-gate 						/* enable frame mode */
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	/*
24927c478bd9Sstevel@tonic-gate 	 * Depending on the transceiver detected, select the source
24937c478bd9Sstevel@tonic-gate 	 * of the clocks for the MAC. Without the clocks, TX_MAC does
24947c478bd9Sstevel@tonic-gate 	 * not reset. When the Global Reset is issued to the Sbus/FEPS
24957c478bd9Sstevel@tonic-gate 	 * ASIC, it selects Internal by default.
24967c478bd9Sstevel@tonic-gate 	 */
24977c478bd9Sstevel@tonic-gate 
249806673d9bSGarrett D'Amore 	switch ((phyad = mii_get_addr(hmep->hme_mii))) {
249906673d9bSGarrett D'Amore 	case -1:
25007c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg);
25017c478bd9Sstevel@tonic-gate 		goto init_fail;	/* abort initialization */
25027c478bd9Sstevel@tonic-gate 
250306673d9bSGarrett D'Amore 	case HME_INTERNAL_PHYAD:
25047c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, 0);
250506673d9bSGarrett D'Amore 		break;
250606673d9bSGarrett D'Amore 	case HME_EXTERNAL_PHYAD:
250706673d9bSGarrett D'Amore 		/* Isolate the Int. xcvr */
25087c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, BMAC_XIFC_MIIBUFDIS);
250906673d9bSGarrett D'Amore 		break;
25107c478bd9Sstevel@tonic-gate 	}
251106673d9bSGarrett D'Amore 
25127c478bd9Sstevel@tonic-gate 	hmep->inits++;
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	/*
25157c478bd9Sstevel@tonic-gate 	 * Initialize BigMAC registers.
25167c478bd9Sstevel@tonic-gate 	 * First set the tx enable bit in tx config reg to 0 and poll on
25177c478bd9Sstevel@tonic-gate 	 * it till it turns to 0. Same for rx config, hash and address
25187c478bd9Sstevel@tonic-gate 	 * filter reg.
25197c478bd9Sstevel@tonic-gate 	 * Here is the sequence per the spec.
25207c478bd9Sstevel@tonic-gate 	 * MADD2 - MAC Address 2
25217c478bd9Sstevel@tonic-gate 	 * MADD1 - MAC Address 1
25227c478bd9Sstevel@tonic-gate 	 * MADD0 - MAC Address 0
25237c478bd9Sstevel@tonic-gate 	 * HASH3, HASH2, HASH1, HASH0 for group address
25247c478bd9Sstevel@tonic-gate 	 * AFR2, AFR1, AFR0 and AFMR for address filter mask
25257c478bd9Sstevel@tonic-gate 	 * Program RXMIN and RXMAX for packet length if not 802.3
25267c478bd9Sstevel@tonic-gate 	 * RXCFG - Rx config for not stripping CRC
25277c478bd9Sstevel@tonic-gate 	 * XXX Anything else to hme configured in RXCFG
25287c478bd9Sstevel@tonic-gate 	 * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN
25297c478bd9Sstevel@tonic-gate 	 * if not 802.3 compliant
25307c478bd9Sstevel@tonic-gate 	 * XIF register for speed selection
25317c478bd9Sstevel@tonic-gate 	 * MASK  - Interrupt mask
25327c478bd9Sstevel@tonic-gate 	 * Set bit 0 of TXCFG
25337c478bd9Sstevel@tonic-gate 	 * Set bit 0 of RXCFG
25347c478bd9Sstevel@tonic-gate 	 */
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 	/*
25377c478bd9Sstevel@tonic-gate 	 * Initialize the TX_MAC registers
25387c478bd9Sstevel@tonic-gate 	 * Initialization of jamsize to work around rx crc bug
25397c478bd9Sstevel@tonic-gate 	 */
25407c478bd9Sstevel@tonic-gate 	PUT_MACREG(jam, jamsize);
25417c478bd9Sstevel@tonic-gate 
25427c478bd9Sstevel@tonic-gate #ifdef	FEPS_URUN_BUG
25437c478bd9Sstevel@tonic-gate 	if (hme_urun_fix)
25447c478bd9Sstevel@tonic-gate 		PUT_MACREG(palen, hme_palen);
25457c478bd9Sstevel@tonic-gate #endif
25467c478bd9Sstevel@tonic-gate 
254706673d9bSGarrett D'Amore 	PUT_MACREG(ipg1, hmep->hme_ipg1);
254806673d9bSGarrett D'Amore 	PUT_MACREG(ipg2, hmep->hme_ipg2);
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	PUT_MACREG(rseed,
255185025c03Sgd 	    ((hmep->hme_ouraddr.ether_addr_octet[0] << 8) & 0x3) |
255285025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[1]);
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	/* Initialize the RX_MAC registers */
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 	/*
25577c478bd9Sstevel@tonic-gate 	 * Program BigMAC with local individual ethernet address.
25587c478bd9Sstevel@tonic-gate 	 */
25597c478bd9Sstevel@tonic-gate 	PUT_MACREG(madd2, (hmep->hme_ouraddr.ether_addr_octet[4] << 8) |
256085025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[5]);
25617c478bd9Sstevel@tonic-gate 	PUT_MACREG(madd1, (hmep->hme_ouraddr.ether_addr_octet[2] << 8) |
256285025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[3]);
25637c478bd9Sstevel@tonic-gate 	PUT_MACREG(madd0, (hmep->hme_ouraddr.ether_addr_octet[0] << 8) |
256485025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[1]);
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 	/*
25677c478bd9Sstevel@tonic-gate 	 * Set up multicast address filter by passing all multicast
25687c478bd9Sstevel@tonic-gate 	 * addresses through a crc generator, and then using the
25697c478bd9Sstevel@tonic-gate 	 * low order 6 bits as a index into the 64 bit logical
25707c478bd9Sstevel@tonic-gate 	 * address filter. The high order three bits select the word,
25717c478bd9Sstevel@tonic-gate 	 * while the rest of the bits select the bit within the word.
25727c478bd9Sstevel@tonic-gate 	 */
257385025c03Sgd 	PUT_MACREG(hash0, hmep->hme_ladrf[0]);
257485025c03Sgd 	PUT_MACREG(hash1, hmep->hme_ladrf[1]);
257585025c03Sgd 	PUT_MACREG(hash2, hmep->hme_ladrf[2]);
257685025c03Sgd 	PUT_MACREG(hash3, hmep->hme_ladrf[3]);
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	/*
257985025c03Sgd 	 * Configure parameters to support VLAN.  (VLAN encapsulation adds
258085025c03Sgd 	 * four bytes.)
25817c478bd9Sstevel@tonic-gate 	 */
258285025c03Sgd 	PUT_MACREG(txmax, ETHERMAX + ETHERFCSL + 4);
258385025c03Sgd 	PUT_MACREG(rxmax, ETHERMAX + ETHERFCSL + 4);
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	/*
25867c478bd9Sstevel@tonic-gate 	 * Initialize HME Global registers, ETX registers and ERX registers.
25877c478bd9Sstevel@tonic-gate 	 */
25887c478bd9Sstevel@tonic-gate 
25890219346bSGarrett D'Amore 	PUT_ETXREG(txring, hmep->hme_tmd_paddr);
25900219346bSGarrett D'Amore 	PUT_ERXREG(rxring, hmep->hme_rmd_paddr);
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	/*
25937c478bd9Sstevel@tonic-gate 	 * ERX registers can be written only if they have even no. of bits set.
25947c478bd9Sstevel@tonic-gate 	 * So, if the value written is not read back, set the lsb and write
25957c478bd9Sstevel@tonic-gate 	 * again.
25967c478bd9Sstevel@tonic-gate 	 * static	int	hme_erx_fix = 1;   : Use the fix for erx bug
25977c478bd9Sstevel@tonic-gate 	 */
25987c478bd9Sstevel@tonic-gate 	{
25997c478bd9Sstevel@tonic-gate 		uint32_t temp;
26000219346bSGarrett D'Amore 		temp  = hmep->hme_rmd_paddr;
26017c478bd9Sstevel@tonic-gate 
26027c478bd9Sstevel@tonic-gate 		if (GET_ERXREG(rxring) != temp)
26037c478bd9Sstevel@tonic-gate 			PUT_ERXREG(rxring, (temp | 4));
26047c478bd9Sstevel@tonic-gate 	}
26057c478bd9Sstevel@tonic-gate 
260685025c03Sgd 	PUT_GLOBREG(config, (hmep->hme_config |
260785025c03Sgd 	    (hmep->hme_64bit_xfer << HMEG_CONFIG_64BIT_SHIFT)));
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 	/*
26107c478bd9Sstevel@tonic-gate 	 * Significant performance improvements can be achieved by
26117c478bd9Sstevel@tonic-gate 	 * disabling transmit interrupt. Thus TMD's are reclaimed only
26127c478bd9Sstevel@tonic-gate 	 * when we run out of them in hmestart().
26137c478bd9Sstevel@tonic-gate 	 */
26147c478bd9Sstevel@tonic-gate 	PUT_GLOBREG(intmask,
261585025c03Sgd 	    HMEG_MASK_INTR | HMEG_MASK_TINT | HMEG_MASK_TX_ALL);
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	PUT_ETXREG(txring_size, ((HME_TMDMAX -1)>> HMET_RINGSZ_SHIFT));
26187c478bd9Sstevel@tonic-gate 	PUT_ETXREG(config, (GET_ETXREG(config) | HMET_CONFIG_TXDMA_EN
261985025c03Sgd 	    | HMET_CONFIG_TXFIFOTH));
26207c478bd9Sstevel@tonic-gate 	/* get the rxring size bits */
26217c478bd9Sstevel@tonic-gate 	switch (HME_RMDMAX) {
26227c478bd9Sstevel@tonic-gate 	case 32:
26237c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ32;
26247c478bd9Sstevel@tonic-gate 		break;
26257c478bd9Sstevel@tonic-gate 	case 64:
26267c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ64;
26277c478bd9Sstevel@tonic-gate 		break;
26287c478bd9Sstevel@tonic-gate 	case 128:
26297c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ128;
26307c478bd9Sstevel@tonic-gate 		break;
26317c478bd9Sstevel@tonic-gate 	case 256:
26327c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ256;
26337c478bd9Sstevel@tonic-gate 		break;
26347c478bd9Sstevel@tonic-gate 	default:
26357c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
263685025c03Sgd 		    unk_rx_ringsz_msg);
26377c478bd9Sstevel@tonic-gate 		goto init_fail;
26387c478bd9Sstevel@tonic-gate 	}
26397c478bd9Sstevel@tonic-gate 	i |= (HME_FSTBYTE_OFFSET << HMER_CONFIG_FBO_SHIFT)
264085025c03Sgd 	    | HMER_CONFIG_RXDMA_EN;
264185025c03Sgd 
264285025c03Sgd 	/* h/w checks start offset in half words */
264385025c03Sgd 	i |= ((sizeof (struct ether_header) / 2) << HMER_RX_CSSTART_SHIFT);
264485025c03Sgd 
26457c478bd9Sstevel@tonic-gate 	PUT_ERXREG(config, i);
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 	/*
26487c478bd9Sstevel@tonic-gate 	 * Bug related to the parity handling in ERX. When erxp-config is
26497c478bd9Sstevel@tonic-gate 	 * read back.
26507c478bd9Sstevel@tonic-gate 	 * Sbus/FEPS drives the parity bit. This value is used while
26517c478bd9Sstevel@tonic-gate 	 * writing again.
26527c478bd9Sstevel@tonic-gate 	 * This fixes the RECV problem in SS5.
26537c478bd9Sstevel@tonic-gate 	 * static	int	hme_erx_fix = 1;   : Use the fix for erx bug
26547c478bd9Sstevel@tonic-gate 	 */
26557c478bd9Sstevel@tonic-gate 	{
26567c478bd9Sstevel@tonic-gate 		uint32_t temp;
26577c478bd9Sstevel@tonic-gate 		temp = GET_ERXREG(config);
26587c478bd9Sstevel@tonic-gate 		PUT_ERXREG(config, i);
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 		if (GET_ERXREG(config) != i)
26617c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG4(hmep, SEVERITY_UNKNOWN, ERX_MSG,
266285025c03Sgd 			    "error:temp = %x erxp->config = %x, should be %x",
266385025c03Sgd 			    temp, GET_ERXREG(config), i);
26647c478bd9Sstevel@tonic-gate 	}
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 	/*
26677c478bd9Sstevel@tonic-gate 	 * Set up the rxconfig, txconfig and seed register without enabling
26687c478bd9Sstevel@tonic-gate 	 * them the former two at this time
26697c478bd9Sstevel@tonic-gate 	 *
26707c478bd9Sstevel@tonic-gate 	 * BigMAC strips the CRC bytes by default. Since this is
26717c478bd9Sstevel@tonic-gate 	 * contrary to other pieces of hardware, this bit needs to
26727c478bd9Sstevel@tonic-gate 	 * enabled to tell BigMAC not to strip the CRC bytes.
26737c478bd9Sstevel@tonic-gate 	 * Do not filter this node's own packets.
26747c478bd9Sstevel@tonic-gate 	 */
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 	if (hme_reject_own) {
26777c478bd9Sstevel@tonic-gate 		PUT_MACREG(rxcfg,
2678228fdff0Sgd 		    ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) |
267985025c03Sgd 		    BMAC_RXCFG_MYOWN | BMAC_RXCFG_HASH));
26807c478bd9Sstevel@tonic-gate 	} else {
26817c478bd9Sstevel@tonic-gate 		PUT_MACREG(rxcfg,
2682228fdff0Sgd 		    ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) |
268385025c03Sgd 		    BMAC_RXCFG_HASH));
26847c478bd9Sstevel@tonic-gate 	}
26857c478bd9Sstevel@tonic-gate 
26867c478bd9Sstevel@tonic-gate 	drv_usecwait(10);	/* wait after setting Hash Enable bit */
26877c478bd9Sstevel@tonic-gate 
268806673d9bSGarrett D'Amore 	fdx = (mii_get_duplex(hmep->hme_mii) == LINK_DUPLEX_FULL);
268906673d9bSGarrett D'Amore 
26907c478bd9Sstevel@tonic-gate 	if (hme_ngu_enable)
269106673d9bSGarrett D'Amore 		PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX : 0) |
269285025c03Sgd 		    BMAC_TXCFG_NGU);
26937c478bd9Sstevel@tonic-gate 	else
269406673d9bSGarrett D'Amore 		PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX: 0));
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate 	i = 0;
269706673d9bSGarrett D'Amore 	if ((hmep->hme_lance_mode) && (hmep->hme_lance_mode_enable))
269806673d9bSGarrett D'Amore 		i = ((hmep->hme_ipg0 & HME_MASK_5BIT) << BMAC_XIFC_IPG0_SHIFT)
269985025c03Sgd 		    | BMAC_XIFC_LANCE_ENAB;
270006673d9bSGarrett D'Amore 	if (phyad == HME_INTERNAL_PHYAD)
27017c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB));
27027c478bd9Sstevel@tonic-gate 	else
27037c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB | BMAC_XIFC_MIIBUFDIS));
27047c478bd9Sstevel@tonic-gate 
27057c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB);
27067c478bd9Sstevel@tonic-gate 	PUT_MACREG(txcfg, GET_MACREG(txcfg) | BMAC_TXCFG_ENAB);
27077c478bd9Sstevel@tonic-gate 
27087c478bd9Sstevel@tonic-gate 	hmep->hme_flags |= (HMERUNNING | HMEINITIALIZED);
27097c478bd9Sstevel@tonic-gate 	/*
27107c478bd9Sstevel@tonic-gate 	 * Update the interrupt mask : this will re-allow interrupts to occur
27117c478bd9Sstevel@tonic-gate 	 */
271285025c03Sgd 	PUT_GLOBREG(intmask, HMEG_MASK_INTR);
271385025c03Sgd 	mac_tx_update(hmep->hme_mh);
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate init_fail:
27167c478bd9Sstevel@tonic-gate 	/*
27177c478bd9Sstevel@tonic-gate 	 * Release the locks in reverse order
27187c478bd9Sstevel@tonic-gate 	 */
27197c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
27207c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_intrlock);
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 	ret = !(hmep->hme_flags & HMERUNNING);
27237c478bd9Sstevel@tonic-gate 	if (ret) {
27247c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
272585025c03Sgd 		    init_fail_gen_msg);
27267c478bd9Sstevel@tonic-gate 	}
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	/*
27297c478bd9Sstevel@tonic-gate 	 * Hardware checks.
27307c478bd9Sstevel@tonic-gate 	 */
27317c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
27327c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
27337c478bd9Sstevel@tonic-gate 	CHECK_MACREG();
27347c478bd9Sstevel@tonic-gate 	CHECK_ERXREG();
27357c478bd9Sstevel@tonic-gate 	CHECK_ETXREG();
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate init_exit:
27387c478bd9Sstevel@tonic-gate 	return (ret);
27397c478bd9Sstevel@tonic-gate }
27407c478bd9Sstevel@tonic-gate 
27417c478bd9Sstevel@tonic-gate /*
27427c478bd9Sstevel@tonic-gate  * Calculate the dvma burstsize by setting up a dvma temporarily.  Return
27437c478bd9Sstevel@tonic-gate  * 0 as burstsize upon failure as it signifies no burst size.
27447c478bd9Sstevel@tonic-gate  * Requests for 64-bit transfer setup, if the platform supports it.
27457c478bd9Sstevel@tonic-gate  * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f),
27467c478bd9Sstevel@tonic-gate  * sun4u Ultra-2 incorrectly returns a 32bit transfer.
27477c478bd9Sstevel@tonic-gate  */
27487c478bd9Sstevel@tonic-gate static int
27497c478bd9Sstevel@tonic-gate hmeburstsizes(struct hme *hmep)
27507c478bd9Sstevel@tonic-gate {
27517c478bd9Sstevel@tonic-gate 	int burstsizes;
27527c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t handle;
27537c478bd9Sstevel@tonic-gate 
27547c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr,
27557c478bd9Sstevel@tonic-gate 	    DDI_DMA_DONTWAIT, NULL, &handle)) {
27567c478bd9Sstevel@tonic-gate 		return (0);
27577c478bd9Sstevel@tonic-gate 	}
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 	hmep->hme_burstsizes = burstsizes = ddi_dma_burstsizes(handle);
27607c478bd9Sstevel@tonic-gate 	ddi_dma_free_handle(&handle);
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 	/*
27637c478bd9Sstevel@tonic-gate 	 * Use user-configurable parameter for enabling 64-bit transfers
27647c478bd9Sstevel@tonic-gate 	 */
27657c478bd9Sstevel@tonic-gate 	burstsizes = (hmep->hme_burstsizes >> 16);
27667c478bd9Sstevel@tonic-gate 	if (burstsizes)
27677c478bd9Sstevel@tonic-gate 		hmep->hme_64bit_xfer = hme_64bit_enable; /* user config value */
27687c478bd9Sstevel@tonic-gate 	else
27697c478bd9Sstevel@tonic-gate 		burstsizes = hmep->hme_burstsizes;
27707c478bd9Sstevel@tonic-gate 
27717c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode)
27727c478bd9Sstevel@tonic-gate 		hmep->hme_64bit_xfer = 0; /* Disable for cheerio */
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 	if (burstsizes & 0x40)
27757c478bd9Sstevel@tonic-gate 		hmep->hme_config = HMEG_CONFIG_BURST64;
27767c478bd9Sstevel@tonic-gate 	else if (burstsizes & 0x20)
27777c478bd9Sstevel@tonic-gate 		hmep->hme_config = HMEG_CONFIG_BURST32;
27787c478bd9Sstevel@tonic-gate 	else
27797c478bd9Sstevel@tonic-gate 		hmep->hme_config = HMEG_CONFIG_BURST16;
27807c478bd9Sstevel@tonic-gate 
27810219346bSGarrett D'Amore 	return (DDI_SUCCESS);
27820219346bSGarrett D'Amore }
27830219346bSGarrett D'Amore 
27840219346bSGarrett D'Amore static int
27850219346bSGarrett D'Amore hmeallocbuf(struct hme *hmep, hmebuf_t *buf, int dir)
27860219346bSGarrett D'Amore {
27870219346bSGarrett D'Amore 	ddi_dma_cookie_t	dmac;
27880219346bSGarrett D'Amore 	size_t			len;
27890219346bSGarrett D'Amore 	unsigned		ccnt;
27900219346bSGarrett D'Amore 
27910219346bSGarrett D'Amore 	if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr,
27920219346bSGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &buf->dmah) != DDI_SUCCESS) {
27930219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
27940219346bSGarrett D'Amore 		    "cannot allocate buf dma handle - failed");
27950219346bSGarrett D'Amore 		return (DDI_FAILURE);
27960219346bSGarrett D'Amore 	}
27970219346bSGarrett D'Amore 
27980219346bSGarrett D'Amore 	if (ddi_dma_mem_alloc(buf->dmah, ROUNDUP(HMEBUFSIZE, 512),
27990219346bSGarrett D'Amore 	    &hme_buf_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL,
28000219346bSGarrett D'Amore 	    &buf->kaddr, &len, &buf->acch) != DDI_SUCCESS) {
28010219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
28020219346bSGarrett D'Amore 		    "cannot allocate buf memory - failed");
28030219346bSGarrett D'Amore 		return (DDI_FAILURE);
28040219346bSGarrett D'Amore 	}
28050219346bSGarrett D'Amore 
28060219346bSGarrett D'Amore 	if (ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->kaddr,
28070219346bSGarrett D'Amore 	    len, dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
28080219346bSGarrett D'Amore 	    &dmac, &ccnt) != DDI_DMA_MAPPED) {
28090219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
28100219346bSGarrett D'Amore 		    "cannot map buf for dma - failed");
28110219346bSGarrett D'Amore 		return (DDI_FAILURE);
28120219346bSGarrett D'Amore 	}
28130219346bSGarrett D'Amore 	buf->paddr = dmac.dmac_address;
28140219346bSGarrett D'Amore 
28150219346bSGarrett D'Amore 	/* apparently they don't handle multiple cookies */
28160219346bSGarrett D'Amore 	if (ccnt > 1) {
28170219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
28180219346bSGarrett D'Amore 		    "too many buf dma cookies");
28190219346bSGarrett D'Amore 		return (DDI_FAILURE);
28200219346bSGarrett D'Amore 	}
28210219346bSGarrett D'Amore 	return (DDI_SUCCESS);
28220219346bSGarrett D'Amore }
28230219346bSGarrett D'Amore 
28240219346bSGarrett D'Amore static int
28250219346bSGarrett D'Amore hmeallocbufs(struct hme *hmep)
28260219346bSGarrett D'Amore {
28270219346bSGarrett D'Amore 	hmep->hme_tbuf = kmem_zalloc(HME_TMDMAX * sizeof (hmebuf_t), KM_SLEEP);
28280219346bSGarrett D'Amore 	hmep->hme_rbuf = kmem_zalloc(HME_RMDMAX * sizeof (hmebuf_t), KM_SLEEP);
28290219346bSGarrett D'Amore 
28300219346bSGarrett D'Amore 	/* Alloc RX buffers. */
28310219346bSGarrett D'Amore 	for (int i = 0; i < HME_RMDMAX; i++) {
28320219346bSGarrett D'Amore 		if (hmeallocbuf(hmep, &hmep->hme_rbuf[i], DDI_DMA_READ) !=
28330219346bSGarrett D'Amore 		    DDI_SUCCESS) {
28340219346bSGarrett D'Amore 			return (DDI_FAILURE);
28350219346bSGarrett D'Amore 		}
28360219346bSGarrett D'Amore 	}
28370219346bSGarrett D'Amore 
28380219346bSGarrett D'Amore 	/* Alloc TX buffers. */
28390219346bSGarrett D'Amore 	for (int i = 0; i < HME_TMDMAX; i++) {
28400219346bSGarrett D'Amore 		if (hmeallocbuf(hmep, &hmep->hme_tbuf[i], DDI_DMA_WRITE) !=
28410219346bSGarrett D'Amore 		    DDI_SUCCESS) {
28420219346bSGarrett D'Amore 			return (DDI_FAILURE);
28430219346bSGarrett D'Amore 		}
28440219346bSGarrett D'Amore 	}
28457c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
28467c478bd9Sstevel@tonic-gate }
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate static void
28497c478bd9Sstevel@tonic-gate hmefreebufs(struct hme *hmep)
28507c478bd9Sstevel@tonic-gate {
28517c478bd9Sstevel@tonic-gate 	int i;
28520219346bSGarrett D'Amore 
28530219346bSGarrett D'Amore 	if (hmep->hme_rbuf == NULL)
28540219346bSGarrett D'Amore 		return;
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate 	/*
28570219346bSGarrett D'Amore 	 * Free and unload pending xmit and recv buffers.
28587c478bd9Sstevel@tonic-gate 	 * Maintaining the 1-to-1 ordered sequence of
28590219346bSGarrett D'Amore 	 * We have written the routine to be idempotent.
28607c478bd9Sstevel@tonic-gate 	 */
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate 	for (i = 0; i < HME_TMDMAX; i++) {
28630219346bSGarrett D'Amore 		hmebuf_t *tbuf = &hmep->hme_tbuf[i];
28640219346bSGarrett D'Amore 		if (tbuf->paddr) {
28650219346bSGarrett D'Amore 			(void) ddi_dma_unbind_handle(tbuf->dmah);
28660219346bSGarrett D'Amore 		}
28670219346bSGarrett D'Amore 		if (tbuf->kaddr) {
28680219346bSGarrett D'Amore 			ddi_dma_mem_free(&tbuf->acch);
28690219346bSGarrett D'Amore 		}
28700219346bSGarrett D'Amore 		if (tbuf->dmah) {
28710219346bSGarrett D'Amore 			ddi_dma_free_handle(&tbuf->dmah);
28727c478bd9Sstevel@tonic-gate 		}
28737c478bd9Sstevel@tonic-gate 	}
28747c478bd9Sstevel@tonic-gate 	for (i = 0; i < HME_RMDMAX; i++) {
28750219346bSGarrett D'Amore 		hmebuf_t *rbuf = &hmep->hme_rbuf[i];
28760219346bSGarrett D'Amore 		if (rbuf->paddr) {
28770219346bSGarrett D'Amore 			(void) ddi_dma_unbind_handle(rbuf->dmah);
28780219346bSGarrett D'Amore 		}
28790219346bSGarrett D'Amore 		if (rbuf->kaddr) {
28800219346bSGarrett D'Amore 			ddi_dma_mem_free(&rbuf->acch);
28810219346bSGarrett D'Amore 		}
28820219346bSGarrett D'Amore 		if (rbuf->dmah) {
28830219346bSGarrett D'Amore 			ddi_dma_free_handle(&rbuf->dmah);
28847c478bd9Sstevel@tonic-gate 		}
28857c478bd9Sstevel@tonic-gate 	}
28860219346bSGarrett D'Amore 	kmem_free(hmep->hme_rbuf, HME_RMDMAX * sizeof (hmebuf_t));
28870219346bSGarrett D'Amore 	kmem_free(hmep->hme_tbuf, HME_TMDMAX * sizeof (hmebuf_t));
28887c478bd9Sstevel@tonic-gate }
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate /*
28917c478bd9Sstevel@tonic-gate  * Un-initialize (STOP) HME channel.
28927c478bd9Sstevel@tonic-gate  */
28937c478bd9Sstevel@tonic-gate static void
28947c478bd9Sstevel@tonic-gate hmeuninit(struct hme *hmep)
28957c478bd9Sstevel@tonic-gate {
28967c478bd9Sstevel@tonic-gate 	/*
28977c478bd9Sstevel@tonic-gate 	 * Allow up to 'HMEDRAINTIME' for pending xmit's to complete.
28987c478bd9Sstevel@tonic-gate 	 */
28990219346bSGarrett D'Amore 	HMEDELAY((hmep->hme_txindex == hmep->hme_txreclaim), HMEDRAINTIME);
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_intrlock);
29027c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
29037c478bd9Sstevel@tonic-gate 
29047c478bd9Sstevel@tonic-gate 	hmep->hme_flags &= ~HMERUNNING;
29057c478bd9Sstevel@tonic-gate 
29067c478bd9Sstevel@tonic-gate 	(void) hmestop(hmep);
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
29097c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_intrlock);
29107c478bd9Sstevel@tonic-gate }
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate /*
29137c478bd9Sstevel@tonic-gate  * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and
29147c478bd9Sstevel@tonic-gate  * map it in IO space. Allocate space for transmit and receive ddi_dma_handle
29157c478bd9Sstevel@tonic-gate  * structures to use the DMA interface.
29167c478bd9Sstevel@tonic-gate  */
29177c478bd9Sstevel@tonic-gate static int
29187c478bd9Sstevel@tonic-gate hmeallocthings(struct hme *hmep)
29197c478bd9Sstevel@tonic-gate {
29200219346bSGarrett D'Amore 	int			size;
29210219346bSGarrett D'Amore 	int			rval;
29220219346bSGarrett D'Amore 	size_t			real_len;
29230219346bSGarrett D'Amore 	uint_t			cookiec;
29240219346bSGarrett D'Amore 	ddi_dma_cookie_t	dmac;
29250219346bSGarrett D'Amore 	dev_info_t		*dip = hmep->dip;
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate 	/*
29287c478bd9Sstevel@tonic-gate 	 * Allocate the TMD and RMD descriptors and extra for page alignment.
29297c478bd9Sstevel@tonic-gate 	 */
29307c478bd9Sstevel@tonic-gate 
29310219346bSGarrett D'Amore 	rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL,
29320219346bSGarrett D'Amore 	    &hmep->hme_rmd_dmah);
29337c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS) {
293485025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
293585025c03Sgd 		    "cannot allocate rmd handle - failed");
29360219346bSGarrett D'Amore 		return (DDI_FAILURE);
29377c478bd9Sstevel@tonic-gate 	}
29380219346bSGarrett D'Amore 	size = HME_RMDMAX * sizeof (struct hme_rmd);
29390219346bSGarrett D'Amore 	rval = ddi_dma_mem_alloc(hmep->hme_rmd_dmah, size,
29400219346bSGarrett D'Amore 	    &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
29410219346bSGarrett D'Amore 	    &hmep->hme_rmd_kaddr, &real_len, &hmep->hme_rmd_acch);
29427c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS) {
294385025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29440219346bSGarrett D'Amore 		    "cannot allocate rmd dma mem - failed");
29450219346bSGarrett D'Amore 		return (DDI_FAILURE);
29467c478bd9Sstevel@tonic-gate 	}
29470219346bSGarrett D'Amore 	hmep->hme_rmdp = (void *)(hmep->hme_rmd_kaddr);
29480219346bSGarrett D'Amore 	rval = ddi_dma_addr_bind_handle(hmep->hme_rmd_dmah, NULL,
29490219346bSGarrett D'Amore 	    hmep->hme_rmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
29500219346bSGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec);
29517c478bd9Sstevel@tonic-gate 	if (rval != DDI_DMA_MAPPED) {
295285025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29530219346bSGarrett D'Amore 		    "cannot allocate rmd dma - failed");
29540219346bSGarrett D'Amore 		return (DDI_FAILURE);
29557c478bd9Sstevel@tonic-gate 	}
29560219346bSGarrett D'Amore 	hmep->hme_rmd_paddr = dmac.dmac_address;
29577c478bd9Sstevel@tonic-gate 	if (cookiec != 1) {
295885025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29590219346bSGarrett D'Amore 		    "too many rmd cookies - failed");
29600219346bSGarrett D'Amore 		return (DDI_FAILURE);
29617c478bd9Sstevel@tonic-gate 	}
29627c478bd9Sstevel@tonic-gate 
29630219346bSGarrett D'Amore 	rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL,
29640219346bSGarrett D'Amore 	    &hmep->hme_tmd_dmah);
29650219346bSGarrett D'Amore 	if (rval != DDI_SUCCESS) {
29660219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29670219346bSGarrett D'Amore 		    "cannot allocate tmd handle - failed");
29680219346bSGarrett D'Amore 		return (DDI_FAILURE);
29690219346bSGarrett D'Amore 	}
29700219346bSGarrett D'Amore 	size = HME_TMDMAX * sizeof (struct hme_rmd);
29710219346bSGarrett D'Amore 	rval = ddi_dma_mem_alloc(hmep->hme_tmd_dmah, size,
29720219346bSGarrett D'Amore 	    &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
29730219346bSGarrett D'Amore 	    &hmep->hme_tmd_kaddr, &real_len, &hmep->hme_tmd_acch);
29740219346bSGarrett D'Amore 	if (rval != DDI_SUCCESS) {
29750219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29760219346bSGarrett D'Amore 		    "cannot allocate tmd dma mem - failed");
29770219346bSGarrett D'Amore 		return (DDI_FAILURE);
29780219346bSGarrett D'Amore 	}
29790219346bSGarrett D'Amore 	hmep->hme_tmdp = (void *)(hmep->hme_tmd_kaddr);
29800219346bSGarrett D'Amore 	rval = ddi_dma_addr_bind_handle(hmep->hme_tmd_dmah, NULL,
29810219346bSGarrett D'Amore 	    hmep->hme_tmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
29820219346bSGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec);
29830219346bSGarrett D'Amore 	if (rval != DDI_DMA_MAPPED) {
29840219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29850219346bSGarrett D'Amore 		    "cannot allocate tmd dma - failed");
29860219346bSGarrett D'Amore 		return (DDI_FAILURE);
29870219346bSGarrett D'Amore 	}
29880219346bSGarrett D'Amore 	hmep->hme_tmd_paddr = dmac.dmac_address;
29890219346bSGarrett D'Amore 	if (cookiec != 1) {
29900219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29910219346bSGarrett D'Amore 		    "too many tmd cookies - failed");
29920219346bSGarrett D'Amore 		return (DDI_FAILURE);
29937c478bd9Sstevel@tonic-gate 	}
29947c478bd9Sstevel@tonic-gate 
29950219346bSGarrett D'Amore 	return (DDI_SUCCESS);
29967c478bd9Sstevel@tonic-gate }
29977c478bd9Sstevel@tonic-gate 
29980219346bSGarrett D'Amore static void
29990219346bSGarrett D'Amore hmefreethings(struct hme *hmep)
30000219346bSGarrett D'Amore {
30010219346bSGarrett D'Amore 	if (hmep->hme_rmd_paddr) {
30020219346bSGarrett D'Amore 		(void) ddi_dma_unbind_handle(hmep->hme_rmd_dmah);
30030219346bSGarrett D'Amore 		hmep->hme_rmd_paddr = 0;
30040219346bSGarrett D'Amore 	}
30050219346bSGarrett D'Amore 	if (hmep->hme_rmd_acch)
30060219346bSGarrett D'Amore 		ddi_dma_mem_free(&hmep->hme_rmd_acch);
30070219346bSGarrett D'Amore 	if (hmep->hme_rmd_dmah)
30080219346bSGarrett D'Amore 		ddi_dma_free_handle(&hmep->hme_rmd_dmah);
30090219346bSGarrett D'Amore 
30100219346bSGarrett D'Amore 	if (hmep->hme_tmd_paddr) {
30110219346bSGarrett D'Amore 		(void) ddi_dma_unbind_handle(hmep->hme_tmd_dmah);
30120219346bSGarrett D'Amore 		hmep->hme_tmd_paddr = 0;
30130219346bSGarrett D'Amore 	}
30140219346bSGarrett D'Amore 	if (hmep->hme_tmd_acch)
30150219346bSGarrett D'Amore 		ddi_dma_mem_free(&hmep->hme_tmd_acch);
30160219346bSGarrett D'Amore 	if (hmep->hme_tmd_dmah)
30170219346bSGarrett D'Amore 		ddi_dma_free_handle(&hmep->hme_tmd_dmah);
30180219346bSGarrett D'Amore }
30197c478bd9Sstevel@tonic-gate 
30207c478bd9Sstevel@tonic-gate /*
30217c478bd9Sstevel@tonic-gate  *	First check to see if it our device interrupting.
30227c478bd9Sstevel@tonic-gate  */
30237c478bd9Sstevel@tonic-gate static uint_t
302485025c03Sgd hmeintr(caddr_t arg)
30257c478bd9Sstevel@tonic-gate {
302685025c03Sgd 	struct hme	*hmep = (void *)arg;
30277c478bd9Sstevel@tonic-gate 	uint32_t	hmesbits;
30287c478bd9Sstevel@tonic-gate 	uint32_t	serviced = DDI_INTR_UNCLAIMED;
30297c478bd9Sstevel@tonic-gate 	uint32_t	num_reads = 0;
303085025c03Sgd 	uint32_t	rflags;
303185025c03Sgd 	mblk_t		*mp, *head, **tail;
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate 
303485025c03Sgd 	head = NULL;
303585025c03Sgd 	tail = &head;
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_intrlock);
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	/*
30407c478bd9Sstevel@tonic-gate 	 * The status register auto-clears on read except for
30417c478bd9Sstevel@tonic-gate 	 * MIF Interrupt bit
30427c478bd9Sstevel@tonic-gate 	 */
30437c478bd9Sstevel@tonic-gate 	hmesbits = GET_GLOBREG(status);
30447c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate 	/*
30477c478bd9Sstevel@tonic-gate 	 * Note: TINT is sometimes enabled in thr hmereclaim()
30487c478bd9Sstevel@tonic-gate 	 */
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate 	/*
30517c478bd9Sstevel@tonic-gate 	 * Bugid 1227832 - to handle spurious interrupts on fusion systems.
30527c478bd9Sstevel@tonic-gate 	 * Claim the first interrupt after initialization
30537c478bd9Sstevel@tonic-gate 	 */
30547c478bd9Sstevel@tonic-gate 	if (hmep->hme_flags & HMEINITIALIZED) {
30557c478bd9Sstevel@tonic-gate 		hmep->hme_flags &= ~HMEINITIALIZED;
30567c478bd9Sstevel@tonic-gate 		serviced = DDI_INTR_CLAIMED;
30577c478bd9Sstevel@tonic-gate 	}
30587c478bd9Sstevel@tonic-gate 
30597c478bd9Sstevel@tonic-gate 	if ((hmesbits & (HMEG_STATUS_INTR | HMEG_STATUS_TINT)) == 0) {
30607c478bd9Sstevel@tonic-gate 						/* No interesting interrupt */
30617c478bd9Sstevel@tonic-gate 		if (hmep->hme_intrstats) {
30627c478bd9Sstevel@tonic-gate 			if (serviced == DDI_INTR_UNCLAIMED)
30637c478bd9Sstevel@tonic-gate 				KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
30647c478bd9Sstevel@tonic-gate 			else
30657c478bd9Sstevel@tonic-gate 				KIOIP->intrs[KSTAT_INTR_HARD]++;
30667c478bd9Sstevel@tonic-gate 		}
30677c478bd9Sstevel@tonic-gate 		mutex_exit(&hmep->hme_intrlock);
30687c478bd9Sstevel@tonic-gate 		return (serviced);
30697c478bd9Sstevel@tonic-gate 	}
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 	serviced = DDI_INTR_CLAIMED;
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate 	if (!(hmep->hme_flags & HMERUNNING)) {
30747c478bd9Sstevel@tonic-gate 		if (hmep->hme_intrstats)
30757c478bd9Sstevel@tonic-gate 			KIOIP->intrs[KSTAT_INTR_HARD]++;
30767c478bd9Sstevel@tonic-gate 		mutex_exit(&hmep->hme_intrlock);
30777c478bd9Sstevel@tonic-gate 		hmeuninit(hmep);
30787c478bd9Sstevel@tonic-gate 		return (serviced);
30797c478bd9Sstevel@tonic-gate 	}
30807c478bd9Sstevel@tonic-gate 
30817c478bd9Sstevel@tonic-gate 	if (hmesbits & (HMEG_STATUS_FATAL_ERR | HMEG_STATUS_NONFATAL_ERR)) {
30827c478bd9Sstevel@tonic-gate 		if (hmesbits & HMEG_STATUS_FATAL_ERR) {
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 			if (hmep->hme_intrstats)
30857c478bd9Sstevel@tonic-gate 				KIOIP->intrs[KSTAT_INTR_HARD]++;
30867c478bd9Sstevel@tonic-gate 			hme_fatal_err(hmep, hmesbits);
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate 			mutex_exit(&hmep->hme_intrlock);
30897c478bd9Sstevel@tonic-gate 			(void) hmeinit(hmep);
30907c478bd9Sstevel@tonic-gate 			return (serviced);
30917c478bd9Sstevel@tonic-gate 		}
30927c478bd9Sstevel@tonic-gate 		hme_nonfatal_err(hmep, hmesbits);
30937c478bd9Sstevel@tonic-gate 	}
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate 	if (hmesbits & (HMEG_STATUS_TX_ALL | HMEG_STATUS_TINT)) {
30967c478bd9Sstevel@tonic-gate 		mutex_enter(&hmep->hme_xmitlock);
30977c478bd9Sstevel@tonic-gate 
30987c478bd9Sstevel@tonic-gate 		hmereclaim(hmep);
30997c478bd9Sstevel@tonic-gate 		mutex_exit(&hmep->hme_xmitlock);
31007c478bd9Sstevel@tonic-gate 	}
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RINT) {
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 		/*
31057c478bd9Sstevel@tonic-gate 		 * This dummy PIO is required to flush the SBus
31067c478bd9Sstevel@tonic-gate 		 * Bridge buffers in QFE.
31077c478bd9Sstevel@tonic-gate 		 */
31080219346bSGarrett D'Amore 		(void) GET_GLOBREG(config);
31097c478bd9Sstevel@tonic-gate 
31107c478bd9Sstevel@tonic-gate 		/*
31110219346bSGarrett D'Amore 		 * Loop through each RMD no more than once.
31127c478bd9Sstevel@tonic-gate 		 */
31130219346bSGarrett D'Amore 		while (num_reads++ < HME_RMDMAX) {
31140219346bSGarrett D'Amore 			hmebuf_t *rbuf;
31150219346bSGarrett D'Amore 			int rxptr;
31160219346bSGarrett D'Amore 
31170219346bSGarrett D'Amore 			rxptr = hmep->hme_rxindex % HME_RMDMAX;
31180219346bSGarrett D'Amore 			HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORKERNEL);
31190219346bSGarrett D'Amore 
31200219346bSGarrett D'Amore 			rflags = GET_RMD_FLAGS(rxptr);
31210219346bSGarrett D'Amore 			if (rflags & HMERMD_OWN) {
31220219346bSGarrett D'Amore 				/*
31230219346bSGarrett D'Amore 				 * Chip still owns it.  We're done.
31240219346bSGarrett D'Amore 				 */
31250219346bSGarrett D'Amore 				break;
31260219346bSGarrett D'Amore 			}
312785025c03Sgd 
31280219346bSGarrett D'Amore 			/*
31290219346bSGarrett D'Amore 			 * Retrieve the packet.
31300219346bSGarrett D'Amore 			 */
31310219346bSGarrett D'Amore 			rbuf = &hmep->hme_rbuf[rxptr];
31320219346bSGarrett D'Amore 			mp = hmeread(hmep, rbuf, rflags);
313385025c03Sgd 
31347c478bd9Sstevel@tonic-gate 			/*
31350219346bSGarrett D'Amore 			 * Return ownership of the RMD.
31367c478bd9Sstevel@tonic-gate 			 */
31370219346bSGarrett D'Amore 			PUT_RMD(rxptr, rbuf->paddr);
31380219346bSGarrett D'Amore 			HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORDEV);
31397c478bd9Sstevel@tonic-gate 
314085025c03Sgd 			if (mp != NULL) {
314185025c03Sgd 				*tail = mp;
314285025c03Sgd 				tail = &mp->b_next;
314385025c03Sgd 			}
314485025c03Sgd 
31457c478bd9Sstevel@tonic-gate 			/*
31460219346bSGarrett D'Amore 			 * Advance to the next RMD.
31477c478bd9Sstevel@tonic-gate 			 */
31480219346bSGarrett D'Amore 			hmep->hme_rxindex++;
31497c478bd9Sstevel@tonic-gate 		}
31507c478bd9Sstevel@tonic-gate 	}
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 	if (hmep->hme_intrstats)
31537c478bd9Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_HARD]++;
31547c478bd9Sstevel@tonic-gate 
31557c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_intrlock);
315685025c03Sgd 
315785025c03Sgd 	if (head != NULL)
315885025c03Sgd 		mac_rx(hmep->hme_mh, NULL, head);
315985025c03Sgd 
31607c478bd9Sstevel@tonic-gate 	return (serviced);
31617c478bd9Sstevel@tonic-gate }
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate /*
31647c478bd9Sstevel@tonic-gate  * Transmit completion reclaiming.
31657c478bd9Sstevel@tonic-gate  */
31667c478bd9Sstevel@tonic-gate static void
31677c478bd9Sstevel@tonic-gate hmereclaim(struct hme *hmep)
31687c478bd9Sstevel@tonic-gate {
31690219346bSGarrett D'Amore 	boolean_t	reclaimed = B_FALSE;
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate 	/*
31727c478bd9Sstevel@tonic-gate 	 * Loop through each TMD.
31737c478bd9Sstevel@tonic-gate 	 */
31740219346bSGarrett D'Amore 	while (hmep->hme_txindex > hmep->hme_txreclaim) {
31750219346bSGarrett D'Amore 
31760219346bSGarrett D'Amore 		int		reclaim;
31770219346bSGarrett D'Amore 		uint32_t	flags;
31780219346bSGarrett D'Amore 
31790219346bSGarrett D'Amore 		reclaim = hmep->hme_txreclaim % HME_TMDMAX;
31800219346bSGarrett D'Amore 		HMESYNCTMD(reclaim, DDI_DMA_SYNC_FORKERNEL);
31810219346bSGarrett D'Amore 
31820219346bSGarrett D'Amore 		flags = GET_TMD_FLAGS(reclaim);
31830219346bSGarrett D'Amore 		if (flags & HMETMD_OWN) {
31840219346bSGarrett D'Amore 			/*
31850219346bSGarrett D'Amore 			 * Chip still owns it.  We're done.
31860219346bSGarrett D'Amore 			 */
31870219346bSGarrett D'Amore 			break;
31880219346bSGarrett D'Amore 		}
31897c478bd9Sstevel@tonic-gate 
31907c478bd9Sstevel@tonic-gate 		/*
31910219346bSGarrett D'Amore 		 * Count a chained packet only once.
31927c478bd9Sstevel@tonic-gate 		 */
31930219346bSGarrett D'Amore 		if (flags & HMETMD_SOP) {
31947c478bd9Sstevel@tonic-gate 			hmep->hme_opackets++;
31957c478bd9Sstevel@tonic-gate 		}
31967c478bd9Sstevel@tonic-gate 
31977c478bd9Sstevel@tonic-gate 		/*
31987c478bd9Sstevel@tonic-gate 		 * MIB II
31997c478bd9Sstevel@tonic-gate 		 */
32000219346bSGarrett D'Amore 		hmep->hme_obytes += flags & HMETMD_BUFSIZE;
32017c478bd9Sstevel@tonic-gate 
32020219346bSGarrett D'Amore 		reclaimed = B_TRUE;
32030219346bSGarrett D'Amore 		hmep->hme_txreclaim++;
32047c478bd9Sstevel@tonic-gate 	}
32057c478bd9Sstevel@tonic-gate 
32060219346bSGarrett D'Amore 	if (reclaimed) {
32077c478bd9Sstevel@tonic-gate 		/*
32087c478bd9Sstevel@tonic-gate 		 * we could reclaim some TMDs so turn off interrupts
32097c478bd9Sstevel@tonic-gate 		 */
32107c478bd9Sstevel@tonic-gate 		if (hmep->hme_wantw) {
32117c478bd9Sstevel@tonic-gate 			PUT_GLOBREG(intmask,
321285025c03Sgd 			    HMEG_MASK_INTR | HMEG_MASK_TINT |
321385025c03Sgd 			    HMEG_MASK_TX_ALL);
321485025c03Sgd 			hmep->hme_wantw = B_FALSE;
321585025c03Sgd 			mac_tx_update(hmep->hme_mh);
32167c478bd9Sstevel@tonic-gate 		}
32177c478bd9Sstevel@tonic-gate 	} else {
32187c478bd9Sstevel@tonic-gate 		/*
32197c478bd9Sstevel@tonic-gate 		 * enable TINTS: so that even if there is no further activity
32207c478bd9Sstevel@tonic-gate 		 * hmereclaim will get called
32217c478bd9Sstevel@tonic-gate 		 */
32227c478bd9Sstevel@tonic-gate 		if (hmep->hme_wantw)
322385025c03Sgd 			PUT_GLOBREG(intmask,
322485025c03Sgd 			    GET_GLOBREG(intmask) & ~HMEG_MASK_TX_ALL);
32257c478bd9Sstevel@tonic-gate 	}
32267c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
32277c478bd9Sstevel@tonic-gate }
32287c478bd9Sstevel@tonic-gate 
32297c478bd9Sstevel@tonic-gate /*
32307c478bd9Sstevel@tonic-gate  * Handle interrupts for fatal errors
32317c478bd9Sstevel@tonic-gate  * Need reinitialization of the ENET channel.
32327c478bd9Sstevel@tonic-gate  */
32337c478bd9Sstevel@tonic-gate static void
32347c478bd9Sstevel@tonic-gate hme_fatal_err(struct hme *hmep, uint_t hmesbits)
32357c478bd9Sstevel@tonic-gate {
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_SLV_PAR_ERR) {
32387c478bd9Sstevel@tonic-gate 		hmep->hme_slvparerr++;
32397c478bd9Sstevel@tonic-gate 	}
32407c478bd9Sstevel@tonic-gate 
32417c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_SLV_ERR_ACK) {
32427c478bd9Sstevel@tonic-gate 		hmep->hme_slverrack++;
32437c478bd9Sstevel@tonic-gate 	}
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_TAG_ERR) {
32467c478bd9Sstevel@tonic-gate 		hmep->hme_txtagerr++;
32477c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
32487c478bd9Sstevel@tonic-gate 	}
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_PAR_ERR) {
32517c478bd9Sstevel@tonic-gate 		hmep->hme_txparerr++;
32527c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
32537c478bd9Sstevel@tonic-gate 	}
32547c478bd9Sstevel@tonic-gate 
32557c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_LATE_ERR) {
32567c478bd9Sstevel@tonic-gate 		hmep->hme_txlaterr++;
32577c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
32587c478bd9Sstevel@tonic-gate 	}
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_ERR_ACK) {
32617c478bd9Sstevel@tonic-gate 		hmep->hme_txerrack++;
32627c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
32637c478bd9Sstevel@tonic-gate 	}
32647c478bd9Sstevel@tonic-gate 
32657c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_EOP_ERR) {
32667c478bd9Sstevel@tonic-gate 		hmep->hme_eoperr++;
32677c478bd9Sstevel@tonic-gate 	}
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_TAG_ERR) {
32707c478bd9Sstevel@tonic-gate 		hmep->hme_rxtagerr++;
32717c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
32727c478bd9Sstevel@tonic-gate 	}
32737c478bd9Sstevel@tonic-gate 
32747c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_PAR_ERR) {
32757c478bd9Sstevel@tonic-gate 		hmep->hme_rxparerr++;
32767c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
32777c478bd9Sstevel@tonic-gate 	}
32787c478bd9Sstevel@tonic-gate 
32797c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_LATE_ERR) {
32807c478bd9Sstevel@tonic-gate 		hmep->hme_rxlaterr++;
32817c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
32827c478bd9Sstevel@tonic-gate 	}
32837c478bd9Sstevel@tonic-gate 
32847c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_ERR_ACK) {
32857c478bd9Sstevel@tonic-gate 		hmep->hme_rxerrack++;
32867c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
32877c478bd9Sstevel@tonic-gate 	}
32887c478bd9Sstevel@tonic-gate }
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate /*
32917c478bd9Sstevel@tonic-gate  * Handle interrupts regarding non-fatal errors.
32927c478bd9Sstevel@tonic-gate  */
32937c478bd9Sstevel@tonic-gate static void
32947c478bd9Sstevel@tonic-gate hme_nonfatal_err(struct hme *hmep, uint_t hmesbits)
32957c478bd9Sstevel@tonic-gate {
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_DROP) {
32987c478bd9Sstevel@tonic-gate 		hmep->hme_missed++;
32997c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
33007c478bd9Sstevel@tonic-gate 	}
33017c478bd9Sstevel@tonic-gate 
33027c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_DEFTIMR_EXP) {
33037c478bd9Sstevel@tonic-gate 		hmep->hme_defer_xmts++;
33047c478bd9Sstevel@tonic-gate 	}
33057c478bd9Sstevel@tonic-gate 
33067c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_FSTCOLC_EXP) {
33077c478bd9Sstevel@tonic-gate 		hmep->hme_fstcol += 256;
33087c478bd9Sstevel@tonic-gate 	}
33097c478bd9Sstevel@tonic-gate 
33107c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_LATCOLC_EXP) {
33117c478bd9Sstevel@tonic-gate 		hmep->hme_tlcol += 256;
33127c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors += 256;
33137c478bd9Sstevel@tonic-gate 	}
33147c478bd9Sstevel@tonic-gate 
33157c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_EXCOLC_EXP) {
331685025c03Sgd 		hmep->hme_excol += 256;
33177c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors += 256;
33187c478bd9Sstevel@tonic-gate 	}
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_NRMCOLC_EXP) {
33217c478bd9Sstevel@tonic-gate 		hmep->hme_coll += 256;
33227c478bd9Sstevel@tonic-gate 	}
33237c478bd9Sstevel@tonic-gate 
33247c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_MXPKTSZ_ERR) {
33257c478bd9Sstevel@tonic-gate 		hmep->hme_babl++;
33267c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
33277c478bd9Sstevel@tonic-gate 	}
33287c478bd9Sstevel@tonic-gate 
33297c478bd9Sstevel@tonic-gate 	/*
33307c478bd9Sstevel@tonic-gate 	 * This error is fatal and the board needs to
33317c478bd9Sstevel@tonic-gate 	 * be reinitialized. Comments?
33327c478bd9Sstevel@tonic-gate 	 */
33337c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TXFIFO_UNDR) {
33347c478bd9Sstevel@tonic-gate 		hmep->hme_uflo++;
33357c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
33367c478bd9Sstevel@tonic-gate 	}
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_SQE_TST_ERR) {
33397c478bd9Sstevel@tonic-gate 		hmep->hme_sqe_errors++;
33407c478bd9Sstevel@tonic-gate 	}
33417c478bd9Sstevel@tonic-gate 
33427c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RCV_CNT_EXP) {
33437c478bd9Sstevel@tonic-gate 		if (hmep->hme_rxcv_enable) {
33447c478bd9Sstevel@tonic-gate 			hmep->hme_cvc += 256;
33457c478bd9Sstevel@tonic-gate 		}
33467c478bd9Sstevel@tonic-gate 	}
33477c478bd9Sstevel@tonic-gate 
33487c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RXFIFO_OVFL) {
33497c478bd9Sstevel@tonic-gate 		hmep->hme_oflo++;
33507c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
33517c478bd9Sstevel@tonic-gate 	}
33527c478bd9Sstevel@tonic-gate 
33537c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_LEN_CNT_EXP) {
33547c478bd9Sstevel@tonic-gate 		hmep->hme_lenerr += 256;
33557c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors += 256;
33567c478bd9Sstevel@tonic-gate 	}
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_ALN_CNT_EXP) {
33597c478bd9Sstevel@tonic-gate 		hmep->hme_align_errors += 256;
33607c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors += 256;
33617c478bd9Sstevel@tonic-gate 	}
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_CRC_CNT_EXP) {
33647c478bd9Sstevel@tonic-gate 		hmep->hme_fcs_errors += 256;
33657c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors += 256;
33667c478bd9Sstevel@tonic-gate 	}
33677c478bd9Sstevel@tonic-gate }
33687c478bd9Sstevel@tonic-gate 
336985025c03Sgd static mblk_t *
33700219346bSGarrett D'Amore hmeread(struct hme *hmep, hmebuf_t *rbuf, uint32_t rflags)
33717c478bd9Sstevel@tonic-gate {
33720219346bSGarrett D'Amore 	mblk_t		*bp;
33730219346bSGarrett D'Amore 	uint32_t	len;
33740219346bSGarrett D'Amore 	t_uscalar_t	type;
33750219346bSGarrett D'Amore 
337685025c03Sgd 	len = (rflags & HMERMD_BUFSIZE) >> HMERMD_BUFSIZE_SHIFT;
33777c478bd9Sstevel@tonic-gate 
33787c478bd9Sstevel@tonic-gate 	/*
33797c478bd9Sstevel@tonic-gate 	 * Check for short packet
33807c478bd9Sstevel@tonic-gate 	 * and check for overflow packet also. The processing is the
33817c478bd9Sstevel@tonic-gate 	 * same for both the cases - reuse the buffer. Update the Buffer
33827c478bd9Sstevel@tonic-gate 	 * overflow counter.
33837c478bd9Sstevel@tonic-gate 	 */
338485025c03Sgd 	if ((len < ETHERMIN) || (rflags & HMERMD_OVFLOW) ||
338585025c03Sgd 	    (len > (ETHERMAX + 4))) {
33867c478bd9Sstevel@tonic-gate 		if (len < ETHERMIN)
33877c478bd9Sstevel@tonic-gate 			hmep->hme_runt++;
33887c478bd9Sstevel@tonic-gate 
33897c478bd9Sstevel@tonic-gate 		else {
33907c478bd9Sstevel@tonic-gate 			hmep->hme_buff++;
33917c478bd9Sstevel@tonic-gate 			hmep->hme_toolong_errors++;
33927c478bd9Sstevel@tonic-gate 		}
33937c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
339485025c03Sgd 		return (NULL);
33957c478bd9Sstevel@tonic-gate 	}
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate 	/*
33987c478bd9Sstevel@tonic-gate 	 * Sync the received buffer before looking at it.
33997c478bd9Sstevel@tonic-gate 	 */
34007c478bd9Sstevel@tonic-gate 
34010219346bSGarrett D'Amore 	(void) ddi_dma_sync(rbuf->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
34027c478bd9Sstevel@tonic-gate 
34037c478bd9Sstevel@tonic-gate 	/*
34047c478bd9Sstevel@tonic-gate 	 * copy the packet data and then recycle the descriptor.
34057c478bd9Sstevel@tonic-gate 	 */
34067c478bd9Sstevel@tonic-gate 
34070219346bSGarrett D'Amore 	if ((bp = allocb(len + HME_FSTBYTE_OFFSET, BPRI_HI)) == NULL) {
34087c478bd9Sstevel@tonic-gate 
34097c478bd9Sstevel@tonic-gate 		hmep->hme_allocbfail++;
34107c478bd9Sstevel@tonic-gate 		hmep->hme_norcvbuf++;
341185025c03Sgd 
341285025c03Sgd 		return (NULL);
34137c478bd9Sstevel@tonic-gate 	}
34147c478bd9Sstevel@tonic-gate 
34150219346bSGarrett D'Amore 	bcopy(rbuf->kaddr, bp->b_rptr, len + HME_FSTBYTE_OFFSET);
34167c478bd9Sstevel@tonic-gate 
34170219346bSGarrett D'Amore 	hmep->hme_ipackets++;
34187c478bd9Sstevel@tonic-gate 
34190219346bSGarrett D'Amore 	/*  Add the First Byte offset to the b_rptr and copy */
34200219346bSGarrett D'Amore 	bp->b_rptr += HME_FSTBYTE_OFFSET;
34210219346bSGarrett D'Amore 	bp->b_wptr = bp->b_rptr + len;
34227c478bd9Sstevel@tonic-gate 
34237c478bd9Sstevel@tonic-gate 	/*
34240219346bSGarrett D'Amore 	 * update MIB II statistics
34257c478bd9Sstevel@tonic-gate 	 */
34260219346bSGarrett D'Amore 	BUMP_InNUcast(hmep, bp->b_rptr);
34270219346bSGarrett D'Amore 	hmep->hme_rbytes += len;
34287c478bd9Sstevel@tonic-gate 
34290219346bSGarrett D'Amore 	type = get_ether_type(bp->b_rptr);
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate 	/*
34320219346bSGarrett D'Amore 	 * TCP partial checksum in hardware
34337c478bd9Sstevel@tonic-gate 	 */
34340219346bSGarrett D'Amore 	if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) {
34350219346bSGarrett D'Amore 		uint16_t cksum = ~rflags & HMERMD_CKSUM;
34360219346bSGarrett D'Amore 		uint_t end = len - sizeof (struct ether_header);
34370219346bSGarrett D'Amore 		(void) hcksum_assoc(bp, NULL, NULL, 0,
34380219346bSGarrett D'Amore 		    0, end, htons(cksum), HCK_PARTIALCKSUM, 0);
34397c478bd9Sstevel@tonic-gate 	}
34407c478bd9Sstevel@tonic-gate 
344185025c03Sgd 	return (bp);
34427c478bd9Sstevel@tonic-gate }
34437c478bd9Sstevel@tonic-gate 
34447c478bd9Sstevel@tonic-gate /*VARARGS*/
34457c478bd9Sstevel@tonic-gate static void
34460219346bSGarrett D'Amore hme_fault_msg(struct hme *hmep, uint_t severity, msg_t type, char *fmt, ...)
34477c478bd9Sstevel@tonic-gate {
34487c478bd9Sstevel@tonic-gate 	char	msg_buffer[255];
34497c478bd9Sstevel@tonic-gate 	va_list	ap;
34507c478bd9Sstevel@tonic-gate 
34517c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
3452228fdff0Sgd 	(void) vsnprintf(msg_buffer, sizeof (msg_buffer), fmt, ap);
34537c478bd9Sstevel@tonic-gate 
345485025c03Sgd 	if (hmep == NULL) {
34557c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "hme : %s", msg_buffer);
34567c478bd9Sstevel@tonic-gate 
345785025c03Sgd 	} else if (type == DISPLAY_MSG) {
345885025c03Sgd 		cmn_err(CE_CONT, "?%s%d : %s\n", ddi_driver_name(hmep->dip),
345985025c03Sgd 		    hmep->instance, msg_buffer);
346085025c03Sgd 	} else if (severity == SEVERITY_HIGH) {
346185025c03Sgd 		cmn_err(CE_WARN, "%s%d : %s, SEVERITY_HIGH, %s\n",
346285025c03Sgd 		    ddi_driver_name(hmep->dip), hmep->instance,
346385025c03Sgd 		    msg_buffer, msg_string[type]);
346485025c03Sgd 	} else {
346585025c03Sgd 		cmn_err(CE_CONT, "%s%d : %s\n", ddi_driver_name(hmep->dip),
346685025c03Sgd 		    hmep->instance, msg_buffer);
346785025c03Sgd 	}
34687c478bd9Sstevel@tonic-gate 	va_end(ap);
34697c478bd9Sstevel@tonic-gate }
34707c478bd9Sstevel@tonic-gate 
34717c478bd9Sstevel@tonic-gate /*
34727c478bd9Sstevel@tonic-gate  * if this is the first init do not bother to save the
34737c478bd9Sstevel@tonic-gate  * counters. They should be 0, but do not count on it.
34747c478bd9Sstevel@tonic-gate  */
34757c478bd9Sstevel@tonic-gate static void
34767c478bd9Sstevel@tonic-gate hmesavecntrs(struct hme *hmep)
34777c478bd9Sstevel@tonic-gate {
34787c478bd9Sstevel@tonic-gate 	uint32_t fecnt, aecnt, lecnt, rxcv;
34797c478bd9Sstevel@tonic-gate 	uint32_t ltcnt, excnt;
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate 	/* XXX What all gets added in ierrors and oerrors? */
34827c478bd9Sstevel@tonic-gate 	fecnt = GET_MACREG(fecnt);
34837c478bd9Sstevel@tonic-gate 	PUT_MACREG(fecnt, 0);
34847c478bd9Sstevel@tonic-gate 
34857c478bd9Sstevel@tonic-gate 	aecnt = GET_MACREG(aecnt);
34867c478bd9Sstevel@tonic-gate 	hmep->hme_align_errors += aecnt;
34877c478bd9Sstevel@tonic-gate 	PUT_MACREG(aecnt, 0);
34887c478bd9Sstevel@tonic-gate 
34897c478bd9Sstevel@tonic-gate 	lecnt = GET_MACREG(lecnt);
34907c478bd9Sstevel@tonic-gate 	hmep->hme_lenerr += lecnt;
34917c478bd9Sstevel@tonic-gate 	PUT_MACREG(lecnt, 0);
34927c478bd9Sstevel@tonic-gate 
34937c478bd9Sstevel@tonic-gate 	rxcv = GET_MACREG(rxcv);
34947c478bd9Sstevel@tonic-gate #ifdef HME_CODEVIOL_BUG
34957c478bd9Sstevel@tonic-gate 	/*
34967c478bd9Sstevel@tonic-gate 	 * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier
34977c478bd9Sstevel@tonic-gate 	 */
34987c478bd9Sstevel@tonic-gate 	if (!hmep->hme_rxcv_enable) {
34997c478bd9Sstevel@tonic-gate 		rxcv = 0;
35007c478bd9Sstevel@tonic-gate 	}
35017c478bd9Sstevel@tonic-gate #endif
35027c478bd9Sstevel@tonic-gate 	hmep->hme_cvc += rxcv;
35037c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcv, 0);
35047c478bd9Sstevel@tonic-gate 
35057c478bd9Sstevel@tonic-gate 	ltcnt = GET_MACREG(ltcnt);
35067c478bd9Sstevel@tonic-gate 	hmep->hme_tlcol += ltcnt;
35077c478bd9Sstevel@tonic-gate 	PUT_MACREG(ltcnt, 0);
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate 	excnt = GET_MACREG(excnt);
351085025c03Sgd 	hmep->hme_excol += excnt;
35117c478bd9Sstevel@tonic-gate 	PUT_MACREG(excnt, 0);
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate 	hmep->hme_fcs_errors += fecnt;
35147c478bd9Sstevel@tonic-gate 	hmep->hme_ierrors += (fecnt + aecnt + lecnt);
35157c478bd9Sstevel@tonic-gate 	hmep->hme_oerrors += (ltcnt + excnt);
35167c478bd9Sstevel@tonic-gate 	hmep->hme_coll += (GET_MACREG(nccnt) + ltcnt);
35177c478bd9Sstevel@tonic-gate 
35187c478bd9Sstevel@tonic-gate 	PUT_MACREG(nccnt, 0);
35197c478bd9Sstevel@tonic-gate 	CHECK_MACREG();
35207c478bd9Sstevel@tonic-gate }
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate /*
35237c478bd9Sstevel@tonic-gate  * To set up the mac address for the network interface:
35247c478bd9Sstevel@tonic-gate  * The adapter card may support a local mac address which is published
35257c478bd9Sstevel@tonic-gate  * in a device node property "local-mac-address". This mac address is
35267c478bd9Sstevel@tonic-gate  * treated as the factory-installed mac address for DLPI interface.
35277c478bd9Sstevel@tonic-gate  * If the adapter firmware has used the device for diskless boot
35287c478bd9Sstevel@tonic-gate  * operation it publishes a property called "mac-address" for use by
35297c478bd9Sstevel@tonic-gate  * inetboot and the device driver.
35307c478bd9Sstevel@tonic-gate  * If "mac-address" is not found, the system options property
35317c478bd9Sstevel@tonic-gate  * "local-mac-address" is used to select the mac-address. If this option
35327c478bd9Sstevel@tonic-gate  * is set to "true", and "local-mac-address" has been found, then
35337c478bd9Sstevel@tonic-gate  * local-mac-address is used; otherwise the system mac address is used
35347c478bd9Sstevel@tonic-gate  * by calling the "localetheraddr()" function.
35357c478bd9Sstevel@tonic-gate  */
35367c478bd9Sstevel@tonic-gate static void
35377c478bd9Sstevel@tonic-gate hme_setup_mac_address(struct hme *hmep, dev_info_t *dip)
35387c478bd9Sstevel@tonic-gate {
35397c478bd9Sstevel@tonic-gate 	char	*prop;
35407c478bd9Sstevel@tonic-gate 	int	prop_len = sizeof (int);
35417c478bd9Sstevel@tonic-gate 
35427c478bd9Sstevel@tonic-gate 	hmep->hme_addrflags = 0;
35437c478bd9Sstevel@tonic-gate 
35447c478bd9Sstevel@tonic-gate 	/*
35457c478bd9Sstevel@tonic-gate 	 * Check if it is an adapter with its own local mac address
35467c478bd9Sstevel@tonic-gate 	 * If it is present, save it as the "factory-address"
35477c478bd9Sstevel@tonic-gate 	 * for this adapter.
35487c478bd9Sstevel@tonic-gate 	 */
354985025c03Sgd 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
355085025c03Sgd 	    "local-mac-address",
355185025c03Sgd 	    (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
35527c478bd9Sstevel@tonic-gate 		if (prop_len == ETHERADDRL) {
35537c478bd9Sstevel@tonic-gate 			hmep->hme_addrflags = HME_FACTADDR_PRESENT;
35547c478bd9Sstevel@tonic-gate 			ether_bcopy(prop, &hmep->hme_factaddr);
35557c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
35560219346bSGarrett D'Amore 			    "Local Ethernet address = %s",
355785025c03Sgd 			    ether_sprintf(&hmep->hme_factaddr));
35587c478bd9Sstevel@tonic-gate 		}
35597c478bd9Sstevel@tonic-gate 		kmem_free(prop, prop_len);
35607c478bd9Sstevel@tonic-gate 	}
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate 	/*
35637c478bd9Sstevel@tonic-gate 	 * Check if the adapter has published "mac-address" property.
35647c478bd9Sstevel@tonic-gate 	 * If it is present, use it as the mac address for this device.
35657c478bd9Sstevel@tonic-gate 	 */
356685025c03Sgd 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
356785025c03Sgd 	    "mac-address", (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
35687c478bd9Sstevel@tonic-gate 		if (prop_len >= ETHERADDRL) {
35697c478bd9Sstevel@tonic-gate 			ether_bcopy(prop, &hmep->hme_ouraddr);
35707c478bd9Sstevel@tonic-gate 			kmem_free(prop, prop_len);
35717c478bd9Sstevel@tonic-gate 			return;
35727c478bd9Sstevel@tonic-gate 		}
35737c478bd9Sstevel@tonic-gate 		kmem_free(prop, prop_len);
35747c478bd9Sstevel@tonic-gate 	}
35757c478bd9Sstevel@tonic-gate 
35760219346bSGarrett D'Amore #ifdef	__sparc
35770219346bSGarrett D'Amore 	/*
35780219346bSGarrett D'Amore 	 * On sparc, we might be able to use the mac address from the
35790219346bSGarrett D'Amore 	 * system.  However, on all other systems, we need to use the
35800219346bSGarrett D'Amore 	 * address from the PROM.
35810219346bSGarrett D'Amore 	 */
35827c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "local-mac-address?",
358385025c03Sgd 	    (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
35847c478bd9Sstevel@tonic-gate 		if ((strncmp("true", prop, prop_len) == 0) &&
358585025c03Sgd 		    (hmep->hme_addrflags & HME_FACTADDR_PRESENT)) {
35867c478bd9Sstevel@tonic-gate 			hmep->hme_addrflags |= HME_FACTADDR_USE;
35877c478bd9Sstevel@tonic-gate 			ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr);
35887c478bd9Sstevel@tonic-gate 			kmem_free(prop, prop_len);
35897c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_NONE, DISPLAY_MSG,
35900219346bSGarrett D'Amore 			    "Using local MAC address");
35917c478bd9Sstevel@tonic-gate 			return;
35927c478bd9Sstevel@tonic-gate 		}
35937c478bd9Sstevel@tonic-gate 		kmem_free(prop, prop_len);
35947c478bd9Sstevel@tonic-gate 	}
35957c478bd9Sstevel@tonic-gate 
35967c478bd9Sstevel@tonic-gate 	/*
35977c478bd9Sstevel@tonic-gate 	 * Get the system ethernet address.
35987c478bd9Sstevel@tonic-gate 	 */
35997c478bd9Sstevel@tonic-gate 	(void) localetheraddr((struct ether_addr *)NULL, &hmep->hme_ouraddr);
36000219346bSGarrett D'Amore #else
36010219346bSGarrett D'Amore 	ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr);
36020219346bSGarrett D'Amore #endif
36037c478bd9Sstevel@tonic-gate }
36047c478bd9Sstevel@tonic-gate 
36057c478bd9Sstevel@tonic-gate /* ARGSUSED */
36067c478bd9Sstevel@tonic-gate static void
36077c478bd9Sstevel@tonic-gate hme_check_acc_handle(char *file, uint_t line, struct hme *hmep,
36087c478bd9Sstevel@tonic-gate     ddi_acc_handle_t handle)
36097c478bd9Sstevel@tonic-gate {
36107c478bd9Sstevel@tonic-gate }
3611