17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5447e4a6petede * Common Development and Distribution License (the "License").
6447e4a6petede * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
227a92e70Zeeshanul Huq - Sun Microsystems - Beijing China * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bdstevel@tonic-gate */
247c478bdstevel@tonic-gate
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate/*
277c478bdstevel@tonic-gate * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver
287c478bdstevel@tonic-gate */
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate#include	<sys/types.h>
317c478bdstevel@tonic-gate#include	<sys/debug.h>
327c478bdstevel@tonic-gate#include	<sys/stream.h>
337c478bdstevel@tonic-gate#include	<sys/cmn_err.h>
347c478bdstevel@tonic-gate#include	<sys/kmem.h>
357c478bdstevel@tonic-gate#include	<sys/crc32.h>
3685025c0gd#include	<sys/modctl.h>
3785025c0gd#include	<sys/conf.h>
387c478bdstevel@tonic-gate#include	<sys/strsun.h>
397c478bdstevel@tonic-gate#include	<sys/kstat.h>
4085025c0gd#include	<sys/pattr.h>
417c478bdstevel@tonic-gate#include	<sys/dlpi.h>
4285025c0gd#include	<sys/strsubr.h>
43da14cebEric Cheng#include	<sys/mac_provider.h>
4485025c0gd#include	<sys/mac_ether.h>
4506673d9Garrett D'Amore#include	<sys/mii.h>
467c478bdstevel@tonic-gate#include	<sys/ethernet.h>
47d62bc4byz#include	<sys/vlan.h>
4885025c0gd#include	<sys/pci.h>
4985025c0gd#include	<sys/policy.h>
5085025c0gd#include	<sys/ddi.h>
5185025c0gd#include	<sys/sunddi.h>
520dc2366Venugopal Iyer#include	<sys/byteorder.h>
530219346Garrett D'Amore#include	"hme_phy.h"
540219346Garrett D'Amore#include	"hme_mac.h"
550219346Garrett D'Amore#include	"hme.h"
567c478bdstevel@tonic-gate
577c478bdstevel@tonic-gatetypedef void	(*fptrv_t)();
587c478bdstevel@tonic-gate
597c478bdstevel@tonic-gatetypedef enum {
607c478bdstevel@tonic-gate	NO_MSG		= 0,
6106673d9Garrett D'Amore	AUTOCONFIG_MSG,
6206673d9Garrett D'Amore	DISPLAY_MSG,
6306673d9Garrett D'Amore	INIT_MSG,
6406673d9Garrett D'Amore	UNINIT_MSG,
6506673d9Garrett D'Amore	CONFIG_MSG,
6606673d9Garrett D'Amore	MII_MSG,
6706673d9Garrett D'Amore	FATAL_ERR_MSG,
6806673d9Garrett D'Amore	NFATAL_ERR_MSG,
6906673d9Garrett D'Amore	XCVR_MSG,
7006673d9Garrett D'Amore	NOXCVR_MSG,
7106673d9Garrett D'Amore	ERX_MSG,
7206673d9Garrett D'Amore	DDI_MSG,
737c478bdstevel@tonic-gate} msg_t;
747c478bdstevel@tonic-gate
757c478bdstevel@tonic-gatemsg_t	hme_debug_level =	NO_MSG;
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gatestatic char	*msg_string[] = {
787c478bdstevel@tonic-gate	"NONE       ",
797c478bdstevel@tonic-gate	"AUTOCONFIG ",
8006673d9Garrett D'Amore	"DISPLAY	"
817c478bdstevel@tonic-gate	"INIT       ",
827c478bdstevel@tonic-gate	"UNINIT		",
837c478bdstevel@tonic-gate	"CONFIG	",
8406673d9Garrett D'Amore	"MII	",
857c478bdstevel@tonic-gate	"FATAL_ERR	",
867c478bdstevel@tonic-gate	"NFATAL_ERR	",
877c478bdstevel@tonic-gate	"XCVR	",
887c478bdstevel@tonic-gate	"NOXCVR	",
897c478bdstevel@tonic-gate	"ERX	",
907c478bdstevel@tonic-gate	"DDI	",
917c478bdstevel@tonic-gate};
927c478bdstevel@tonic-gate
937c478bdstevel@tonic-gate#define	SEVERITY_NONE	0
947c478bdstevel@tonic-gate#define	SEVERITY_LOW	0
957c478bdstevel@tonic-gate#define	SEVERITY_MID	1
967c478bdstevel@tonic-gate#define	SEVERITY_HIGH	2
977c478bdstevel@tonic-gate#define	SEVERITY_UNKNOWN 99
987c478bdstevel@tonic-gate
997c478bdstevel@tonic-gate#define	FEPS_URUN_BUG
1007c478bdstevel@tonic-gate#define	HME_CODEVIOL_BUG
1017c478bdstevel@tonic-gate
1027c478bdstevel@tonic-gate#define	KIOIP	KSTAT_INTR_PTR(hmep->hme_intrstats)
1037c478bdstevel@tonic-gate
1047c478bdstevel@tonic-gate/*
1057c478bdstevel@tonic-gate * The following variables are used for checking fixes in Sbus/FEPS 2.0
1067c478bdstevel@tonic-gate */
1077c478bdstevel@tonic-gatestatic	int	hme_urun_fix = 0;	/* Bug fixed in Sbus/FEPS 2.0 */
1087c478bdstevel@tonic-gate
1097c478bdstevel@tonic-gate/*
1107c478bdstevel@tonic-gate * The following variables are used for configuring various features
1117c478bdstevel@tonic-gate */
1127c478bdstevel@tonic-gatestatic	int	hme_64bit_enable =	1;	/* Use 64-bit sbus transfers */
1137c478bdstevel@tonic-gatestatic	int	hme_reject_own =	1;	/* Reject packets with own SA */
11406673d9Garrett D'Amorestatic	int	hme_ngu_enable =	0;	/* Never Give Up mode */
1157c478bdstevel@tonic-gate
1160dc2366Venugopal Iyerchar *hme_priv_prop[] = {
1170dc2366Venugopal Iyer	"_ipg0",
1180dc2366Venugopal Iyer	"_ipg1",
1190dc2366Venugopal Iyer	"_ipg2",
1200dc2366Venugopal Iyer	"_lance_mode",
1210dc2366Venugopal Iyer	NULL
12206673d9Garrett D'Amore};
1237c478bdstevel@tonic-gate
1247c478bdstevel@tonic-gatestatic	int	hme_lance_mode =	1;	/* to enable lance mode */
1257c478bdstevel@tonic-gatestatic	int	hme_ipg0 =		16;
1267c478bdstevel@tonic-gatestatic	int	hme_ipg1 =		8;
1277c478bdstevel@tonic-gatestatic	int	hme_ipg2 =		4;
1287c478bdstevel@tonic-gate
1297c478bdstevel@tonic-gate/*
1307c478bdstevel@tonic-gate * The following parameters may be configured by the user. If they are not
1317c478bdstevel@tonic-gate * configured by the user, the values will be based on the capabilities of
1327c478bdstevel@tonic-gate * the transceiver.
1337c478bdstevel@tonic-gate * The value "HME_NOTUSR" is ORed with the parameter value to indicate values
1347c478bdstevel@tonic-gate * which are NOT configured by the user.
1357c478bdstevel@tonic-gate */
1367c478bdstevel@tonic-gate
1377c478bdstevel@tonic-gate#define	HME_NOTUSR	0x0f000000
1387c478bdstevel@tonic-gate#define	HME_MASK_1BIT	0x1
1397c478bdstevel@tonic-gate#define	HME_MASK_5BIT	0x1f
1407c478bdstevel@tonic-gate#define	HME_MASK_8BIT	0xff
1417c478bdstevel@tonic-gate
1427c478bdstevel@tonic-gate/*
1437c478bdstevel@tonic-gate * All strings used by hme messaging functions
1447c478bdstevel@tonic-gate */
1457c478bdstevel@tonic-gate
1467c478bdstevel@tonic-gatestatic	char *no_xcvr_msg =
1477c478bdstevel@tonic-gate	"No transceiver found.";
1487c478bdstevel@tonic-gate
1497c478bdstevel@tonic-gatestatic	char *burst_size_msg =
1507c478bdstevel@tonic-gate	"Could not identify the burst size";
1517c478bdstevel@tonic-gate
1527c478bdstevel@tonic-gatestatic	char *unk_rx_ringsz_msg =
1537c478bdstevel@tonic-gate	"Unknown receive RINGSZ";
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gatestatic  char *add_intr_fail_msg =
1567c478bdstevel@tonic-gate	"ddi_add_intr(9F) failed";
1577c478bdstevel@tonic-gate
1587c478bdstevel@tonic-gatestatic  char *mregs_4global_reg_fail_msg =
1597c478bdstevel@tonic-gate	"ddi_regs_map_setup(9F) for global reg failed";
1607c478bdstevel@tonic-gate
1617c478bdstevel@tonic-gatestatic	char *mregs_4etx_reg_fail_msg =
1627c478bdstevel@tonic-gate	"ddi_map_regs for etx reg failed";
1637c478bdstevel@tonic-gate
1647c478bdstevel@tonic-gatestatic	char *mregs_4erx_reg_fail_msg =
1657c478bdstevel@tonic-gate	"ddi_map_regs for erx reg failed";
1667c478bdstevel@tonic-gate
1677c478bdstevel@tonic-gatestatic	char *mregs_4bmac_reg_fail_msg =
1687c478bdstevel@tonic-gate	"ddi_map_regs for bmac reg failed";
1697c478bdstevel@tonic-gate
1707c478bdstevel@tonic-gatestatic	char *mregs_4mif_reg_fail_msg =
1717c478bdstevel@tonic-gate	"ddi_map_regs for mif reg failed";
1727c478bdstevel@tonic-gate
1737c478bdstevel@tonic-gatestatic	char *init_fail_gen_msg =
1747c478bdstevel@tonic-gate	"Failed to initialize hardware/driver";
1757c478bdstevel@tonic-gate
1767c478bdstevel@tonic-gatestatic	char *ddi_nregs_fail_msg =
1777c478bdstevel@tonic-gate	"ddi_dev_nregs failed(9F), returned %d";
1787c478bdstevel@tonic-gate
1797c478bdstevel@tonic-gatestatic	char *bad_num_regs_msg =
1807c478bdstevel@tonic-gate	"Invalid number of registers.";
1817c478bdstevel@tonic-gate
1827c478bdstevel@tonic-gate
1837c478bdstevel@tonic-gate/* FATAL ERR msgs */
1847c478bdstevel@tonic-gate/*
1857c478bdstevel@tonic-gate * Function prototypes.
1867c478bdstevel@tonic-gate */
187f2cd0f0gd/* these two are global so that qfe can use them */
188f2cd0f0gdint hmeattach(dev_info_t *, ddi_attach_cmd_t);
189f2cd0f0gdint hmedetach(dev_info_t *, ddi_detach_cmd_t);
1900219346Garrett D'Amoreint hmequiesce(dev_info_t *);
19185025c0gdstatic	boolean_t hmeinit_xfer_params(struct hme *);
1927c478bdstevel@tonic-gatestatic	uint_t hmestop(struct hme *);
1937c478bdstevel@tonic-gatestatic	void hmestatinit(struct hme *);
1947c478bdstevel@tonic-gatestatic	int hmeallocthings(struct hme *);
1950219346Garrett D'Amorestatic	void hmefreethings(struct hme *);
1960219346Garrett D'Amorestatic	int hmeallocbuf(struct hme *, hmebuf_t *, int);
1970219346Garrett D'Amorestatic	int hmeallocbufs(struct hme *);
1987c478bdstevel@tonic-gatestatic	void hmefreebufs(struct hme *);
1997c478bdstevel@tonic-gatestatic	void hmeget_hm_rev_property(struct hme *);
20085025c0gdstatic	boolean_t hmestart(struct hme *, mblk_t *);
20185025c0gdstatic	uint_t hmeintr(caddr_t);
2027c478bdstevel@tonic-gatestatic	void hmereclaim(struct hme *);
2037c478bdstevel@tonic-gatestatic	int hmeinit(struct hme *);
2047c478bdstevel@tonic-gatestatic	void hmeuninit(struct hme *hmep);
2050219346Garrett D'Amorestatic 	mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t);
2067c478bdstevel@tonic-gatestatic	void hmesavecntrs(struct hme *);
2077c478bdstevel@tonic-gatestatic	void hme_fatal_err(struct hme *, uint_t);
2087c478bdstevel@tonic-gatestatic	void hme_nonfatal_err(struct hme *, uint_t);
2097c478bdstevel@tonic-gatestatic	int hmeburstsizes(struct hme *);
21006673d9Garrett D'Amorestatic	void send_bit(struct hme *, uint16_t);
21106673d9Garrett D'Amorestatic	uint16_t get_bit_std(uint8_t, struct hme *);
21206673d9Garrett D'Amorestatic	uint16_t hme_bb_mii_read(struct hme *, uint8_t, uint8_t);
21306673d9Garrett D'Amorestatic	void hme_bb_mii_write(struct hme *, uint8_t, uint8_t, uint16_t);
2147c478bdstevel@tonic-gatestatic	void hme_bb_force_idle(struct hme *);
21506673d9Garrett D'Amorestatic	uint16_t hme_mii_read(void *, uint8_t, uint8_t);
21606673d9Garrett D'Amorestatic	void hme_mii_write(void *, uint8_t, uint8_t, uint16_t);
2177c478bdstevel@tonic-gatestatic	void hme_setup_mac_address(struct hme *, dev_info_t *);
21806673d9Garrett D'Amorestatic	void hme_mii_notify(void *, link_state_t);
2197c478bdstevel@tonic-gate
2200219346Garrett D'Amorestatic void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...);
2217c478bdstevel@tonic-gate
2227c478bdstevel@tonic-gatestatic void hme_check_acc_handle(char *, uint_t, struct hme *,
22385025c0gd    ddi_acc_handle_t);
2247c478bdstevel@tonic-gate
22585025c0gd/*
22685025c0gd * Nemo (GLDv3) Functions.
22785025c0gd */
22885025c0gdstatic int	hme_m_stat(void *, uint_t, uint64_t *);
22985025c0gdstatic int	hme_m_start(void *);
23085025c0gdstatic void	hme_m_stop(void *);
23185025c0gdstatic int	hme_m_promisc(void *, boolean_t);
23285025c0gdstatic int	hme_m_multicst(void *, boolean_t, const uint8_t *);
23385025c0gdstatic int	hme_m_unicst(void *, const uint8_t *);
23485025c0gdstatic mblk_t	*hme_m_tx(void *, mblk_t *);
23585025c0gdstatic boolean_t	hme_m_getcapab(void *, mac_capab_t, void *);
2360dc2366Venugopal Iyerstatic int hme_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
2370dc2366Venugopal Iyerstatic void hme_m_propinfo(void *, const char *, mac_prop_id_t,
2380dc2366Venugopal Iyer    mac_prop_info_handle_t);
23906673d9Garrett D'Amorestatic int hme_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
24006673d9Garrett D'Amore    const void *);
24106673d9Garrett D'Amore
24206673d9Garrett D'Amorestatic mii_ops_t hme_mii_ops = {
24306673d9Garrett D'Amore	MII_OPS_VERSION,
24406673d9Garrett D'Amore	hme_mii_read,
24506673d9Garrett D'Amore	hme_mii_write,
24606673d9Garrett D'Amore	hme_mii_notify,
24706673d9Garrett D'Amore	NULL
24806673d9Garrett D'Amore};
24985025c0gd
25085025c0gdstatic mac_callbacks_t hme_m_callbacks = {
2510dc2366Venugopal Iyer	MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
25285025c0gd	hme_m_stat,
25385025c0gd	hme_m_start,
25485025c0gd	hme_m_stop,
25585025c0gd	hme_m_promisc,
25685025c0gd	hme_m_multicst,
25785025c0gd	hme_m_unicst,
25885025c0gd	hme_m_tx,
25906673d9Garrett D'Amore	NULL,
2600dc2366Venugopal Iyer	NULL,
26185025c0gd	hme_m_getcapab,
26206673d9Garrett D'Amore	NULL,
26306673d9Garrett D'Amore	NULL,
26406673d9Garrett D'Amore	hme_m_setprop,
26506673d9Garrett D'Amore	hme_m_getprop,
2660dc2366Venugopal Iyer	hme_m_propinfo
26785025c0gd};
26885025c0gd
26985025c0gdDDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach,
2700219346Garrett D'Amore    nodev, NULL, D_MP, NULL, hmequiesce);
2717c478bdstevel@tonic-gate
2727c478bdstevel@tonic-gate#define	HME_FAULT_MSG1(p, s, t, f) \
2730219346Garrett D'Amore    hme_fault_msg((p), (s), (t), (f));
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate#define	HME_FAULT_MSG2(p, s, t, f, a) \
2760219346Garrett D'Amore    hme_fault_msg((p), (s), (t), (f), (a));
2777c478bdstevel@tonic-gate
2787c478bdstevel@tonic-gate#define	HME_FAULT_MSG3(p, s, t, f, a, b) \
2790219346Garrett D'Amore    hme_fault_msg((p), (s), (t), (f), (a), (b));
2807c478bdstevel@tonic-gate
2817c478bdstevel@tonic-gate#define	HME_FAULT_MSG4(p, s, t, f, a, b, c) \
2820219346Garrett D'Amore    hme_fault_msg((p), (s), (t), (f), (a), (b), (c));
2837c478bdstevel@tonic-gate
2847c478bdstevel@tonic-gate#define	CHECK_MIFREG() \
2857c478bdstevel@tonic-gate	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh)
2867c478bdstevel@tonic-gate#define	CHECK_ETXREG() \
2877c478bdstevel@tonic-gate	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh)
2887c478bdstevel@tonic-gate#define	CHECK_ERXREG() \
2897c478bdstevel@tonic-gate	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh)
2907c478bdstevel@tonic-gate#define	CHECK_MACREG() \
2917c478bdstevel@tonic-gate	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh)
2927c478bdstevel@tonic-gate#define	CHECK_GLOBREG() \
2937c478bdstevel@tonic-gate	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh)
2947c478bdstevel@tonic-gate
2957c478bdstevel@tonic-gate/*
2967c478bdstevel@tonic-gate * Claim the device is ultra-capable of burst in the beginning.  Use
2977c478bdstevel@tonic-gate * the value returned by ddi_dma_burstsizes() to actually set the HME
2987c478bdstevel@tonic-gate * global configuration register later.
2997c478bdstevel@tonic-gate *
3007c478bdstevel@tonic-gate * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports
3017c478bdstevel@tonic-gate * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains
3027c478bdstevel@tonic-gate * the the burstsizes in both the lo and hi words.
3037c478bdstevel@tonic-gate */
3047c478bdstevel@tonic-gate#define	HMELIMADDRLO	((uint64_t)0x00000000)
3057c478bdstevel@tonic-gate#define	HMELIMADDRHI	((uint64_t)0xffffffff)
3067c478bdstevel@tonic-gate
3070219346Garrett D'Amore/*
3080219346Garrett D'Amore * Note that rx and tx data buffers can be arbitrarily aligned, but
3090219346Garrett D'Amore * that the descriptor rings need to be aligned on 2K boundaries, per
3100219346Garrett D'Amore * the spec.
3110219346Garrett D'Amore */
3127c478bdstevel@tonic-gatestatic ddi_dma_attr_t hme_dma_attr = {
3137c478bdstevel@tonic-gate	DMA_ATTR_V0,		/* version number. */
3147c478bdstevel@tonic-gate	(uint64_t)HMELIMADDRLO,	/* low address */
3157c478bdstevel@tonic-gate	(uint64_t)HMELIMADDRHI,	/* high address */
3167c478bdstevel@tonic-gate	(uint64_t)0x00ffffff,	/* address counter max */
3170219346Garrett D'Amore	(uint64_t)HME_HMDALIGN,	/* alignment */
3187c478bdstevel@tonic-gate	(uint_t)0x00700070,	/* dlim_burstsizes for 32 and 64 bit xfers */
3197c478bdstevel@tonic-gate	(uint32_t)0x1,		/* minimum transfer size */
3207c478bdstevel@tonic-gate	(uint64_t)0x7fffffff,	/* maximum transfer size */
3217c478bdstevel@tonic-gate	(uint64_t)0x00ffffff,	/* maximum segment size */
3227c478bdstevel@tonic-gate	1,			/* scatter/gather list length */
3237c478bdstevel@tonic-gate	512,			/* granularity */
3247c478bdstevel@tonic-gate	0			/* attribute flags */
3257c478bdstevel@tonic-gate};
3267c478bdstevel@tonic-gate
3270219346Garrett D'Amorestatic ddi_device_acc_attr_t hme_buf_attr = {
3280219346Garrett D'Amore	DDI_DEVICE_ATTR_V0,
3290219346Garrett D'Amore	DDI_NEVERSWAP_ACC,
3300219346Garrett D'Amore	DDI_STRICTORDER_ACC,	/* probably could allow merging & caching */
3310219346Garrett D'Amore	DDI_DEFAULT_ACC,
3327c478bdstevel@tonic-gate};
3337c478bdstevel@tonic-gate
3347c478bdstevel@tonic-gatestatic uchar_t pci_latency_timer = 0;
3357c478bdstevel@tonic-gate
3367c478bdstevel@tonic-gate/*
3377c478bdstevel@tonic-gate * Module linkage information for the kernel.
3387c478bdstevel@tonic-gate */
3397c478bdstevel@tonic-gatestatic struct modldrv modldrv = {
3407c478bdstevel@tonic-gate	&mod_driverops,	/* Type of module.  This one is a driver */
34185025c0gd	"Sun HME 10/100 Mb Ethernet",
34285025c0gd	&hme_dev_ops,	/* driver ops */
3437c478bdstevel@tonic-gate};
3447c478bdstevel@tonic-gate
3457c478bdstevel@tonic-gatestatic struct modlinkage modlinkage = {
3467c478bdstevel@tonic-gate	MODREV_1, &modldrv, NULL
3477c478bdstevel@tonic-gate};
3487c478bdstevel@tonic-gate
3497c478bdstevel@tonic-gate/* <<<<<<<<<<<<<<<<<<<<<<  Register operations >>>>>>>>>>>>>>>>>>>>> */
3507c478bdstevel@tonic-gate
3517c478bdstevel@tonic-gate#define	GET_MIFREG(reg) \
3527c478bdstevel@tonic-gate	ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg)
3537c478bdstevel@tonic-gate#define	PUT_MIFREG(reg, value) \
3547c478bdstevel@tonic-gate	ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value)
3557c478bdstevel@tonic-gate
3567c478bdstevel@tonic-gate#define	GET_ETXREG(reg) \
3577c478bdstevel@tonic-gate	ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg)
3587c478bdstevel@tonic-gate#define	PUT_ETXREG(reg, value) \
3597c478bdstevel@tonic-gate	ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value)
3607c478bdstevel@tonic-gate#define	GET_ERXREG(reg) \
3617c478bdstevel@tonic-gate	ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg)
3627c478bdstevel@tonic-gate#define	PUT_ERXREG(reg, value) \
3637c478bdstevel@tonic-gate	ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value)
3647c478bdstevel@tonic-gate#define	GET_MACREG(reg) \
3657c478bdstevel@tonic-gate	ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg)
3667c478bdstevel@tonic-gate#define	PUT_MACREG(reg, value) \
3677c478bdstevel@tonic-gate	ddi_put32(hmep->hme_bmacregh, \
3687c478bdstevel@tonic-gate		(uint32_t *)&hmep->hme_bmacregp->reg, value)
3697c478bdstevel@tonic-gate#define	GET_GLOBREG(reg) \
3707c478bdstevel@tonic-gate	ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg)
3717c478bdstevel@tonic-gate#define	PUT_GLOBREG(reg, value) \
3727c478bdstevel@tonic-gate	ddi_put32(hmep->hme_globregh, \
3737c478bdstevel@tonic-gate		(uint32_t *)&hmep->hme_globregp->reg, value)
3740219346Garrett D'Amore#define	PUT_TMD(ptr, paddr, len, flags)					\
3750219346Garrett D'Amore	ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \
3760219346Garrett D'Amore	ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags,	\
3770219346Garrett D'Amore	    len | flags)
3780219346Garrett D'Amore#define	GET_TMD_FLAGS(ptr)					\
3790219346Garrett D'Amore	ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags)
3800219346Garrett D'Amore#define	PUT_RMD(ptr, paddr) \
3810219346Garrett D'Amore	ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \
3820219346Garrett D'Amore	ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags,	\
3830219346Garrett D'Amore	    (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN)
3840219346Garrett D'Amore#define	GET_RMD_FLAGS(ptr)					\
3850219346Garrett D'Amore	ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags)
3860219346Garrett D'Amore
3877c478bdstevel@tonic-gate#define	GET_ROM8(offset) \
3887c478bdstevel@tonic-gate	ddi_get8((hmep->hme_romh), (offset))
3897c478bdstevel@tonic-gate
3907c478bdstevel@tonic-gate/*
3917c478bdstevel@tonic-gate * Ether_copy is not endian-correct. Define an endian-correct version.
3927c478bdstevel@tonic-gate */
3937c478bdstevel@tonic-gate#define	ether_bcopy(a, b) (bcopy(a, b, 6))
3947c478bdstevel@tonic-gate
3957c478bdstevel@tonic-gate/*
3967c478bdstevel@tonic-gate * Ether-type is specifically big-endian, but data region is unknown endian
3977c478bdstevel@tonic-gate */
39885025c0gd#define	get_ether_type(ptr) \
39985025c0gd	(((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13])))
4007c478bdstevel@tonic-gate
4017c478bdstevel@tonic-gate/* <<<<<<<<<<<<<<<<<<<<<<  Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */
4027c478bdstevel@tonic-gate
4037c478bdstevel@tonic-gate#define	BMAC_DEFAULT_JAMSIZE	(0x04)		/* jamsize equals 4 */
4047c478bdstevel@tonic-gate#define	BMAC_LONG_JAMSIZE	(0x10)		/* jamsize equals 0x10 */
4057c478bdstevel@tonic-gatestatic	int 	jamsize = BMAC_DEFAULT_JAMSIZE;
4067c478bdstevel@tonic-gate
4077c478bdstevel@tonic-gate
4087c478bdstevel@tonic-gate/*
4097c478bdstevel@tonic-gate * Calculate the bit in the multicast address filter that selects the given
4107c478bdstevel@tonic-gate * address.
4117c478bdstevel@tonic-gate */
4127c478bdstevel@tonic-gate
4137c478bdstevel@tonic-gatestatic uint32_t
41485025c0gdhmeladrf_bit(const uint8_t *addr)
4157c478bdstevel@tonic-gate{
4167c478bdstevel@tonic-gate	uint32_t crc;
4177c478bdstevel@tonic-gate
4187c478bdstevel@tonic-gate	CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
4197c478bdstevel@tonic-gate
4207c478bdstevel@tonic-gate	/*
4217c478bdstevel@tonic-gate	 * Just want the 6 most significant bits.
4227c478bdstevel@tonic-gate	 */
4237c478bdstevel@tonic-gate	return (crc >> 26);
4247c478bdstevel@tonic-gate}
4257c478bdstevel@tonic-gate
4267c478bdstevel@tonic-gate/* <<<<<<<<<<<<<<<<<<<<<<<<  Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
4277c478bdstevel@tonic-gate
4287c478bdstevel@tonic-gatestatic void
42906673d9Garrett D'Amoresend_bit(struct hme *hmep, uint16_t x)
4307c478bdstevel@tonic-gate{
4317c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbdata, x);
4327c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
4337c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
4347c478bdstevel@tonic-gate}
4357c478bdstevel@tonic-gate
4367c478bdstevel@tonic-gate
4377c478bdstevel@tonic-gate/*
4387c478bdstevel@tonic-gate * To read the MII register bits according to the IEEE Standard
4397c478bdstevel@tonic-gate */
44006673d9Garrett D'Amorestatic uint16_t
44106673d9Garrett D'Amoreget_bit_std(uint8_t phyad, struct hme *hmep)
4427c478bdstevel@tonic-gate{
44306673d9Garrett D'Amore	uint16_t	x;
4447c478bdstevel@tonic-gate
4457c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
4467c478bdstevel@tonic-gate	drv_usecwait(1);	/* wait for  >330 ns for stable data */
44706673d9Garrett D'Amore	if (phyad == HME_INTERNAL_PHYAD)
4487c478bdstevel@tonic-gate		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0;
4497c478bdstevel@tonic-gate	else
4507c478bdstevel@tonic-gate		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0;
4517c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
4527c478bdstevel@tonic-gate	return (x);
4537c478bdstevel@tonic-gate}
4547c478bdstevel@tonic-gate
4557c478bdstevel@tonic-gate#define	SEND_BIT(x)		send_bit(hmep, x)
45606673d9Garrett D'Amore#define	GET_BIT_STD(phyad, x)	x = get_bit_std(phyad, hmep)
4577c478bdstevel@tonic-gate
4587c478bdstevel@tonic-gate
4597c478bdstevel@tonic-gatestatic void
46006673d9Garrett D'Amorehme_bb_mii_write(struct hme *hmep, uint8_t phyad, uint8_t regad, uint16_t data)
4617c478bdstevel@tonic-gate{
4627c478bdstevel@tonic-gate	int	i;
4637c478bdstevel@tonic-gate
4647c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
4657c478bdstevel@tonic-gate	(void) hme_bb_force_idle(hmep);
4667c478bdstevel@tonic-gate	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
4677c478bdstevel@tonic-gate	SEND_BIT(0); SEND_BIT(1);	/* <OP> */
4687c478bdstevel@tonic-gate
4697c478bdstevel@tonic-gate	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
4707c478bdstevel@tonic-gate		SEND_BIT((phyad >> i) & 1);
4717c478bdstevel@tonic-gate	}
4727c478bdstevel@tonic-gate
4737c478bdstevel@tonic-gate	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
4747c478bdstevel@tonic-gate		SEND_BIT((regad >> i) & 1);
4757c478bdstevel@tonic-gate	}
4767c478bdstevel@tonic-gate
4777c478bdstevel@tonic-gate	SEND_BIT(1); SEND_BIT(0);	/* <TA> */
4787c478bdstevel@tonic-gate
4797c478bdstevel@tonic-gate	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
4807c478bdstevel@tonic-gate		SEND_BIT((data >> i) & 1);
4817c478bdstevel@tonic-gate	}
4827c478bdstevel@tonic-gate
4837c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
4847c478bdstevel@tonic-gate	CHECK_MIFREG();
4857c478bdstevel@tonic-gate}
4867c478bdstevel@tonic-gate
4877c478bdstevel@tonic-gate/* Return 0 if OK, 1 if error (Transceiver does not talk management) */
48806673d9Garrett D'Amorestatic uint16_t
48906673d9Garrett D'Amorehme_bb_mii_read(struct hme *hmep, uint8_t phyad, uint8_t regad)
4907c478bdstevel@tonic-gate{
4917c478bdstevel@tonic-gate	int		i;
4927c478bdstevel@tonic-gate	uint32_t	x;
49306673d9Garrett D'Amore	uint16_t	data = 0;
4947c478bdstevel@tonic-gate
4957c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
4967c478bdstevel@tonic-gate	(void) hme_bb_force_idle(hmep);
4977c478bdstevel@tonic-gate	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
4987c478bdstevel@tonic-gate	SEND_BIT(1); SEND_BIT(0);	/* <OP> */
4997c478bdstevel@tonic-gate	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
5007c478bdstevel@tonic-gate		SEND_BIT((phyad >> i) & 1);
5017c478bdstevel@tonic-gate	}
5027c478bdstevel@tonic-gate	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
5037c478bdstevel@tonic-gate		SEND_BIT((regad >> i) & 1);
5047c478bdstevel@tonic-gate	}
5057c478bdstevel@tonic-gate
5067c478bdstevel@tonic-gate	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
5077c478bdstevel@tonic-gate
50806673d9Garrett D'Amore	GET_BIT_STD(phyad, x);
50906673d9Garrett D'Amore	GET_BIT_STD(phyad, x);		/* <TA> */
51006673d9Garrett D'Amore	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
51106673d9Garrett D'Amore		GET_BIT_STD(phyad, x);
51206673d9Garrett D'Amore		data += (x << i);
5137c478bdstevel@tonic-gate	}
51406673d9Garrett D'Amore	/*
51506673d9Garrett D'Amore	 * Kludge to get the Transceiver out of hung mode
51606673d9Garrett D'Amore	 */
51706673d9Garrett D'Amore	GET_BIT_STD(phyad, x);
51806673d9Garrett D'Amore	GET_BIT_STD(phyad, x);
51906673d9Garrett D'Amore	GET_BIT_STD(phyad, x);
5207c478bdstevel@tonic-gate	CHECK_MIFREG();
52106673d9Garrett D'Amore	return (data);
5227c478bdstevel@tonic-gate}
5237c478bdstevel@tonic-gate
5247c478bdstevel@tonic-gate
5257c478bdstevel@tonic-gatestatic void
5267c478bdstevel@tonic-gatehme_bb_force_idle(struct hme *hmep)
5277c478bdstevel@tonic-gate{
5287c478bdstevel@tonic-gate	int	i;
5297c478bdstevel@tonic-gate
5307c478bdstevel@tonic-gate	for (i = 0; i < 33; i++) {
5317c478bdstevel@tonic-gate		SEND_BIT(1);
5327c478bdstevel@tonic-gate	}
5337c478bdstevel@tonic-gate}
5347c478bdstevel@tonic-gate
5357c478bdstevel@tonic-gate/* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
5367c478bdstevel@tonic-gate
5377c478bdstevel@tonic-gate
5387c478bdstevel@tonic-gate/* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
5397c478bdstevel@tonic-gate
5407c478bdstevel@tonic-gate/* Return 0 if OK, 1 if error (Transceiver does not talk management) */
54106673d9Garrett D'Amorestatic uint16_t
54206673d9Garrett D'Amorehme_mii_read(void *arg, uint8_t phyad, uint8_t regad)
5437c478bdstevel@tonic-gate{
54406673d9Garrett D'Amore	struct hme	*hmep = arg;
5457c478bdstevel@tonic-gate	uint32_t	frame;
546e8717caGarrett D'Amore	uint32_t	tmp_mif;
547e8717caGarrett D'Amore	uint32_t	tmp_xif;
5487c478bdstevel@tonic-gate
549e8717caGarrett D'Amore	tmp_mif = GET_MIFREG(mif_cfg);
550e8717caGarrett D'Amore	tmp_xif = GET_MACREG(xifc);
551e8717caGarrett D'Amore
552e8717caGarrett D'Amore	switch (phyad) {
553e8717caGarrett D'Amore	case HME_EXTERNAL_PHYAD:
554e8717caGarrett D'Amore		PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
555e8717caGarrett D'Amore		PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
556e8717caGarrett D'Amore		break;
557e8717caGarrett D'Amore	case HME_INTERNAL_PHYAD:
558e8717caGarrett D'Amore		PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
559e8717caGarrett D'Amore		PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
560e8717caGarrett D'Amore		break;
561e8717caGarrett D'Amore	default:
562e8717caGarrett D'Amore		return (0xffff);
563e8717caGarrett D'Amore	}
564e8717caGarrett D'Amore
565e8717caGarrett D'Amore	if (!hmep->hme_frame_enable) {
566e8717caGarrett D'Amore		frame = (hme_bb_mii_read(hmep, phyad, regad));
567e8717caGarrett D'Amore		PUT_MACREG(xifc, tmp_xif);
568e8717caGarrett D'Amore		PUT_MIFREG(mif_cfg, tmp_mif);
569e8717caGarrett D'Amore		return (frame & 0xffff);
570e8717caGarrett D'Amore	}
5717c478bdstevel@tonic-gate
5720219346Garrett D'Amore	PUT_MIFREG(mif_frame,
5730219346Garrett D'Amore	    HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) |
5740219346Garrett D'Amore	    (regad << HME_MIF_FRREGAD_SHIFT));
5757c478bdstevel@tonic-gate/*
5767c478bdstevel@tonic-gate *	HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
5777c478bdstevel@tonic-gate */
5780219346Garrett D'Amore	HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
5790219346Garrett D'Amore	frame = GET_MIFREG(mif_frame);
5807c478bdstevel@tonic-gate	CHECK_MIFREG();
581e8717caGarrett D'Amore
582e8717caGarrett D'Amore	PUT_MACREG(xifc, tmp_xif);
583e8717caGarrett D'Amore	PUT_MIFREG(mif_cfg, tmp_mif);
584e8717caGarrett D'Amore
5857c478bdstevel@tonic-gate	if ((frame & HME_MIF_FRTA0) == 0) {
5867c478bdstevel@tonic-gate
5877c478bdstevel@tonic-gate
58806673d9Garrett D'Amore		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, MII_MSG,
5890219346Garrett D'Amore		    "MIF Read failure");
59006673d9Garrett D'Amore		return (0xffff);
5917c478bdstevel@tonic-gate	}
59206673d9Garrett D'Amore	return ((uint16_t)(frame & HME_MIF_FRDATA));
5937c478bdstevel@tonic-gate}
5947c478bdstevel@tonic-gate
5957c478bdstevel@tonic-gatestatic void
59606673d9Garrett D'Amorehme_mii_write(void *arg, uint8_t phyad, uint8_t regad, uint16_t data)
5977c478bdstevel@tonic-gate{
59806673d9Garrett D'Amore	struct hme *hmep = arg;
5997c478bdstevel@tonic-gate	uint32_t frame;
600e8717caGarrett D'Amore	uint32_t tmp_mif;
601e8717caGarrett D'Amore	uint32_t tmp_xif;
602e8717caGarrett D'Amore
603e8717caGarrett D'Amore	tmp_mif = GET_MIFREG(mif_cfg);
604e8717caGarrett D'Amore	tmp_xif = GET_MACREG(xifc);
605e8717caGarrett D'Amore
606e8717caGarrett D'Amore	switch (phyad) {
607e8717caGarrett D'Amore	case HME_EXTERNAL_PHYAD:
608e8717caGarrett D'Amore		PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
609e8717caGarrett D'Amore		PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
610e8717caGarrett D'Amore		break;
611e8717caGarrett D'Amore	case HME_INTERNAL_PHYAD:
612e8717caGarrett D'Amore		PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
613e8717caGarrett D'Amore		PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
614e8717caGarrett D'Amore		break;
615e8717caGarrett D'Amore	default:
616e8717caGarrett D'Amore		return;
617e8717caGarrett D'Amore	}
6187c478bdstevel@tonic-gate
6197c478bdstevel@tonic-gate	if (!hmep->hme_frame_enable) {
62006673d9Garrett D'Amore		hme_bb_mii_write(hmep, phyad, regad, data);
621e8717caGarrett D'Amore		PUT_MACREG(xifc, tmp_xif);
622e8717caGarrett D'Amore		PUT_MIFREG(mif_cfg, tmp_mif);
6237c478bdstevel@tonic-gate		return;
6247c478bdstevel@tonic-gate	}
6257c478bdstevel@tonic-gate
6260219346Garrett D'Amore	PUT_MIFREG(mif_frame,
6270219346Garrett D'Amore	    HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) |
6280219346Garrett D'Amore	    (regad << HME_MIF_FRREGAD_SHIFT) | data);
6297c478bdstevel@tonic-gate/*
6307c478bdstevel@tonic-gate *	HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
6317c478bdstevel@tonic-gate */
6320219346Garrett D'Amore	HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
6330219346Garrett D'Amore	frame = GET_MIFREG(mif_frame);
634e8717caGarrett D'Amore	PUT_MACREG(xifc, tmp_xif);
635e8717caGarrett D'Amore	PUT_MIFREG(mif_cfg, tmp_mif);
6367c478bdstevel@tonic-gate	CHECK_MIFREG();
6377c478bdstevel@tonic-gate	if ((frame & HME_MIF_FRTA0) == 0) {
63806673d9Garrett D'Amore		HME_FAULT_MSG1(hmep, SEVERITY_MID, MII_MSG,
6390219346Garrett D'Amore		    "MIF Write failure");
6407c478bdstevel@tonic-gate	}
6417c478bdstevel@tonic-gate}
6427c478bdstevel@tonic-gate
6437c478bdstevel@tonic-gatestatic void
64406673d9Garrett D'Amorehme_mii_notify(void *arg, link_state_t link)
6457c478bdstevel@tonic-gate{
6467c478bdstevel@tonic-gate	struct hme *hmep = arg;
6477c478bdstevel@tonic-gate
64806673d9Garrett D'Amore	if (link == LINK_STATE_UP) {
64906673d9Garrett D'Amore		(void) hmeinit(hmep);
6507c478bdstevel@tonic-gate	}
65106673d9Garrett D'Amore	mac_link_update(hmep->hme_mh, link);
6527c478bdstevel@tonic-gate}
6537c478bdstevel@tonic-gate
6547c478bdstevel@tonic-gate/* <<<<<<<<<<<<<<<<<<<<<<<<<<<  LOADABLE ENTRIES  >>>>>>>>>>>>>>>>>>>>>>> */
6557c478bdstevel@tonic-gate
6567c478bdstevel@tonic-gateint
6577c478bdstevel@tonic-gate_init(void)
6587c478bdstevel@tonic-gate{
6597c478bdstevel@tonic-gate	int	status;
6607c478bdstevel@tonic-gate
66185025c0gd	mac_init_ops(&hme_dev_ops, "hme");
66285025c0gd	if ((status = mod_install(&modlinkage)) != 0) {
66385025c0gd		mac_fini_ops(&hme_dev_ops);
6647c478bdstevel@tonic-gate	}
6657c478bdstevel@tonic-gate	return (status);
6667c478bdstevel@tonic-gate}
6677c478bdstevel@tonic-gate
6687c478bdstevel@tonic-gateint
6697c478bdstevel@tonic-gate_fini(void)
6707c478bdstevel@tonic-gate{
6717c478bdstevel@tonic-gate	int	status;
6727c478bdstevel@tonic-gate
67385025c0gd	if ((status = mod_remove(&modlinkage)) == 0) {
67485025c0gd		mac_fini_ops(&hme_dev_ops);
6757c478bdstevel@tonic-gate	}
6767c478bdstevel@tonic-gate	return (status);
6777c478bdstevel@tonic-gate}
6787c478bdstevel@tonic-gate
6797c478bdstevel@tonic-gateint
6807c478bdstevel@tonic-gate_info(struct modinfo *modinfop)
6817c478bdstevel@tonic-gate{
6827c478bdstevel@tonic-gate	return (mod_info(&modlinkage, modinfop));
6837c478bdstevel@tonic-gate}
6847c478bdstevel@tonic-gate
6857c478bdstevel@tonic-gate/*
6867c478bdstevel@tonic-gate * ddi_dma_sync() a TMD or RMD descriptor.
6877c478bdstevel@tonic-gate */
6880219346Garrett D'Amore#define	HMESYNCRMD(num, who)				\
6890219346Garrett D'Amore	(void) ddi_dma_sync(hmep->hme_rmd_dmah,		\
6900219346Garrett D'Amore	    (num * sizeof (struct hme_rmd)),		\
6910219346Garrett D'Amore	    sizeof (struct hme_rmd),			\
6920219346Garrett D'Amore	    who)
6930219346Garrett D'Amore
6940219346Garrett D'Amore#define	HMESYNCTMD(num, who)				\
6950219346Garrett D'Amore	(void) ddi_dma_sync(hmep->hme_tmd_dmah,		\
6960219346Garrett D'Amore	    (num * sizeof (struct hme_tmd)),		\
6970219346Garrett D'Amore	    sizeof (struct hme_tmd),			\
6980219346Garrett D'Amore	    who)
6997c478bdstevel@tonic-gate
7007c478bdstevel@tonic-gate/*
7017c478bdstevel@tonic-gate * Ethernet broadcast address definition.
7027c478bdstevel@tonic-gate */
7037c478bdstevel@tonic-gatestatic	struct ether_addr	etherbroadcastaddr = {
7047c478bdstevel@tonic-gate	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
7057c478bdstevel@tonic-gate};
7067c478bdstevel@tonic-gate
7077c478bdstevel@tonic-gate/*
7087c478bdstevel@tonic-gate * MIB II broadcast/multicast packets
7097c478bdstevel@tonic-gate */
71085025c0gd#define	IS_BROADCAST(pkt) (bcmp(pkt, &etherbroadcastaddr, ETHERADDRL) == 0)
71185025c0gd#define	IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
71285025c0gd#define	BUMP_InNUcast(hmep, pkt) \
7130219346Garrett D'Amore	if (IS_MULTICAST(pkt)) {			       \
7140219346Garrett D'Amore		if (IS_BROADCAST(pkt)) {		       \
7150219346Garrett D'Amore			hmep->hme_brdcstrcv++;		       \
7160219346Garrett D'Amore		} else {				       \
7170219346Garrett D'Amore			hmep->hme_multircv++;		       \
7180219346Garrett D'Amore		}					       \
7190219346Garrett D'Amore	}
72085025c0gd#define	BUMP_OutNUcast(hmep, pkt) \
7210219346Garrett D'Amore	if (IS_MULTICAST(pkt)) {			       \
7220219346Garrett D'Amore		if (IS_BROADCAST(pkt)) {		       \
7230219346Garrett D'Amore			hmep->hme_brdcstxmt++;		       \
7240219346Garrett D'Amore		} else {				       \
7250219346Garrett D'Amore			hmep->hme_multixmt++;		       \
7260219346Garrett D'Amore		}					       \
7270219346Garrett D'Amore	}
7287c478bdstevel@tonic-gate
7297c478bdstevel@tonic-gatestatic int
7307c478bdstevel@tonic-gatehme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr)
7317c478bdstevel@tonic-gate{
7327c478bdstevel@tonic-gate	char propstr[80];
7337c478bdstevel@tonic-gate	int i, needprop = 0;
7347c478bdstevel@tonic-gate	struct ether_addr local_mac;
7357c478bdstevel@tonic-gate
7367c478bdstevel@tonic-gate	if (strcmp(vpdname, "NA") == 0) {
7377c478bdstevel@tonic-gate		(void) strcpy(propstr, "local-mac-address");
7387c478bdstevel@tonic-gate		needprop = 1;
7397c478bdstevel@tonic-gate	} else if (strcmp(vpdname, "Z0") == 0) {
7407c478bdstevel@tonic-gate		(void) strcpy(propstr, "model");
7417c478bdstevel@tonic-gate		needprop = 1;
7427c478bdstevel@tonic-gate	} else if (strcmp(vpdname, "Z1") == 0) {
7437c478bdstevel@tonic-gate		(void) strcpy(propstr, "board-model");
7447c478bdstevel@tonic-gate		needprop = 1;
7457c478bdstevel@tonic-gate	}
7467c478bdstevel@tonic-gate
7477c478bdstevel@tonic-gate	if (needprop == 1) {
7480219346Garrett D'Amore
7497c478bdstevel@tonic-gate		if (strcmp(propstr, "local-mac-address") == 0) {
7507c478bdstevel@tonic-gate			for (i = 0; i < ETHERADDRL; i++)
7517c478bdstevel@tonic-gate				local_mac.ether_addr_octet[i] =
75285025c0gd				    (uchar_t)vpdstr[i];
7537c478bdstevel@tonic-gate			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
75485025c0gd			    DDI_PROP_CANSLEEP, propstr,
75585025c0gd			    (char *)local_mac.ether_addr_octet, ETHERADDRL)
75685025c0gd			    != DDI_SUCCESS) {
7577c478bdstevel@tonic-gate				return (DDI_FAILURE);
7587c478bdstevel@tonic-gate			}
7597c478bdstevel@tonic-gate		} else {
7607c478bdstevel@tonic-gate			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
76185025c0gd			    DDI_PROP_CANSLEEP, propstr, vpdstr,
76285025c0gd			    strlen(vpdstr)+1) != DDI_SUCCESS) {
7637c478bdstevel@tonic-gate				return (DDI_FAILURE);
7647c478bdstevel@tonic-gate			}
7657c478bdstevel@tonic-gate		}
7667c478bdstevel@tonic-gate	}
7677c478bdstevel@tonic-gate	return (0);
7687c478bdstevel@tonic-gate}
7697c478bdstevel@tonic-gate
7707c478bdstevel@tonic-gate/*
7717c478bdstevel@tonic-gate * Get properties from old VPD
7727c478bdstevel@tonic-gate * for PCI cards
7737c478bdstevel@tonic-gate */
7747c478bdstevel@tonic-gatestatic int
7757c478bdstevel@tonic-gatehme_get_oldvpd_props(dev_info_t *dip, int vpd_base)
7767c478bdstevel@tonic-gate{
7777c478bdstevel@tonic-gate	struct hme *hmep;
7787c478bdstevel@tonic-gate	int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
7797c478bdstevel@tonic-gate	char kw_namestr[3];
7807c478bdstevel@tonic-gate	char kw_fieldstr[256];
7817c478bdstevel@tonic-gate	int i;
7827c478bdstevel@tonic-gate
7837c478bdstevel@tonic-gate	hmep = ddi_get_driver_private(dip);
7847c478bdstevel@tonic-gate
7857c478bdstevel@tonic-gate	vpd_start = vpd_base;
7867c478bdstevel@tonic-gate
7877c478bdstevel@tonic-gate	if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
7887c478bdstevel@tonic-gate		return (1); /* error */
7897c478bdstevel@tonic-gate	} else {
7907c478bdstevel@tonic-gate		vpd_len = 9;
7917c478bdstevel@tonic-gate	}
7927c478bdstevel@tonic-gate
7937c478bdstevel@tonic-gate	/* Get local-mac-address */
7947c478bdstevel@tonic-gate	kw_start = vpd_start + 3; /* Location of 1st keyword */
7957c478bdstevel@tonic-gate	kw_ptr = kw_start;
7967c478bdstevel@tonic-gate	while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
7977c478bdstevel@tonic-gate		kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
7987c478bdstevel@tonic-gate		kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
7997c478bdstevel@tonic-gate		kw_namestr[2] = '\0';
8007c478bdstevel@tonic-gate		kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
8017c478bdstevel@tonic-gate		for (i = 0, kw_ptr += 3; i < kw_len; i++)
8027c478bdstevel@tonic-gate			kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
8037c478bdstevel@tonic-gate		kw_fieldstr[i] = '\0';
8047c478bdstevel@tonic-gate		if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) {
8057c478bdstevel@tonic-gate			return (DDI_FAILURE);
8067c478bdstevel@tonic-gate		}
8077c478bdstevel@tonic-gate		kw_ptr += kw_len;
8087c478bdstevel@tonic-gate	} /* next keyword */
8097c478bdstevel@tonic-gate
81085025c0gd	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model",
81185025c0gd	    "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) {
8127c478bdstevel@tonic-gate		return (DDI_FAILURE);
8137c478bdstevel@tonic-gate	}
8147c478bdstevel@tonic-gate	return (0);
8157c478bdstevel@tonic-gate}
8167c478bdstevel@tonic-gate
8177c478bdstevel@tonic-gate
8187c478bdstevel@tonic-gate/*
8197c478bdstevel@tonic-gate * Get properties from new VPD
8207c478bdstevel@tonic-gate * for CompactPCI cards
8217c478bdstevel@tonic-gate */
8227c478bdstevel@tonic-gatestatic int
8237c478bdstevel@tonic-gatehme_get_newvpd_props(dev_info_t *dip, int vpd_base)
8247c478bdstevel@tonic-gate{
8257c478bdstevel@tonic-gate	struct hme *hmep;
8267c478bdstevel@tonic-gate	int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
8277c478bdstevel@tonic-gate	char kw_namestr[3];
8287c478bdstevel@tonic-gate	char kw_fieldstr[256];
8297c478bdstevel@tonic-gate	int maxvpdsize, i;
8307c478bdstevel@tonic-gate
8317c478bdstevel@tonic-gate	hmep = ddi_get_driver_private(dip);
8327c478bdstevel@tonic-gate
8337c478bdstevel@tonic-gate	maxvpdsize = 1024; /* Real size not known until after it is read */
8347c478bdstevel@tonic-gate
8357c478bdstevel@tonic-gate	vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) |
83685025c0gd	    ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3;
8377c478bdstevel@tonic-gate	vpd_start = vpd_base + vpd_start;
8387c478bdstevel@tonic-gate	while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */
8397c478bdstevel@tonic-gate		if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
8407c478bdstevel@tonic-gate			break; /* no VPD found */
8417c478bdstevel@tonic-gate		} else {
8427c478bdstevel@tonic-gate			vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start
84385025c0gd			    + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start
84485025c0gd			    + 2]) & 0xff) << 8);
8457c478bdstevel@tonic-gate		}
8467c478bdstevel@tonic-gate		/* Get all keywords in this VPD */
8477c478bdstevel@tonic-gate		kw_start = vpd_start + 3; /* Location of 1st keyword */
8487c478bdstevel@tonic-gate		kw_ptr = kw_start;
8497c478bdstevel@tonic-gate		while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
8507c478bdstevel@tonic-gate			kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
8517c478bdstevel@tonic-gate			kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
8527c478bdstevel@tonic-gate			kw_namestr[2] = '\0';
85385025c0gd			kw_len =
85485025c0gd			    (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
8557c478bdstevel@tonic-gate			for (i = 0, kw_ptr += 3; i < kw_len; i++)
85685025c0gd				kw_fieldstr[i] =
85785025c0gd				    GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
8587c478bdstevel@tonic-gate			kw_fieldstr[i] = '\0';
8597c478bdstevel@tonic-gate			if (hme_create_prop_from_kw(dip, kw_namestr,
86085025c0gd			    kw_fieldstr)) {
8617c478bdstevel@tonic-gate				return (DDI_FAILURE);
8627c478bdstevel@tonic-gate			}
8637c478bdstevel@tonic-gate			kw_ptr += kw_len;
8647c478bdstevel@tonic-gate		} /* next keyword */
8657c478bdstevel@tonic-gate		vpd_start += (vpd_len + 3);
8667c478bdstevel@tonic-gate	} /* next VPD */
8677c478bdstevel@tonic-gate	return (0);
8687c478bdstevel@tonic-gate}
8697c478bdstevel@tonic-gate
8707c478bdstevel@tonic-gate
8717c478bdstevel@tonic-gate/*
8727c478bdstevel@tonic-gate * Get properties from VPD
8737c478bdstevel@tonic-gate */
8747c478bdstevel@tonic-gatestatic int
8757c478bdstevel@tonic-gatehme_get_vpd_props(dev_info_t *dip)
8767c478bdstevel@tonic-gate{
8777c478bdstevel@tonic-gate	struct hme *hmep;
8787c478bdstevel@tonic-gate	int v0, v1, vpd_base;
8797c478bdstevel@tonic-gate	int i, epromsrchlimit;
8807c478bdstevel@tonic-gate
8817c478bdstevel@tonic-gate
8827c478bdstevel@tonic-gate	hmep = ddi_get_driver_private(dip);
8837c478bdstevel@tonic-gate
8847c478bdstevel@tonic-gate	v0 = (int)(GET_ROM8(&(hmep->hme_romp[0])));
8857c478bdstevel@tonic-gate	v1 = (int)(GET_ROM8(&(hmep->hme_romp[1])));
8867c478bdstevel@tonic-gate	v0 = ((v0 & 0xff) << 8 | v1);
8877c478bdstevel@tonic-gate
8887c478bdstevel@tonic-gate	if ((v0 & 0xffff) != 0x55aa) {
8897c478bdstevel@tonic-gate		cmn_err(CE_NOTE, " Valid pci prom not found \n");
8907c478bdstevel@tonic-gate		return (1);
8917c478bdstevel@tonic-gate	}
8927c478bdstevel@tonic-gate
8937c478bdstevel@tonic-gate	epromsrchlimit = 4096;
8947c478bdstevel@tonic-gate	for (i = 2; i < epromsrchlimit; i++) {
89585025c0gd		/* "PCIR" */
89685025c0gd		if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') &&
89785025c0gd		    ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') &&
89885025c0gd		    ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') &&
89985025c0gd		    ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) {
90085025c0gd			vpd_base =
90185025c0gd			    (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) |
90285025c0gd			    (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8);
9037c478bdstevel@tonic-gate			break; /* VPD pointer found */
9047c478bdstevel@tonic-gate		}
9057c478bdstevel@tonic-gate	}
9067c478bdstevel@tonic-gate
9077c478bdstevel@tonic-gate	/* No VPD found */
9087c478bdstevel@tonic-gate	if (vpd_base == 0) {
9097c478bdstevel@tonic-gate		cmn_err(CE_NOTE, " Vital Product Data pointer not found \n");
9107c478bdstevel@tonic-gate		return (1);
9117c478bdstevel@tonic-gate	}
9127c478bdstevel@tonic-gate
9137c478bdstevel@tonic-gate	v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base])));
9147c478bdstevel@tonic-gate	if (v0 == 0x82) {
9157c478bdstevel@tonic-gate		if (hme_get_newvpd_props(dip, vpd_base))
9167c478bdstevel@tonic-gate			return (1);
9177c478bdstevel@tonic-gate		return (0);
9187c478bdstevel@tonic-gate	} else if (v0 == 0x90) {
9190219346Garrett D'Amore		/* If we are are SUNW,qfe card, look for the Nth "NA" descr */
9200219346Garrett D'Amore		if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12])  != 0x79) &&
9210219346Garrett D'Amore		    GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) {
9220219346Garrett D'Amore			vpd_base += hmep->hme_devno * 12;
9230219346Garrett D'Amore		}
9247c478bdstevel@tonic-gate		if (hme_get_oldvpd_props(dip, vpd_base))
9257c478bdstevel@tonic-gate			return (1);
9267c478bdstevel@tonic-gate		return (0);
9277c478bdstevel@tonic-gate	} else
9287c478bdstevel@tonic-gate		return (1);	/* unknown start byte in VPD */
9297c478bdstevel@tonic-gate}
9307c478bdstevel@tonic-gate
9310219346Garrett D'Amore/*
9320219346Garrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe
9330219346Garrett D'Amore * cards, so we have to extract it from the ebus bridge that is
9340219346Garrett D'Amore * function zero of the same device.  This is a bit of an ugly hack.
9350219346Garrett D'Amore * (The ebus bridge leaves the entire ROM mapped at base address
9360219346Garrett D'Amore * register 0x10.)
9370219346Garrett D'Amore */
9380219346Garrett D'Amore
9390219346Garrett D'Amoretypedef struct {
9400219346Garrett D'Amore	struct hme 		*hmep;
9410219346Garrett D'Amore	dev_info_t		*parent;
9420219346Garrett D'Amore	uint8_t			bus, dev;
9430219346Garrett D'Amore	ddi_acc_handle_t	acch;
9440219346Garrett D'Amore	caddr_t			romp;
9450219346Garrett D'Amore} ebus_rom_t;
9460219346Garrett D'Amore
9470219346Garrett D'Amorestatic int
9480219346Garrett D'Amorehme_mapebusrom(dev_info_t *dip, void *arg)
9490219346Garrett D'Amore{
9500219346Garrett D'Amore	int		*regs;
9510219346Garrett D'Amore	unsigned	nregs;
9520219346Garrett D'Amore	int		reg;
9530219346Garrett D'Amore	ebus_rom_t	*rom = arg;
9540219346Garrett D'Amore	struct hme	*hmep = rom->hmep;
9550219346Garrett D'Amore
9560219346Garrett D'Amore	/*
9570219346Garrett D'Amore	 * We only want to look at our peers.  Skip our parent.
9580219346Garrett D'Amore	 */
9590219346Garrett D'Amore	if (dip == rom->parent) {
9600219346Garrett D'Amore		return (DDI_WALK_PRUNESIB);
9610219346Garrett D'Amore	}
9620219346Garrett D'Amore
96306673d9Garrett D'Amore	if (ddi_get_parent(dip) != rom->parent)
96406673d9Garrett D'Amore		return (DDI_WALK_CONTINUE);
96506673d9Garrett D'Amore
9660219346Garrett D'Amore	if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
9670219346Garrett D'Amore	    "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
9680219346Garrett D'Amore		return (DDI_WALK_PRUNECHILD);
9690219346Garrett D'Amore	}
9700219346Garrett D'Amore
9710219346Garrett D'Amore	if (nregs < 1) {
9720219346Garrett D'Amore		ddi_prop_free(regs);
9730219346Garrett D'Amore		return (DDI_WALK_PRUNECHILD);
9740219346Garrett D'Amore	}
9750219346Garrett D'Amore	reg = regs[0];
9760219346Garrett D'Amore	ddi_prop_free(regs);
9770219346Garrett D'Amore
9780219346Garrett D'Amore	/*
9790219346Garrett D'Amore	 * Look for function 0 on our bus and device.  If the device doesn't
9800219346Garrett D'Amore	 * match, it might be an alternate peer, in which case we don't want
9810219346Garrett D'Amore	 * to examine any of its children.
9820219346Garrett D'Amore	 */
9830219346Garrett D'Amore	if ((PCI_REG_BUS_G(reg) != rom->bus) ||
9840219346Garrett D'Amore	    (PCI_REG_DEV_G(reg) != rom->dev) ||
9850219346Garrett D'Amore	    (PCI_REG_FUNC_G(reg) != 0)) {
9860219346Garrett D'Amore		return (DDI_WALK_PRUNECHILD);
9870219346Garrett D'Amore	}
9880219346Garrett D'Amore
9890219346Garrett D'Amore	(void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr,
9900219346Garrett D'Amore	    &rom->acch);
9910219346Garrett D'Amore	/*
9920219346Garrett D'Amore	 * If we can't map the registers, the caller will notice that
9930219346Garrett D'Amore	 * the acch is NULL.
9940219346Garrett D'Amore	 */
9950219346Garrett D'Amore	return (DDI_WALK_TERMINATE);
9960219346Garrett D'Amore}
9970219346Garrett D'Amore
9980219346Garrett D'Amorestatic int
9990219346Garrett D'Amorehmeget_promebus(dev_info_t *dip)
10000219346Garrett D'Amore{
10010219346Garrett D'Amore	ebus_rom_t	rom;
10020219346Garrett D'Amore	int		*regs;
10030219346Garrett D'Amore	unsigned	nregs;
10040219346Garrett D'Amore	struct hme	*hmep;
10050219346Garrett D'Amore
10060219346Garrett D'Amore	hmep = ddi_get_driver_private(dip);
10070219346Garrett D'Amore
10080219346Garrett D'Amore	bzero(&rom, sizeof (rom));
10090219346Garrett D'Amore
10100219346Garrett D'Amore	/*
10110219346Garrett D'Amore	 * For x86, the BIOS doesn't map the PCI Rom register for the qfe
10120219346Garrett D'Amore	 * cards, so we have to extract it from the eBus bridge that is
10130219346Garrett D'Amore	 * function zero.  This is a bit of an ugly hack.
10140219346Garrett D'Amore	 */
10150219346Garrett D'Amore	if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
10160219346Garrett D'Amore	    "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
10170219346Garrett D'Amore		return (DDI_FAILURE);
10180219346Garrett D'Amore	}
10190219346Garrett D'Amore
10200219346Garrett D'Amore	if (nregs < 5) {
10210219346Garrett D'Amore		ddi_prop_free(regs);
10220219346Garrett D'Amore		return (DDI_FAILURE);
10230219346Garrett D'Amore	}
10240219346Garrett D'Amore	rom.hmep = hmep;
10250219346Garrett D'Amore	rom.bus = PCI_REG_BUS_G(regs[0]);
10260219346Garrett D'Amore	rom.dev = PCI_REG_DEV_G(regs[0]);
10270219346Garrett D'Amore	hmep->hme_devno = rom.dev;
10280219346Garrett D'Amore	rom.parent = ddi_get_parent(dip);
10290219346Garrett D'Amore
10300219346Garrett D'Amore	/*
10310219346Garrett D'Amore	 * The implementation of ddi_walk_devs says that we must not
103206673d9Garrett D'Amore	 * be called during autoconfiguration.  However, it turns out
103306673d9Garrett D'Amore	 * that it is safe to call this during our attach routine,
103406673d9Garrett D'Amore	 * because we are not a nexus device.
10350219346Garrett D'Amore	 *
103606673d9Garrett D'Amore	 * Previously we rooted our search at our immediate parent,
103706673d9Garrett D'Amore	 * but this triggered an assertion panic in debug kernels.
10380219346Garrett D'Amore	 */
103906673d9Garrett D'Amore	ddi_walk_devs(ddi_root_node(), hme_mapebusrom, &rom);
10400219346Garrett D'Amore
10410219346Garrett D'Amore	if (rom.acch) {
10420219346Garrett D'Amore		hmep->hme_romh = rom.acch;
10430219346Garrett D'Amore		hmep->hme_romp = (unsigned char *)rom.romp;
10440219346Garrett D'Amore		return (DDI_SUCCESS);
10450219346Garrett D'Amore	}
10460219346Garrett D'Amore	return (DDI_FAILURE);
10470219346Garrett D'Amore}
10480219346Garrett D'Amore
10497c478bdstevel@tonic-gatestatic int
10507c478bdstevel@tonic-gatehmeget_promprops(dev_info_t *dip)
10517c478bdstevel@tonic-gate{
10527c478bdstevel@tonic-gate	struct hme *hmep;
10537c478bdstevel@tonic-gate	int rom_bar;
10547c478bdstevel@tonic-gate	ddi_acc_handle_t cfg_handle;
10557c478bdstevel@tonic-gate	struct {
10567c478bdstevel@tonic-gate		uint16_t vendorid;
10577c478bdstevel@tonic-gate		uint16_t devid;
10587c478bdstevel@tonic-gate		uint16_t command;
10597c478bdstevel@tonic-gate		uint16_t status;
10607c478bdstevel@tonic-gate		uint32_t junk1;
10617c478bdstevel@tonic-gate		uint8_t cache_line;
10627c478bdstevel@tonic-gate		uint8_t latency;
10637c478bdstevel@tonic-gate		uint8_t header;
10647c478bdstevel@tonic-gate		uint8_t bist;
10657c478bdstevel@tonic-gate		uint32_t base;
10667c478bdstevel@tonic-gate		uint32_t base14;
10677c478bdstevel@tonic-gate		uint32_t base18;
10687c478bdstevel@tonic-gate		uint32_t base1c;
10697c478bdstevel@tonic-gate		uint32_t base20;
10707c478bdstevel@tonic-gate		uint32_t base24;
10717c478bdstevel@tonic-gate		uint32_t base28;
10727c478bdstevel@tonic-gate		uint32_t base2c;
10737c478bdstevel@tonic-gate		uint32_t base30;
10747c478bdstevel@tonic-gate	} *cfg_ptr;
10757c478bdstevel@tonic-gate
10767c478bdstevel@tonic-gate	hmep = ddi_get_driver_private(dip);
10777c478bdstevel@tonic-gate
10787c478bdstevel@tonic-gate
10797c478bdstevel@tonic-gate	/*
10807c478bdstevel@tonic-gate	 * map configuration space
10817c478bdstevel@tonic-gate	 */
10827c478bdstevel@tonic-gate	if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
108385025c0gd	    0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
10847c478bdstevel@tonic-gate		return (DDI_FAILURE);
10857c478bdstevel@tonic-gate	}
10867c478bdstevel@tonic-gate
10877c478bdstevel@tonic-gate	/*
10887c478bdstevel@tonic-gate	 * Enable bus-master and memory accesses
10897c478bdstevel@tonic-gate	 */
10907c478bdstevel@tonic-gate	ddi_put16(cfg_handle, &cfg_ptr->command,
109185025c0gd	    PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT |
109285025c0gd	    PCI_COMM_MAE | PCI_COMM_ME);
10937c478bdstevel@tonic-gate
10947c478bdstevel@tonic-gate	/*
10957c478bdstevel@tonic-gate	 * Enable rom accesses
10967c478bdstevel@tonic-gate	 */
10977c478bdstevel@tonic-gate	rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30);
10987c478bdstevel@tonic-gate	ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1);
10997c478bdstevel@tonic-gate
11007c478bdstevel@tonic-gate
11010219346Garrett D'Amore	if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0,
11020219346Garrett D'Amore	    &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) &&
11030219346Garrett D'Amore	    (hmeget_promebus(dip) != DDI_SUCCESS)) {
11040219346Garrett D'Amore
11057c478bdstevel@tonic-gate		if (cfg_ptr)
11067c478bdstevel@tonic-gate			ddi_regs_map_free(&cfg_handle);
11077c478bdstevel@tonic-gate		return (DDI_FAILURE);
11087c478bdstevel@tonic-gate	} else {
11097c478bdstevel@tonic-gate		if (hme_get_vpd_props(dip))
11100219346Garrett D'Amore			return (DDI_FAILURE);
11117c478bdstevel@tonic-gate	}
11127c478bdstevel@tonic-gate	if (hmep->hme_romp)
11137c478bdstevel@tonic-gate		ddi_regs_map_free(&hmep->hme_romh);
11147c478bdstevel@tonic-gate	if (cfg_ptr)
11157c478bdstevel@tonic-gate		ddi_regs_map_free(&cfg_handle);
11160219346Garrett D'Amore	return (DDI_SUCCESS);
11177c478bdstevel@tonic-gate
11187c478bdstevel@tonic-gate}
11197c478bdstevel@tonic-gate
11207c478bdstevel@tonic-gatestatic void
11217c478bdstevel@tonic-gatehmeget_hm_rev_property(struct hme *hmep)
11227c478bdstevel@tonic-gate{
11237c478bdstevel@tonic-gate	int	hm_rev;
11247c478bdstevel@tonic-gate
11257c478bdstevel@tonic-gate
11267c478bdstevel@tonic-gate	hm_rev = hmep->asic_rev;
11277c478bdstevel@tonic-gate	switch (hm_rev) {
11287c478bdstevel@tonic-gate	case HME_2P1_REVID:
11297c478bdstevel@tonic-gate	case HME_2P1_REVID_OBP:
11307c478bdstevel@tonic-gate		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
113185025c0gd		    "SBus 2.1 Found (Rev Id = %x)", hm_rev);
11327c478bdstevel@tonic-gate		hmep->hme_frame_enable = 1;
11337c478bdstevel@tonic-gate		break;
11347c478bdstevel@tonic-gate
11357c478bdstevel@tonic-gate	case HME_2P0_REVID:
11367c478bdstevel@tonic-gate		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
113785025c0gd		    "SBus 2.0 Found (Rev Id = %x)", hm_rev);
11387c478bdstevel@tonic-gate		break;
11397c478bdstevel@tonic-gate
11407c478bdstevel@tonic-gate	case HME_1C0_REVID:
11417c478bdstevel@tonic-gate		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
114285025c0gd		    "PCI IO 1.0 Found (Rev Id = %x)", hm_rev);
11437c478bdstevel@tonic-gate		break;
11447c478bdstevel@tonic-gate
11457c478bdstevel@tonic-gate	default:
114606673d9Garrett D'Amore		HME_FAULT_MSG3(hmep, SEVERITY_NONE, DISPLAY_MSG,
114785025c0gd		    "%s (Rev Id = %x) Found",
114885025c0gd		    (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev);
11497c478bdstevel@tonic-gate		hmep->hme_frame_enable = 1;
11507c478bdstevel@tonic-gate		hmep->hme_lance_mode_enable = 1;
11517c478bdstevel@tonic-gate		hmep->hme_rxcv_enable = 1;
11527c478bdstevel@tonic-gate		break;
11537c478bdstevel@tonic-gate	}
11547c478bdstevel@tonic-gate}
11557c478bdstevel@tonic-gate
11567c478bdstevel@tonic-gate/*
11577c478bdstevel@tonic-gate * Interface exists: make available by filling in network interface
11587c478bdstevel@tonic-gate * record.  System will initialize the interface when it is ready
11597c478bdstevel@tonic-gate * to accept packets.
11607c478bdstevel@tonic-gate */
1161f2cd0f0gdint
11627c478bdstevel@tonic-gatehmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
11637c478bdstevel@tonic-gate{
11647c478bdstevel@tonic-gate	struct hme *hmep;
116585025c0gd	mac_register_t *macp = NULL;
11667c478bdstevel@tonic-gate	int 	regno;
11677c478bdstevel@tonic-gate	int hm_rev = 0;
11687c478bdstevel@tonic-gate	int prop_len = sizeof (int);
11697c478bdstevel@tonic-gate	ddi_acc_handle_t cfg_handle;
11707c478bdstevel@tonic-gate	struct {
11717c478bdstevel@tonic-gate		uint16_t vendorid;
11727c478bdstevel@tonic-gate		uint16_t devid;
11737c478bdstevel@tonic-gate		uint16_t command;
11747c478bdstevel@tonic-gate		uint16_t status;
11757c478bdstevel@tonic-gate		uint8_t revid;
11767c478bdstevel@tonic-gate		uint8_t j1;
11777c478bdstevel@tonic-gate		uint16_t j2;
11787c478bdstevel@tonic-gate	} *cfg_ptr;
11797c478bdstevel@tonic-gate
11807c478bdstevel@tonic-gate	switch (cmd) {
11817c478bdstevel@tonic-gate	case DDI_ATTACH:
11827c478bdstevel@tonic-gate		break;
11837c478bdstevel@tonic-gate
11847c478bdstevel@tonic-gate	case DDI_RESUME:
11857c478bdstevel@tonic-gate		if ((hmep = ddi_get_driver_private(dip)) == NULL)
118685025c0gd			return (DDI_FAILURE);
11877c478bdstevel@tonic-gate
11887c478bdstevel@tonic-gate		hmep->hme_flags &= ~HMESUSPENDED;
118906673d9Garrett D'Amore
119006673d9Garrett D'Amore		mii_resume(hmep->hme_mii);
119185025c0gd
1192228fdffgd		if (hmep->hme_started)
119385025c0gd			(void) hmeinit(hmep);
11947c478bdstevel@tonic-gate		return (DDI_SUCCESS);
11957c478bdstevel@tonic-gate
11967c478bdstevel@tonic-gate	default:
11977c478bdstevel@tonic-gate		return (DDI_FAILURE);
11987c478bdstevel@tonic-gate	}
11997c478bdstevel@tonic-gate
12007c478bdstevel@tonic-gate	/*
12017c478bdstevel@tonic-gate	 * Allocate soft device data structure
12027c478bdstevel@tonic-gate	 */
12030219346Garrett D'Amore	hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP);
12047c478bdstevel@tonic-gate
12057c478bdstevel@tonic-gate	/*
12067c478bdstevel@tonic-gate	 * Might as well set up elements of data structure
12077c478bdstevel@tonic-gate	 */
12087c478bdstevel@tonic-gate	hmep->dip =		dip;
12097c478bdstevel@tonic-gate	hmep->instance = 	ddi_get_instance(dip);
12107c478bdstevel@tonic-gate	hmep->pagesize =	ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */
12117c478bdstevel@tonic-gate
12127c478bdstevel@tonic-gate	/*
12137c478bdstevel@tonic-gate	 *  Might as well setup the driver private
12147c478bdstevel@tonic-gate	 * structure as part of the dip.
12157c478bdstevel@tonic-gate	 */
12167c478bdstevel@tonic-gate	ddi_set_driver_private(dip, hmep);
12177c478bdstevel@tonic-gate
12187c478bdstevel@tonic-gate	/*
12197c478bdstevel@tonic-gate	 * Reject this device if it's in a slave-only slot.
12207c478bdstevel@tonic-gate	 */
12217c478bdstevel@tonic-gate	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
12227c478bdstevel@tonic-gate		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
12230219346Garrett D'Amore		    "Dev not used - dev in slave only slot");
12247c478bdstevel@tonic-gate		goto error_state;
12257c478bdstevel@tonic-gate	}
12267c478bdstevel@tonic-gate
12277c478bdstevel@tonic-gate	/*
12287c478bdstevel@tonic-gate	 * Map in the device registers.
12297c478bdstevel@tonic-gate	 *
12307c478bdstevel@tonic-gate	 * Reg # 0 is the Global register set
12317c478bdstevel@tonic-gate	 * Reg # 1 is the ETX register set
12327c478bdstevel@tonic-gate	 * Reg # 2 is the ERX register set
12337c478bdstevel@tonic-gate	 * Reg # 3 is the BigMAC register set.
12347c478bdstevel@tonic-gate	 * Reg # 4 is the MIF register set
12357c478bdstevel@tonic-gate	 */
12367c478bdstevel@tonic-gate	if (ddi_dev_nregs(dip, &regno) != (DDI_SUCCESS)) {
12377c478bdstevel@tonic-gate		HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG,
123885025c0gd		    ddi_nregs_fail_msg, regno);
12397c478bdstevel@tonic-gate		goto error_state;
12407c478bdstevel@tonic-gate	}
12417c478bdstevel@tonic-gate
12427c478bdstevel@tonic-gate	switch (regno) {
12437c478bdstevel@tonic-gate	case 5:
12447c478bdstevel@tonic-gate		hmep->hme_cheerio_mode = 0;
12457c478bdstevel@tonic-gate		break;
12467c478bdstevel@tonic-gate	case 2:
12477c478bdstevel@tonic-gate	case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */
12487c478bdstevel@tonic-gate		hmep->hme_cheerio_mode = 1;
12497c478bdstevel@tonic-gate		break;
12507c478bdstevel@tonic-gate	default:
125185025c0gd		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
125285025c0gd		    bad_num_regs_msg);
12537c478bdstevel@tonic-gate		goto error_state;
12547c478bdstevel@tonic-gate	}
12557c478bdstevel@tonic-gate
12567c478bdstevel@tonic-gate	/* Initialize device attributes structure */
12577c478bdstevel@tonic-gate	hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
12587c478bdstevel@tonic-gate
12597c478bdstevel@tonic-gate	if (hmep->hme_cheerio_mode)
126085025c0gd		hmep->hme_dev_attr.devacc_attr_endian_flags =
126185025c0gd		    DDI_STRUCTURE_LE_ACC;
12627c478bdstevel@tonic-gate	else
126385025c0gd		hmep->hme_dev_attr.devacc_attr_endian_flags =
126485025c0gd		    DDI_STRUCTURE_BE_ACC;
12657c478bdstevel@tonic-gate
12667c478bdstevel@tonic-gate	hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
12677c478bdstevel@tonic-gate
12687c478bdstevel@tonic-gate	if (hmep->hme_cheerio_mode) {
12697c478bdstevel@tonic-gate		uint8_t		oldLT;
12707c478bdstevel@tonic-gate		uint8_t		newLT = 0;
12717c478bdstevel@tonic-gate		dev_info_t	*pdip;
12727c478bdstevel@tonic-gate		const char	*pdrvname;
12737c478bdstevel@tonic-gate
12747c478bdstevel@tonic-gate		/*
12757c478bdstevel@tonic-gate		 * Map the PCI config space
12767c478bdstevel@tonic-gate		 */
12777c478bdstevel@tonic-gate		if (pci_config_setup(dip, &hmep->pci_config_handle) !=
127885025c0gd		    DDI_SUCCESS) {
12797c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
128085025c0gd			    "pci_config_setup() failed..");
12817c478bdstevel@tonic-gate			goto error_state;
12827c478bdstevel@tonic-gate		}
12837c478bdstevel@tonic-gate
12847c478bdstevel@tonic-gate		if (ddi_regs_map_setup(dip, 1,
128585025c0gd		    (caddr_t *)&(hmep->hme_globregp), 0, 0,
128685025c0gd		    &hmep->hme_dev_attr, &hmep->hme_globregh)) {
12877c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
128885025c0gd			    mregs_4global_reg_fail_msg);
12897c478bdstevel@tonic-gate			goto error_unmap;
12907c478bdstevel@tonic-gate		}
12917c478bdstevel@tonic-gate		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
12927c478bdstevel@tonic-gate		    hmep->hme_mifregh = hmep->hme_globregh;
12937c478bdstevel@tonic-gate
129485025c0gd		hmep->hme_etxregp =
129585025c0gd		    (void *)(((caddr_t)hmep->hme_globregp) + 0x2000);
129685025c0gd		hmep->hme_erxregp =
129785025c0gd		    (void *)(((caddr_t)hmep->hme_globregp) + 0x4000);
129885025c0gd		hmep->hme_bmacregp =
129985025c0gd		    (void *)(((caddr_t)hmep->hme_globregp) + 0x6000);
130085025c0gd		hmep->hme_mifregp =
130185025c0gd		    (void *)(((caddr_t)hmep->hme_globregp) + 0x7000);
13027c478bdstevel@tonic-gate
13037c478bdstevel@tonic-gate		/*
13047c478bdstevel@tonic-gate		 * Get parent pci bridge info.
13057c478bdstevel@tonic-gate		 */
13067c478bdstevel@tonic-gate		pdip = ddi_get_parent(dip);
13077c478bdstevel@tonic-gate		pdrvname = ddi_driver_name(pdip);
13087c478bdstevel@tonic-gate
13097c478bdstevel@tonic-gate		oldLT = pci_config_get8(hmep->pci_config_handle,
131085025c0gd		    PCI_CONF_LATENCY_TIMER);
13117c478bdstevel@tonic-gate		/*
13127c478bdstevel@tonic-gate		 * Honor value set in /etc/system
13137c478bdstevel@tonic-gate		 * "set hme:pci_latency_timer=0xYY"
13147c478bdstevel@tonic-gate		 */
13157c478bdstevel@tonic-gate		if (pci_latency_timer)
13167c478bdstevel@tonic-gate			newLT = pci_latency_timer;
13177c478bdstevel@tonic-gate		/*
13187c478bdstevel@tonic-gate		 * Modify LT for simba
13197c478bdstevel@tonic-gate		 */
13207c478bdstevel@tonic-gate		else if (strcmp("simba", pdrvname) == 0)
13217c478bdstevel@tonic-gate			newLT = 0xf0;
13227c478bdstevel@tonic-gate		/*
13237c478bdstevel@tonic-gate		 * Ensure minimum cheerio latency timer of 0x50
13247c478bdstevel@tonic-gate		 * Usually OBP or pci bridge should set this value
13257c478bdstevel@tonic-gate		 * based on cheerio
13267c478bdstevel@tonic-gate		 * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8
13277c478bdstevel@tonic-gate		 * Some system set cheerio LT at 0x40
13287c478bdstevel@tonic-gate		 */
13297c478bdstevel@tonic-gate		else if (oldLT < 0x40)
13307c478bdstevel@tonic-gate			newLT = 0x50;
13317c478bdstevel@tonic-gate
13327c478bdstevel@tonic-gate		/*
13337c478bdstevel@tonic-gate		 * Now program cheerio's pci latency timer with newLT
13347c478bdstevel@tonic-gate		 */
13357c478bdstevel@tonic-gate		if (newLT)
13367c478bdstevel@tonic-gate			pci_config_put8(hmep->pci_config_handle,
133785025c0gd			    PCI_CONF_LATENCY_TIMER, (uchar_t)newLT);
13387c478bdstevel@tonic-gate	} else { /* Map register sets */
13397c478bdstevel@tonic-gate		if (ddi_regs_map_setup(dip, 0,
134085025c0gd		    (caddr_t *)&(hmep->hme_globregp), 0, 0,
134185025c0gd		    &hmep->hme_dev_attr, &hmep->hme_globregh)) {
13427c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
134385025c0gd			    mregs_4global_reg_fail_msg);
13447c478bdstevel@tonic-gate			goto error_state;
13457c478bdstevel@tonic-gate		}
13467c478bdstevel@tonic-gate		if (ddi_regs_map_setup(dip, 1,
134785025c0gd		    (caddr_t *)&(hmep->hme_etxregp), 0, 0,
134885025c0gd		    &hmep->hme_dev_attr, &hmep->hme_etxregh)) {
13497c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
135085025c0gd			    mregs_4etx_reg_fail_msg);
13517c478bdstevel@tonic-gate			goto error_unmap;
13527c478bdstevel@tonic-gate		}
13537c478bdstevel@tonic-gate		if (ddi_regs_map_setup(dip, 2,
135485025c0gd		    (caddr_t *)&(hmep->hme_erxregp), 0, 0,
135585025c0gd		    &hmep->hme_dev_attr, &hmep->hme_erxregh)) {
13567c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
135785025c0gd			    mregs_4erx_reg_fail_msg);
13587c478bdstevel@tonic-gate			goto error_unmap;
13597c478bdstevel@tonic-gate		}
13607c478bdstevel@tonic-gate		if (ddi_regs_map_setup(dip, 3,
136185025c0gd		    (caddr_t *)&(hmep->hme_bmacregp), 0, 0,
136285025c0gd		    &hmep->hme_dev_attr, &hmep->hme_bmacregh)) {
13637c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
136485025c0gd			    mregs_4bmac_reg_fail_msg);
13657c478bdstevel@tonic-gate			goto error_unmap;
13667c478bdstevel@tonic-gate		}
13677c478bdstevel@tonic-gate
13687c478bdstevel@tonic-gate		if (ddi_regs_map_setup(dip, 4,
136985025c0gd		    (caddr_t *)&(hmep->hme_mifregp), 0, 0,
137085025c0gd		    &hmep->hme_dev_attr, &hmep->hme_mifregh)) {
13717c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
137285025c0gd			    mregs_4mif_reg_fail_msg);
13737c478bdstevel@tonic-gate			goto error_unmap;
13747c478bdstevel@tonic-gate		}
13757c478bdstevel@tonic-gate	} /* Endif cheerio_mode */
13767c478bdstevel@tonic-gate
13777c478bdstevel@tonic-gate	/*
13787c478bdstevel@tonic-gate	 * Based on the hm-rev, set some capabilities
13797c478bdstevel@tonic-gate	 * Set up default capabilities for HM 2.0
13807c478bdstevel@tonic-gate	 */
13817c478bdstevel@tonic-gate	hmep->hme_frame_enable = 0;
13827c478bdstevel@tonic-gate	hmep->hme_lance_mode_enable = 0;
13837c478bdstevel@tonic-gate	hmep->hme_rxcv_enable = 0;
13847c478bdstevel@tonic-gate
13857c478bdstevel@tonic-gate	/* NEW routine to get the properties */
13867c478bdstevel@tonic-gate
13877c478bdstevel@tonic-gate	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev",
138885025c0gd	    (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) {
13897c478bdstevel@tonic-gate
13907c478bdstevel@tonic-gate		hmep->asic_rev = hm_rev;
13917c478bdstevel@tonic-gate		hmeget_hm_rev_property(hmep);
13927c478bdstevel@tonic-gate	} else {
13937c478bdstevel@tonic-gate		/*
13947c478bdstevel@tonic-gate		 * hm_rev property not found so, this is
13957c478bdstevel@tonic-gate		 * case of hot insertion of card without interpreting fcode.
13967c478bdstevel@tonic-gate		 * Get it from revid in config space after mapping it.
13977c478bdstevel@tonic-gate		 */
13987c478bdstevel@tonic-gate		if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
139985025c0gd		    0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
14007c478bdstevel@tonic-gate			return (DDI_FAILURE);
14017c478bdstevel@tonic-gate		}
14027c478bdstevel@tonic-gate		/*
14037c478bdstevel@tonic-gate		 * Since this is cheerio-based PCI card, we write 0xC in the
14047c478bdstevel@tonic-gate		 * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits
14057c478bdstevel@tonic-gate		 * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1)
14067c478bdstevel@tonic-gate		 */
14077c478bdstevel@tonic-gate		hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid);
14087c478bdstevel@tonic-gate		hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK);
14097c478bdstevel@tonic-gate		hmep->asic_rev = hm_rev;
14107c478bdstevel@tonic-gate		if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
141185025c0gd		    "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) !=
141285025c0gd		    DDI_SUCCESS) {
14137c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
141406673d9Garrett D'Amore			    "ddi_prop_create error for hm_rev");
14157c478bdstevel@tonic-gate		}
14167c478bdstevel@tonic-gate		ddi_regs_map_free(&cfg_handle);
14177c478bdstevel@tonic-gate
14187c478bdstevel@tonic-gate		hmeget_hm_rev_property(hmep);
14197c478bdstevel@tonic-gate
14207c478bdstevel@tonic-gate		/* get info via VPD */
14210219346Garrett D'Amore		if (hmeget_promprops(dip) != DDI_SUCCESS) {
14227c478bdstevel@tonic-gate			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
142306673d9Garrett D'Amore			    "no promprops");
14247c478bdstevel@tonic-gate		}
14257c478bdstevel@tonic-gate	}
14267c478bdstevel@tonic-gate
14277c478bdstevel@tonic-gate	if (ddi_intr_hilevel(dip, 0)) {
14287c478bdstevel@tonic-gate		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG,
142985025c0gd		    " high-level interrupts are not supported");
14307c478bdstevel@tonic-gate		goto error_unmap;
14317c478bdstevel@tonic-gate	}
14327c478bdstevel@tonic-gate
14337c478bdstevel@tonic-gate	/*
14347c478bdstevel@tonic-gate	 * Get intr. block cookie so that mutex locks can be initialized.
14357c478bdstevel@tonic-gate	 */
14367c478bdstevel@tonic-gate	if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS)
14377c478bdstevel@tonic-gate		goto error_unmap;
14387c478bdstevel@tonic-gate
14397c478bdstevel@tonic-gate	/*
14407c478bdstevel@tonic-gate	 * Initialize mutex's for this device.
14417c478bdstevel@tonic-gate	 */
144285025c0gd	mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
144385025c0gd	mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
14447c478bdstevel@tonic-gate
14457c478bdstevel@tonic-gate	/*
14467c478bdstevel@tonic-gate	 * Quiesce the hardware.
14477c478bdstevel@tonic-gate	 */
14487c478bdstevel@tonic-gate	(void) hmestop(hmep);
14497c478bdstevel@tonic-gate
14507c478bdstevel@tonic-gate	/*
14517c478bdstevel@tonic-gate	 * Add interrupt to system
14527c478bdstevel@tonic-gate	 */
14537c478bdstevel@tonic-gate	if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL,
14547c478bdstevel@tonic-gate	    (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) {
14557c478bdstevel@tonic-gate		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
145685025c0gd		    add_intr_fail_msg);
14577c478bdstevel@tonic-gate		goto error_mutex;
14587c478bdstevel@tonic-gate	}
14597c478bdstevel@tonic-gate
14607c478bdstevel@tonic-gate	/*
14617c478bdstevel@tonic-gate	 * Set up the ethernet mac address.
14627c478bdstevel@tonic-gate	 */
14637c478bdstevel@tonic-gate	hme_setup_mac_address(hmep, dip);
14647c478bdstevel@tonic-gate
14657c478bdstevel@tonic-gate	if (!hmeinit_xfer_params(hmep))
146685025c0gd		goto error_intr;
14677c478bdstevel@tonic-gate
14687c478bdstevel@tonic-gate	if (hmeburstsizes(hmep) == DDI_FAILURE) {
14697c478bdstevel@tonic-gate		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg);
147085025c0gd		goto error_intr;
14717c478bdstevel@tonic-gate	}
14727c478bdstevel@tonic-gate
14730219346Garrett D'Amore	if (hmeallocthings(hmep) != DDI_SUCCESS) {
14740219346Garrett D'Amore		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
14750219346Garrett D'Amore		    "resource allocation failed");
14760219346Garrett D'Amore		goto error_intr;
14770219346Garrett D'Amore	}
14780219346Garrett D'Amore
14790219346Garrett D'Amore	if (hmeallocbufs(hmep) != DDI_SUCCESS) {
14800219346Garrett D'Amore		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
14810219346Garrett D'Amore		    "buffer allocation failed");
14820219346Garrett D'Amore		goto error_intr;
14830219346Garrett D'Amore	}
14847c478bdstevel@tonic-gate
14857c478bdstevel@tonic-gate	hmestatinit(hmep);
148685025c0gd
1487e8717caGarrett D'Amore	/* our external (preferred) PHY is at address 0 */
1488e8717caGarrett D'Amore	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "first-phy", 0);
1489e8717caGarrett D'Amore
149006673d9Garrett D'Amore	hmep->hme_mii = mii_alloc(hmep, dip, &hme_mii_ops);
149106673d9Garrett D'Amore	if (hmep->hme_mii == NULL) {
149206673d9Garrett D'Amore		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
149306673d9Garrett D'Amore		    "mii_alloc failed");
149406673d9Garrett D'Amore		goto error_intr;
149506673d9Garrett D'Amore	}
149606673d9Garrett D'Amore	/* force a probe for the PHY */
149706673d9Garrett D'Amore	mii_probe(hmep->hme_mii);
149806673d9Garrett D'Amore
149985025c0gd	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
150085025c0gd		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
150185025c0gd		    "mac_alloc failed");
150285025c0gd		goto error_intr;
150385025c0gd	}
150485025c0gd	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
150585025c0gd	macp->m_driver = hmep;
150685025c0gd	macp->m_dip = dip;
150785025c0gd	macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet;
150885025c0gd	macp->m_callbacks = &hme_m_callbacks;
150985025c0gd	macp->m_min_sdu = 0;
151085025c0gd	macp->m_max_sdu = ETHERMTU;
1511d62bc4byz	macp->m_margin = VLAN_TAGSZ;
151206673d9Garrett D'Amore	macp->m_priv_props = hme_priv_prop;
151385025c0gd	if (mac_register(macp, &hmep->hme_mh) != 0) {
151485025c0gd		mac_free(macp);
151585025c0gd		goto error_intr;
151685025c0gd	}
151785025c0gd
151885025c0gd	mac_free(macp);
151985025c0gd
15207c478bdstevel@tonic-gate	ddi_report_dev(dip);
15217c478bdstevel@tonic-gate	return (DDI_SUCCESS);
15227c478bdstevel@tonic-gate
15237c478bdstevel@tonic-gate	/*
15247c478bdstevel@tonic-gate	 * Failure Exit
15257c478bdstevel@tonic-gate	 */
15267c478bdstevel@tonic-gate
15277c478bdstevel@tonic-gateerror_intr:
15287c478bdstevel@tonic-gate	if (hmep->hme_cookie)
15297c478bdstevel@tonic-gate		ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
15307c478bdstevel@tonic-gate
153106673d9Garrett D'Amore	if (hmep->hme_mii)
153206673d9Garrett D'Amore		mii_free(hmep->hme_mii);
153306673d9Garrett D'Amore
15347c478bdstevel@tonic-gateerror_mutex:
15357c478bdstevel@tonic-gate	mutex_destroy(&hmep->hme_xmitlock);
15367c478bdstevel@tonic-gate	mutex_destroy(&hmep->hme_intrlock);
15377c478bdstevel@tonic-gate
15387c478bdstevel@tonic-gateerror_unmap:
15397c478bdstevel@tonic-gate	if (hmep->hme_globregh)
154085025c0gd		ddi_regs_map_free(&hmep->hme_globregh);
15417c478bdstevel@tonic-gate	if (hmep->hme_cheerio_mode == 0) {
15427c478bdstevel@tonic-gate		if (hmep->hme_etxregh)
154385025c0gd			ddi_regs_map_free(&hmep->hme_etxregh);
15447c478bdstevel@tonic-gate		if (hmep->hme_erxregh)
154585025c0gd			ddi_regs_map_free(&hmep->hme_erxregh);
15467c478bdstevel@tonic-gate		if (hmep->hme_bmacregh)
154785025c0gd			ddi_regs_map_free(&hmep->hme_bmacregh);
15487c478bdstevel@tonic-gate		if (hmep->hme_mifregh)
154985025c0gd			ddi_regs_map_free(&hmep->hme_mifregh);
15507c478bdstevel@tonic-gate	} else {
15517c478bdstevel@tonic-gate		if (hmep->pci_config_handle)
15527c478bdstevel@tonic-gate			(void) pci_config_teardown(&hmep->pci_config_handle);
15537c478bdstevel@tonic-gate		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
15547c478bdstevel@tonic-gate		    hmep->hme_mifregh = hmep->hme_globregh = NULL;
15557c478bdstevel@tonic-gate	}
15567c478bdstevel@tonic-gate
15577c478bdstevel@tonic-gateerror_state:
15580219346Garrett D'Amore	hmefreethings(hmep);
15590219346Garrett D'Amore	hmefreebufs(hmep);
15600219346Garrett D'Amore
15617c478bdstevel@tonic-gate	if (hmep) {
15627c478bdstevel@tonic-gate		kmem_free((caddr_t)hmep, sizeof (*hmep));
15637c478bdstevel@tonic-gate		ddi_set_driver_private(dip, NULL);
15647c478bdstevel@tonic-gate	}
15657c478bdstevel@tonic-gate
15667c478bdstevel@tonic-gate	return (DDI_FAILURE);
15677c478bdstevel@tonic-gate}
15687c478bdstevel@tonic-gate
1569f2cd0f0gdint
15707c478bdstevel@tonic-gatehmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
15717c478bdstevel@tonic-gate{
157285025c0gd	struct hme *hmep;
15737c478bdstevel@tonic-gate
15747c478bdstevel@tonic-gate	if ((hmep = ddi_get_driver_private(dip)) == NULL)
15757c478bdstevel@tonic-gate		return (DDI_FAILURE);
15767c478bdstevel@tonic-gate
15777c478bdstevel@tonic-gate	switch (cmd) {
15787c478bdstevel@tonic-gate	case DDI_DETACH:
15797c478bdstevel@tonic-gate		break;
15807c478bdstevel@tonic-gate
15817c478bdstevel@tonic-gate	case DDI_SUSPEND:
158206673d9Garrett D'Amore		mii_suspend(hmep->hme_mii);
15837c478bdstevel@tonic-gate		hmep->hme_flags |= HMESUSPENDED;
15847c478bdstevel@tonic-gate		hmeuninit(hmep);
15857c478bdstevel@tonic-gate		return (DDI_SUCCESS);
15867c478bdstevel@tonic-gate
15877c478bdstevel@tonic-gate	default:
158885025c0gd		return (DDI_FAILURE);
158985025c0gd	}
159085025c0gd
159185025c0gd
159285025c0gd	if (mac_unregister(hmep->hme_mh) != 0) {
15937c478bdstevel@tonic-gate		return (DDI_FAILURE);
15947c478bdstevel@tonic-gate	}
15957c478bdstevel@tonic-gate
15967c478bdstevel@tonic-gate	/*
15977c478bdstevel@tonic-gate	 * Make driver quiescent, we don't want to prevent the
15984dd87b6gd	 * detach on failure.  Note that this should be redundant,
15994dd87b6gd	 * since mac_stop should already have called hmeuninit().
16007c478bdstevel@tonic-gate	 */
16014dd87b6gd	if (!(hmep->hme_flags & HMESUSPENDED)) {
16024dd87b6gd		(void) hmestop(hmep);
16034dd87b6gd	}
16047c478bdstevel@tonic-gate
160506673d9Garrett D'Amore	if (hmep->hme_mii)
160606673d9Garrett D'Amore		mii_free(hmep->hme_mii);
160706673d9Garrett D'Amore
16087c478bdstevel@tonic-gate	/*
16097c478bdstevel@tonic-gate	 * Remove instance of the intr
16107c478bdstevel@tonic-gate	 */
16117c478bdstevel@tonic-gate	ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
16127c478bdstevel@tonic-gate
16137c478bdstevel@tonic-gate	/*
161485025c0gd	 * Unregister kstats.
161585025c0gd	 */
161685025c0gd	if (hmep->hme_ksp != NULL)
161785025c0gd		kstat_delete(hmep->hme_ksp);
161885025c0gd	if (hmep->hme_intrstats != NULL)
161985025c0gd		kstat_delete(hmep->hme_intrstats);
162085025c0gd
162106673d9Garrett D'Amore	hmep->hme_ksp = NULL;
162206673d9Garrett D'Amore	hmep->hme_intrstats = NULL;
162385025c0gd
162485025c0gd	/*
16257c478bdstevel@tonic-gate	 * Destroy all mutexes and data structures allocated during
16267c478bdstevel@tonic-gate	 * attach time.
162785025c0gd	 *
162885025c0gd	 * Note: at this time we should be the only thread accessing
162985025c0gd	 * the structures for this instance.
16307c478bdstevel@tonic-gate	 */
16317c478bdstevel@tonic-gate
16327c478bdstevel@tonic-gate	if (hmep->hme_globregh)
16337c478bdstevel@tonic-gate		ddi_regs_map_free(&hmep->hme_globregh);
16347c478bdstevel@tonic-gate	if (hmep->hme_cheerio_mode == 0) {
16357c478bdstevel@tonic-gate		if (hmep->hme_etxregh)
163685025c0gd			ddi_regs_map_free(&hmep->hme_etxregh);
16377c478bdstevel@tonic-gate		if (hmep->hme_erxregh)
163885025c0gd			ddi_regs_map_free(&hmep->hme_erxregh);
16397c478bdstevel@tonic-gate		if (hmep->hme_bmacregh)
164085025c0gd			ddi_regs_map_free(&hmep->hme_bmacregh);
16417c478bdstevel@tonic-gate		if (hmep->hme_mifregh)
164285025c0gd			ddi_regs_map_free(&hmep->hme_mifregh);
16437c478bdstevel@tonic-gate	} else {
16447c478bdstevel@tonic-gate		if (hmep->pci_config_handle)
16457c478bdstevel@tonic-gate			(void) pci_config_teardown(&hmep->pci_config_handle);
16467c478bdstevel@tonic-gate		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
16477c478bdstevel@tonic-gate		    hmep->hme_mifregh = hmep->hme_globregh = NULL;
16487c478bdstevel@tonic-gate	}
16497c478bdstevel@tonic-gate
165085025c0gd	mutex_destroy(&hmep->hme_xmitlock);
165185025c0gd	mutex_destroy(&hmep->hme_intrlock);
16527c478bdstevel@tonic-gate
16530219346Garrett D'Amore	hmefreethings(hmep);
165485025c0gd	hmefreebufs(hmep);
16557c478bdstevel@tonic-gate
165685025c0gd	ddi_set_driver_private(dip, NULL);
165785025c0gd	kmem_free(hmep, sizeof (struct hme));
16587c478bdstevel@tonic-gate
16597c478bdstevel@tonic-gate	return (DDI_SUCCESS);
16607c478bdstevel@tonic-gate}
16617c478bdstevel@tonic-gate
16620219346Garrett D'Amoreint
16630219346Garrett D'Amorehmequiesce(dev_info_t *dip)
16640219346Garrett D'Amore{
16650219346Garrett D'Amore	struct hme *hmep;
16660219346Garrett D'Amore
16670219346Garrett D'Amore	if ((hmep = ddi_get_driver_private(dip)) == NULL)
16680219346Garrett D'Amore		return (DDI_FAILURE);
16690219346Garrett D'Amore
16700219346Garrett D'Amore	(void) hmestop(hmep);
16710219346Garrett D'Amore	return (DDI_SUCCESS);
16720219346Garrett D'Amore}
16730219346Garrett D'Amore
167485025c0gdstatic boolean_t
16757c478bdstevel@tonic-gatehmeinit_xfer_params(struct hme *hmep)
16767c478bdstevel@tonic-gate{
16777c478bdstevel@tonic-gate	int hme_ipg1_conf, hme_ipg2_conf;
16787c478bdstevel@tonic-gate	int hme_ipg0_conf, hme_lance_mode_conf;
16797c478bdstevel@tonic-gate	int prop_len = sizeof (int);
16807c478bdstevel@tonic-gate	dev_info_t *dip;
16817c478bdstevel@tonic-gate
16827c478bdstevel@tonic-gate	dip = hmep->dip;
16837c478bdstevel@tonic-gate
16847c478bdstevel@tonic-gate	/*
16857c478bdstevel@tonic-gate	 * Set up the start-up values for user-configurable parameters
16867c478bdstevel@tonic-gate	 * Get the values from the global variables first.
16877c478bdstevel@tonic-gate	 * Use the MASK to limit the value to allowed maximum.
16887c478bdstevel@tonic-gate	 */
168906673d9Garrett D'Amore	hmep->hme_ipg1 = hme_ipg1 & HME_MASK_8BIT;
169006673d9Garrett D'Amore	hmep->hme_ipg2 = hme_ipg2 & HME_MASK_8BIT;
169106673d9Garrett D'Amore	hmep->hme_ipg0 = hme_ipg0 & HME_MASK_5BIT;
16927c478bdstevel@tonic-gate
16937c478bdstevel@tonic-gate	/*
16947c478bdstevel@tonic-gate	 * Get the parameter values configured in .conf file.
16957c478bdstevel@tonic-gate	 */
16967c478bdstevel@tonic-gate	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1",
169785025c0gd	    (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) {
169806673d9Garrett D'Amore		hmep->hme_ipg1 = hme_ipg1_conf & HME_MASK_8BIT;
16997c478bdstevel@tonic-gate	}
17007c478bdstevel@tonic-gate
17017c478bdstevel@tonic-gate	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2",
170285025c0gd	    (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) {
170306673d9Garrett D'Amore		hmep->hme_ipg2 = hme_ipg2_conf & HME_MASK_8BIT;
17047c478bdstevel@tonic-gate	}
17057c478bdstevel@tonic-gate
17067c478bdstevel@tonic-gate	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0",
170785025c0gd	    (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) {
170806673d9Garrett D'Amore		hmep->hme_ipg0 = hme_ipg0_conf & HME_MASK_5BIT;
17097c478bdstevel@tonic-gate	}
17107c478bdstevel@tonic-gate
17117c478bdstevel@tonic-gate	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode",
171285025c0gd	    (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) {
171306673d9Garrett D'Amore		hmep->hme_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT;
17147c478bdstevel@tonic-gate	}
17157c478bdstevel@tonic-gate
17167c478bdstevel@tonic-gate	return (B_TRUE);
17177c478bdstevel@tonic-gate}
17187c478bdstevel@tonic-gate
17197c478bdstevel@tonic-gate/*
17207c478bdstevel@tonic-gate * Return 0 upon success, 1 on failure.
17217c478bdstevel@tonic-gate */
17227c478bdstevel@tonic-gatestatic uint_t
17237c478bdstevel@tonic-gatehmestop(struct hme *hmep)
17247c478bdstevel@tonic-gate{
17257c478bdstevel@tonic-gate	/*
17267c478bdstevel@tonic-gate	 * Disable the Tx dma engine.
17277c478bdstevel@tonic-gate	 */
17287c478bdstevel@tonic-gate	PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN));
17297c478bdstevel@tonic-gate	HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY);
17307c478bdstevel@tonic-gate
17317c478bdstevel@tonic-gate	/*
17327c478bdstevel@tonic-gate	 * Disable the Rx dma engine.
17337c478bdstevel@tonic-gate	 */
17347c478bdstevel@tonic-gate	PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN));
17357c478bdstevel@tonic-gate	HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY);
17367c478bdstevel@tonic-gate
17377c478bdstevel@tonic-gate	/*
17387c478bdstevel@tonic-gate	 * By this time all things should be quiet, so hit the
17397c478bdstevel@tonic-gate	 * chip with a reset.
17407c478bdstevel@tonic-gate	 */
17417c478bdstevel@tonic-gate	PUT_GLOBREG(reset, HMEG_RESET_GLOBAL);
17427c478bdstevel@tonic-gate
17437c478bdstevel@tonic-gate	HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY);
17447c478bdstevel@tonic-gate	if (GET_GLOBREG(reset)) {
17457c478bdstevel@tonic-gate		return (1);
17467c478bdstevel@tonic-gate	}
17477c478bdstevel@tonic-gate
17487c478bdstevel@tonic-gate	CHECK_GLOBREG();
17497c478bdstevel@tonic-gate	return (0);
17507c478bdstevel@tonic-gate}
17517c478bdstevel@tonic-gate
17527c478bdstevel@tonic-gatestatic int
17537c478bdstevel@tonic-gatehmestat_kstat_update(kstat_t *ksp, int rw)
17547c478bdstevel@tonic-gate{
17557c478bdstevel@tonic-gate	struct hme *hmep;
17567c478bdstevel@tonic-gate	struct hmekstat *hkp;
17577c478bdstevel@tonic-gate
17587c478bdstevel@tonic-gate	hmep = (struct hme *)ksp->ks_private;
17597c478bdstevel@tonic-gate	hkp = (struct hmekstat *)ksp->ks_data;
17607c478bdstevel@tonic-gate
176185025c0gd	if (rw != KSTAT_READ)
176285025c0gd		return (EACCES);
176385025c0gd
17647c478bdstevel@tonic-gate	/*
17657c478bdstevel@tonic-gate	 * Update all the stats by reading all the counter registers.
17667c478bdstevel@tonic-gate	 * Counter register stats are not updated till they overflow
17677c478bdstevel@tonic-gate	 * and interrupt.
17687c478bdstevel@tonic-gate	 */
17697c478bdstevel@tonic-gate
17707c478bdstevel@tonic-gate	mutex_enter(&hmep->hme_xmitlock);
17714dd87b6gd	if (hmep->hme_flags & HMERUNNING) {
17727c478bdstevel@tonic-gate		hmereclaim(hmep);
17734dd87b6gd		hmesavecntrs(hmep);
17744dd87b6gd	}
17757c478bdstevel@tonic-gate	mutex_exit(&hmep->hme_xmitlock);
17767c478bdstevel@tonic-gate
177785025c0gd	hkp->hk_cvc.value.ul		= hmep->hme_cvc;
177885025c0gd	hkp->hk_lenerr.value.ul		= hmep->hme_lenerr;
177985025c0gd	hkp->hk_buff.value.ul		= hmep->hme_buff;
178085025c0gd	hkp->hk_missed.value.ul		= hmep->hme_missed;
178185025c0gd	hkp->hk_allocbfail.value.ul	= hmep->hme_allocbfail;
178285025c0gd	hkp->hk_babl.value.ul		= hmep->hme_babl;
178385025c0gd	hkp->hk_tmder.value.ul		= hmep->hme_tmder;
178485025c0gd	hkp->hk_txlaterr.value.ul	= hmep->hme_txlaterr;
178585025c0gd	hkp->hk_rxlaterr.value.ul	= hmep->hme_rxlaterr;
178685025c0gd	hkp->hk_slvparerr.value.ul	= hmep->hme_slvparerr;
178785025c0gd	hkp->hk_txparerr.value.ul	= hmep->hme_txparerr;
178885025c0gd	hkp->hk_rxparerr.value.ul	=