xref: /onnv-gate/usr/src/uts/common/io/mxfe/mxfe.c (revision 11878:ac93462db6d7)
14978Sgd78059 /*
24978Sgd78059  * Solaris driver for ethernet cards based on the Macronix 98715
34978Sgd78059  *
44978Sgd78059  * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
54978Sgd78059  * All rights reserved.
64978Sgd78059  *
74978Sgd78059  * Redistribution and use in source and binary forms, with or without
84978Sgd78059  * modification, are permitted provided that the following conditions
94978Sgd78059  * are met:
104978Sgd78059  * 1. Redistributions of source code must retain the above copyright
114978Sgd78059  *    notice, this list of conditions and the following disclaimer.
124978Sgd78059  * 2. Redistributions in binary form must reproduce the above copyright
134978Sgd78059  *    notice, this list of conditions and the following disclaimer in the
144978Sgd78059  *    documentation and/or other materials provided with the distribution.
154978Sgd78059  * 3. Neither the name of the author nor the names of any co-contributors
164978Sgd78059  *    may be used to endorse or promote products derived from this software
174978Sgd78059  *    without specific prior written permission.
184978Sgd78059  *
194978Sgd78059  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
204978Sgd78059  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214978Sgd78059  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224978Sgd78059  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
234978Sgd78059  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244978Sgd78059  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254978Sgd78059  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264978Sgd78059  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274978Sgd78059  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284978Sgd78059  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294978Sgd78059  * POSSIBILITY OF SUCH DAMAGE.
304978Sgd78059  */
316684Sgd78059 /*
32*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
336684Sgd78059  * Use is subject to license terms.
346684Sgd78059  */
354978Sgd78059 
364978Sgd78059 
374978Sgd78059 #include <sys/varargs.h>
384978Sgd78059 #include <sys/types.h>
394978Sgd78059 #include <sys/modctl.h>
404978Sgd78059 #include <sys/conf.h>
414978Sgd78059 #include <sys/devops.h>
424978Sgd78059 #include <sys/stream.h>
434978Sgd78059 #include <sys/strsun.h>
444978Sgd78059 #include <sys/cmn_err.h>
454978Sgd78059 #include <sys/dlpi.h>
464978Sgd78059 #include <sys/ethernet.h>
474978Sgd78059 #include <sys/kmem.h>
484978Sgd78059 #include <sys/time.h>
494978Sgd78059 #include <sys/miiregs.h>
504978Sgd78059 #include <sys/strsun.h>
514978Sgd78059 #include <sys/mac.h>
524978Sgd78059 #include <sys/mac_ether.h>
534978Sgd78059 #include <sys/ddi.h>
544978Sgd78059 #include <sys/sunddi.h>
555895Syz147064 #include <sys/vlan.h>
564978Sgd78059 
574978Sgd78059 #include "mxfe.h"
584978Sgd78059 #include "mxfeimpl.h"
594978Sgd78059 
604978Sgd78059 /*
614978Sgd78059  * Driver globals.
624978Sgd78059  */
634978Sgd78059 
644978Sgd78059 /* patchable debug flag ... must not be static! */
654978Sgd78059 #ifdef	DEBUG
664978Sgd78059 unsigned		mxfe_debug = DWARN;
674978Sgd78059 #endif
684978Sgd78059 
694978Sgd78059 /* table of supported devices */
704978Sgd78059 static mxfe_card_t mxfe_cards[] = {
714978Sgd78059 
724978Sgd78059 	/*
734978Sgd78059 	 * Lite-On products
744978Sgd78059 	 */
754978Sgd78059 	{ 0x11ad, 0xc115, 0, 0, "Lite-On LC82C115", MXFE_PNICII },
764978Sgd78059 
774978Sgd78059 	/*
784978Sgd78059 	 * Macronix chips
794978Sgd78059 	 */
804978Sgd78059 	{ 0x10d9, 0x0531, 0x25, 0xff, "Macronix MX98715AEC", MXFE_98715AEC },
814978Sgd78059 	{ 0x10d9, 0x0531, 0x20, 0xff, "Macronix MX98715A", MXFE_98715A },
824978Sgd78059 	{ 0x10d9, 0x0531, 0x60, 0xff, "Macronix MX98715B", MXFE_98715B },
834978Sgd78059 	{ 0x10d9, 0x0531, 0x30, 0xff, "Macronix MX98725", MXFE_98725 },
844978Sgd78059 	{ 0x10d9, 0x0531, 0x00, 0xff, "Macronix MX98715", MXFE_98715 },
854978Sgd78059 	{ 0x10d9, 0x0512, 0, 0, "Macronix MX98713", MXFE_98713 },
864978Sgd78059 
874978Sgd78059 	/*
884978Sgd78059 	 * Compex (relabeled Macronix products)
894978Sgd78059 	 */
904978Sgd78059 	{ 0x11fc, 0x9881, 0x00, 0x00, "Compex 9881", MXFE_98713 },
914978Sgd78059 	{ 0x11fc, 0x9881, 0x10, 0xff, "Compex 9881A", MXFE_98713A },
924978Sgd78059 	/*
934978Sgd78059 	 * Models listed here
944978Sgd78059 	 */
954978Sgd78059 	{ 0x11ad, 0xc001, 0, 0, "Linksys LNE100TX", MXFE_PNICII },
964978Sgd78059 	{ 0x2646, 0x000b, 0, 0, "Kingston KNE111TX", MXFE_PNICII },
974978Sgd78059 	{ 0x1154, 0x0308, 0, 0, "Buffalo LGY-PCI-TXL", MXFE_98715AEC },
984978Sgd78059 };
994978Sgd78059 
1004978Sgd78059 #define	ETHERVLANMTU	(ETHERMAX + 4)
1014978Sgd78059 
1024978Sgd78059 /*
1034978Sgd78059  * Function prototypes
1044978Sgd78059  */
1054978Sgd78059 static int	mxfe_attach(dev_info_t *, ddi_attach_cmd_t);
1064978Sgd78059 static int	mxfe_detach(dev_info_t *, ddi_detach_cmd_t);
1074978Sgd78059 static int	mxfe_resume(dev_info_t *);
1089199Sgdamore@opensolaris.org static int	mxfe_quiesce(dev_info_t *);
1094978Sgd78059 static int	mxfe_m_unicst(void *, const uint8_t *);
1104978Sgd78059 static int	mxfe_m_multicst(void *, boolean_t, const uint8_t *);
1114978Sgd78059 static int	mxfe_m_promisc(void *, boolean_t);
1124978Sgd78059 static mblk_t	*mxfe_m_tx(void *, mblk_t *);
1134978Sgd78059 static int	mxfe_m_stat(void *, uint_t, uint64_t *);
1144978Sgd78059 static int	mxfe_m_start(void *);
1154978Sgd78059 static void	mxfe_m_stop(void *);
1166684Sgd78059 static int	mxfe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
117*11878SVenu.Iyer@Sun.COM     void *);
1186684Sgd78059 static int	mxfe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
1196684Sgd78059     const void *);
120*11878SVenu.Iyer@Sun.COM static void	mxfe_m_propinfo(void *, const char *, mac_prop_id_t,
121*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t);
1224978Sgd78059 static unsigned	mxfe_intr(caddr_t);
1234978Sgd78059 static void	mxfe_startmac(mxfe_t *);
1244978Sgd78059 static void	mxfe_stopmac(mxfe_t *);
1254978Sgd78059 static void	mxfe_resetrings(mxfe_t *);
1264978Sgd78059 static boolean_t	mxfe_initialize(mxfe_t *);
1274978Sgd78059 static void	mxfe_startall(mxfe_t *);
1284978Sgd78059 static void	mxfe_stopall(mxfe_t *);
1294978Sgd78059 static void	mxfe_resetall(mxfe_t *);
1304978Sgd78059 static mxfe_txbuf_t *mxfe_alloctxbuf(mxfe_t *);
1314978Sgd78059 static void	mxfe_destroytxbuf(mxfe_txbuf_t *);
1324978Sgd78059 static mxfe_rxbuf_t *mxfe_allocrxbuf(mxfe_t *);
1334978Sgd78059 static void	mxfe_destroyrxbuf(mxfe_rxbuf_t *);
1344978Sgd78059 static void	mxfe_send_setup(mxfe_t *);
1354978Sgd78059 static boolean_t	mxfe_send(mxfe_t *, mblk_t *);
1364978Sgd78059 static int	mxfe_allocrxring(mxfe_t *);
1374978Sgd78059 static void	mxfe_freerxring(mxfe_t *);
1384978Sgd78059 static int	mxfe_alloctxring(mxfe_t *);
1394978Sgd78059 static void	mxfe_freetxring(mxfe_t *);
1404978Sgd78059 static void	mxfe_error(dev_info_t *, char *, ...);
1414978Sgd78059 static uint8_t	mxfe_sromwidth(mxfe_t *);
1424978Sgd78059 static uint16_t	mxfe_readsromword(mxfe_t *, unsigned);
1434978Sgd78059 static void	mxfe_readsrom(mxfe_t *, unsigned, unsigned, void *);
1444978Sgd78059 static void	mxfe_getfactaddr(mxfe_t *, uchar_t *);
1456684Sgd78059 static uint8_t	mxfe_miireadbit(mxfe_t *);
1466684Sgd78059 static void	mxfe_miiwritebit(mxfe_t *, uint8_t);
1474978Sgd78059 static void	mxfe_miitristate(mxfe_t *);
1486684Sgd78059 static uint16_t	mxfe_miiread(mxfe_t *, int, int);
1494978Sgd78059 static void	mxfe_miiwrite(mxfe_t *, int, int, uint16_t);
1506684Sgd78059 static uint16_t	mxfe_miireadgeneral(mxfe_t *, int, int);
1514978Sgd78059 static void	mxfe_miiwritegeneral(mxfe_t *, int, int, uint16_t);
1526684Sgd78059 static uint16_t	mxfe_miiread98713(mxfe_t *, int, int);
1534978Sgd78059 static void	mxfe_miiwrite98713(mxfe_t *, int, int, uint16_t);
1544978Sgd78059 static void	mxfe_startphy(mxfe_t *);
1554978Sgd78059 static void	mxfe_stopphy(mxfe_t *);
1564978Sgd78059 static void	mxfe_startphymii(mxfe_t *);
1574978Sgd78059 static void	mxfe_startphynway(mxfe_t *);
1584978Sgd78059 static void	mxfe_startnway(mxfe_t *);
1594978Sgd78059 static void	mxfe_reportlink(mxfe_t *);
1604978Sgd78059 static void	mxfe_checklink(mxfe_t *);
1614978Sgd78059 static void	mxfe_checklinkmii(mxfe_t *);
1624978Sgd78059 static void	mxfe_checklinknway(mxfe_t *);
1634978Sgd78059 static void	mxfe_disableinterrupts(mxfe_t *);
1644978Sgd78059 static void	mxfe_enableinterrupts(mxfe_t *);
1654978Sgd78059 static void	mxfe_reclaim(mxfe_t *);
1669199Sgdamore@opensolaris.org static boolean_t	mxfe_receive(mxfe_t *, mblk_t **);
1674978Sgd78059 
1684978Sgd78059 #ifdef	DEBUG
1694978Sgd78059 static void	mxfe_dprintf(mxfe_t *, const char *, int, char *, ...);
1704978Sgd78059 #endif
1714978Sgd78059 
1724978Sgd78059 #define	KIOIP	KSTAT_INTR_PTR(mxfep->mxfe_intrstat)
1734978Sgd78059 
1744978Sgd78059 static mac_callbacks_t mxfe_m_callbacks = {
175*11878SVenu.Iyer@Sun.COM 	MC_SETPROP | MC_GETPROP | MC_PROPINFO,
1764978Sgd78059 	mxfe_m_stat,
1774978Sgd78059 	mxfe_m_start,
1784978Sgd78059 	mxfe_m_stop,
1794978Sgd78059 	mxfe_m_promisc,
1804978Sgd78059 	mxfe_m_multicst,
1814978Sgd78059 	mxfe_m_unicst,
1824978Sgd78059 	mxfe_m_tx,
183*11878SVenu.Iyer@Sun.COM 	NULL,
1846684Sgd78059 	NULL,		/* mc_ioctl */
1856684Sgd78059 	NULL,		/* mc_getcapab */
1866684Sgd78059 	NULL,		/* mc_open */
1876684Sgd78059 	NULL,		/* mc_close */
1886684Sgd78059 	mxfe_m_setprop,
189*11878SVenu.Iyer@Sun.COM 	mxfe_m_getprop,
190*11878SVenu.Iyer@Sun.COM 	mxfe_m_propinfo
1914978Sgd78059 };
1924978Sgd78059 
1934978Sgd78059 /*
1944978Sgd78059  * Stream information
1954978Sgd78059  */
1964978Sgd78059 DDI_DEFINE_STREAM_OPS(mxfe_devops, nulldev, nulldev, mxfe_attach, mxfe_detach,
1979199Sgdamore@opensolaris.org     nodev, NULL, D_MP, NULL, mxfe_quiesce);
1984978Sgd78059 
1994978Sgd78059 /*
2004978Sgd78059  * Module linkage information.
2014978Sgd78059  */
2024978Sgd78059 
2034978Sgd78059 static struct modldrv mxfe_modldrv = {
2044978Sgd78059 	&mod_driverops,			/* drv_modops */
2054978Sgd78059 	"Macronix Fast Ethernet",	/* drv_linkinfo */
2064978Sgd78059 	&mxfe_devops			/* drv_dev_ops */
2074978Sgd78059 };
2084978Sgd78059 
2094978Sgd78059 static struct modlinkage mxfe_modlinkage = {
2104978Sgd78059 	MODREV_1,		/* ml_rev */
2114978Sgd78059 	{ &mxfe_modldrv, NULL } /* ml_linkage */
2124978Sgd78059 };
2134978Sgd78059 
2144978Sgd78059 /*
2154978Sgd78059  * Device attributes.
2164978Sgd78059  */
2174978Sgd78059 static ddi_device_acc_attr_t mxfe_devattr = {
2184978Sgd78059 	DDI_DEVICE_ATTR_V0,
2194978Sgd78059 	DDI_STRUCTURE_LE_ACC,
2204978Sgd78059 	DDI_STRICTORDER_ACC
2214978Sgd78059 };
2224978Sgd78059 
2234978Sgd78059 static ddi_device_acc_attr_t mxfe_bufattr = {
2244978Sgd78059 	DDI_DEVICE_ATTR_V0,
2254978Sgd78059 	DDI_NEVERSWAP_ACC,
2264978Sgd78059 	DDI_STRICTORDER_ACC
2274978Sgd78059 };
2284978Sgd78059 
2294978Sgd78059 static ddi_dma_attr_t mxfe_dma_attr = {
2304978Sgd78059 	DMA_ATTR_V0,		/* dma_attr_version */
2314978Sgd78059 	0,			/* dma_attr_addr_lo */
2324978Sgd78059 	0xFFFFFFFFU,		/* dma_attr_addr_hi */
2334978Sgd78059 	0x7FFFFFFFU,		/* dma_attr_count_max */
2344978Sgd78059 	4,			/* dma_attr_align */
2354978Sgd78059 	0x3F,			/* dma_attr_burstsizes */
2364978Sgd78059 	1,			/* dma_attr_minxfer */
2374978Sgd78059 	0xFFFFFFFFU,		/* dma_attr_maxxfer */
2384978Sgd78059 	0xFFFFFFFFU,		/* dma_attr_seg */
2394978Sgd78059 	1,			/* dma_attr_sgllen */
2404978Sgd78059 	1,			/* dma_attr_granular */
2414978Sgd78059 	0			/* dma_attr_flags */
2424978Sgd78059 };
2434978Sgd78059 
2444978Sgd78059 /*
2454978Sgd78059  * Tx buffers can be arbitrarily aligned.  Additionally, they can
2464978Sgd78059  * cross a page boundary, so we use the two buffer addresses of the
2474978Sgd78059  * chip to provide a two-entry scatter-gather list.
2484978Sgd78059  */
2494978Sgd78059 static ddi_dma_attr_t mxfe_dma_txattr = {
2504978Sgd78059 	DMA_ATTR_V0,		/* dma_attr_version */
2514978Sgd78059 	0,			/* dma_attr_addr_lo */
2524978Sgd78059 	0xFFFFFFFFU,		/* dma_attr_addr_hi */
2534978Sgd78059 	0x7FFFFFFFU,		/* dma_attr_count_max */
2544978Sgd78059 	1,			/* dma_attr_align */
2554978Sgd78059 	0x3F,			/* dma_attr_burstsizes */
2564978Sgd78059 	1,			/* dma_attr_minxfer */
2574978Sgd78059 	0xFFFFFFFFU,		/* dma_attr_maxxfer */
2584978Sgd78059 	0xFFFFFFFFU,		/* dma_attr_seg */
2594978Sgd78059 	2,			/* dma_attr_sgllen */
2604978Sgd78059 	1,			/* dma_attr_granular */
2614978Sgd78059 	0			/* dma_attr_flags */
2624978Sgd78059 };
2634978Sgd78059 
2644978Sgd78059 /*
2654978Sgd78059  * Ethernet addresses.
2664978Sgd78059  */
2674978Sgd78059 static uchar_t mxfe_broadcast[ETHERADDRL] = {
2684978Sgd78059 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2694978Sgd78059 };
2704978Sgd78059 
2714978Sgd78059 /*
2724978Sgd78059  * DDI entry points.
2734978Sgd78059  */
2744978Sgd78059 int
_init(void)2754978Sgd78059 _init(void)
2764978Sgd78059 {
2774978Sgd78059 	int	rv;
2784978Sgd78059 	mac_init_ops(&mxfe_devops, "mxfe");
2794978Sgd78059 	if ((rv = mod_install(&mxfe_modlinkage)) != DDI_SUCCESS) {
2804978Sgd78059 		mac_fini_ops(&mxfe_devops);
2814978Sgd78059 	}
2824978Sgd78059 	return (rv);
2834978Sgd78059 }
2844978Sgd78059 
2854978Sgd78059 int
_fini(void)2864978Sgd78059 _fini(void)
2874978Sgd78059 {
2884978Sgd78059 	int	rv;
2894978Sgd78059 	if ((rv = mod_remove(&mxfe_modlinkage)) == DDI_SUCCESS) {
2904978Sgd78059 		mac_fini_ops(&mxfe_devops);
2914978Sgd78059 	}
2924978Sgd78059 	return (rv);
2934978Sgd78059 }
2944978Sgd78059 
2954978Sgd78059 int
_info(struct modinfo * modinfop)2964978Sgd78059 _info(struct modinfo *modinfop)
2974978Sgd78059 {
2984978Sgd78059 	return (mod_info(&mxfe_modlinkage, modinfop));
2994978Sgd78059 }
3004978Sgd78059 
3014978Sgd78059 int
mxfe_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3024978Sgd78059 mxfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3034978Sgd78059 {
3044978Sgd78059 	mxfe_t			*mxfep;
3054978Sgd78059 	mac_register_t		*macp;
3064978Sgd78059 	int			inst = ddi_get_instance(dip);
3074978Sgd78059 	ddi_acc_handle_t	pci;
3084978Sgd78059 	uint16_t		venid;
3094978Sgd78059 	uint16_t		devid;
3104978Sgd78059 	uint16_t		revid;
3114978Sgd78059 	uint16_t		svid;
3124978Sgd78059 	uint16_t		ssid;
3134978Sgd78059 	uint16_t		cachesize;
3144978Sgd78059 	mxfe_card_t		*cardp;
3154978Sgd78059 	int			i;
3164978Sgd78059 
3174978Sgd78059 	switch (cmd) {
3184978Sgd78059 	case DDI_RESUME:
3194978Sgd78059 		return (mxfe_resume(dip));
3204978Sgd78059 
3214978Sgd78059 	case DDI_ATTACH:
3224978Sgd78059 		break;
3234978Sgd78059 
3244978Sgd78059 	default:
3254978Sgd78059 		return (DDI_FAILURE);
3264978Sgd78059 	}
3274978Sgd78059 
3284978Sgd78059 	/* this card is a bus master, reject any slave-only slot */
3294978Sgd78059 	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
3304978Sgd78059 		mxfe_error(dip, "slot does not support PCI bus-master");
3314978Sgd78059 		return (DDI_FAILURE);
3324978Sgd78059 	}
3334978Sgd78059 	/* PCI devices shouldn't generate hilevel interrupts */
3344978Sgd78059 	if (ddi_intr_hilevel(dip, 0) != 0) {
3354978Sgd78059 		mxfe_error(dip, "hilevel interrupts not supported");
3364978Sgd78059 		return (DDI_FAILURE);
3374978Sgd78059 	}
3384978Sgd78059 	if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
3394978Sgd78059 		mxfe_error(dip, "unable to setup PCI config handle");
3404978Sgd78059 		return (DDI_FAILURE);
3414978Sgd78059 	}
3424978Sgd78059 
3434978Sgd78059 	venid = pci_config_get16(pci, PCI_VID);
3444978Sgd78059 	devid = pci_config_get16(pci, PCI_DID);
3454978Sgd78059 	revid = pci_config_get16(pci, PCI_RID);
3464978Sgd78059 	svid = pci_config_get16(pci, PCI_SVID);
3474978Sgd78059 	ssid = pci_config_get16(pci, PCI_SSID);
3484978Sgd78059 
3494978Sgd78059 	/*
3504978Sgd78059 	 * the last entry in the card table matches every possible
3514978Sgd78059 	 * card, so the for-loop always terminates properly.
3524978Sgd78059 	 */
3534978Sgd78059 	cardp = NULL;
3544978Sgd78059 	for (i = 0; i < (sizeof (mxfe_cards) / sizeof (mxfe_card_t)); i++) {
3554978Sgd78059 		if ((venid == mxfe_cards[i].card_venid) &&
3564978Sgd78059 		    (devid == mxfe_cards[i].card_devid) &&
3574978Sgd78059 		    ((revid & mxfe_cards[i].card_revmask) ==
3584978Sgd78059 		    mxfe_cards[i].card_revid)) {
3594978Sgd78059 			cardp = &mxfe_cards[i];
3604978Sgd78059 		}
3614978Sgd78059 		if ((svid == mxfe_cards[i].card_venid) &&
3624978Sgd78059 		    (ssid == mxfe_cards[i].card_devid) &&
3634978Sgd78059 		    ((revid & mxfe_cards[i].card_revmask) ==
3644978Sgd78059 		    mxfe_cards[i].card_revid)) {
3654978Sgd78059 			cardp = &mxfe_cards[i];
3664978Sgd78059 			break;
3674978Sgd78059 		}
3684978Sgd78059 	}
3694978Sgd78059 
3704978Sgd78059 	if (cardp == NULL) {
3714978Sgd78059 		pci_config_teardown(&pci);
3724978Sgd78059 		mxfe_error(dip, "Unable to identify PCI card");
3734978Sgd78059 		return (DDI_FAILURE);
3744978Sgd78059 	}
3754978Sgd78059 
3764978Sgd78059 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
3774978Sgd78059 	    cardp->card_cardname) != DDI_PROP_SUCCESS) {
3784978Sgd78059 		pci_config_teardown(&pci);
3794978Sgd78059 		mxfe_error(dip, "Unable to create model property");
3804978Sgd78059 		return (DDI_FAILURE);
3814978Sgd78059 	}
3824978Sgd78059 
3834978Sgd78059 	/*
3844978Sgd78059 	 * Grab the PCI cachesize -- we use this to program the
3854978Sgd78059 	 * cache-optimization bus access bits.
3864978Sgd78059 	 */
3874978Sgd78059 	cachesize = pci_config_get8(pci, PCI_CLS);
3884978Sgd78059 
3894978Sgd78059 	/* this cannot fail */
3904978Sgd78059 	mxfep = kmem_zalloc(sizeof (mxfe_t), KM_SLEEP);
3914978Sgd78059 	ddi_set_driver_private(dip, mxfep);
3924978Sgd78059 
3934978Sgd78059 	/* get the interrupt block cookie */
3944978Sgd78059 	if (ddi_get_iblock_cookie(dip, 0, &mxfep->mxfe_icookie)
3954978Sgd78059 	    != DDI_SUCCESS) {
3964978Sgd78059 		mxfe_error(dip, "ddi_get_iblock_cookie failed");
3974978Sgd78059 		pci_config_teardown(&pci);
3984978Sgd78059 		kmem_free(mxfep, sizeof (mxfe_t));
3994978Sgd78059 		return (DDI_FAILURE);
4004978Sgd78059 	}
4014978Sgd78059 
4024978Sgd78059 	mxfep->mxfe_dip = dip;
4034978Sgd78059 	mxfep->mxfe_cardp = cardp;
4044978Sgd78059 	mxfep->mxfe_phyaddr = -1;
4054978Sgd78059 	mxfep->mxfe_cachesize = cachesize;
4064978Sgd78059 
4074978Sgd78059 	/* default properties */
4084978Sgd78059 	mxfep->mxfe_adv_aneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4094978Sgd78059 	    "adv_autoneg_cap", 1);
4104978Sgd78059 	mxfep->mxfe_adv_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4114978Sgd78059 	    "adv_100T4_cap", 1);
4124978Sgd78059 	mxfep->mxfe_adv_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4134978Sgd78059 	    "adv_100fdx_cap", 1);
4144978Sgd78059 	mxfep->mxfe_adv_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4154978Sgd78059 	    "adv_100hdx_cap", 1);
4164978Sgd78059 	mxfep->mxfe_adv_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4174978Sgd78059 	    "adv_10fdx_cap", 1);
4184978Sgd78059 	mxfep->mxfe_adv_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4194978Sgd78059 	    "adv_10hdx_cap", 1);
4204978Sgd78059 
4214978Sgd78059 	DBG(DPCI, "PCI vendor id = %x", venid);
4224978Sgd78059 	DBG(DPCI, "PCI device id = %x", devid);
4234978Sgd78059 	DBG(DPCI, "PCI revision id = %x", revid);
4244978Sgd78059 	DBG(DPCI, "PCI cachesize = %d", cachesize);
4254978Sgd78059 	DBG(DPCI, "PCI COMM = %x", pci_config_get8(pci, PCI_CMD));
4264978Sgd78059 	DBG(DPCI, "PCI STAT = %x", pci_config_get8(pci, PCI_STAT));
4274978Sgd78059 
4284978Sgd78059 	mutex_init(&mxfep->mxfe_xmtlock, NULL, MUTEX_DRIVER,
4294978Sgd78059 	    mxfep->mxfe_icookie);
4304978Sgd78059 	mutex_init(&mxfep->mxfe_intrlock, NULL, MUTEX_DRIVER,
4314978Sgd78059 	    mxfep->mxfe_icookie);
4324978Sgd78059 
4334978Sgd78059 	/*
4344978Sgd78059 	 * Enable bus master, IO space, and memory space accesses.
4354978Sgd78059 	 */
4364978Sgd78059 	pci_config_put16(pci, PCI_CMD,
4374978Sgd78059 	    pci_config_get16(pci, PCI_CMD) |
4384978Sgd78059 	    PCI_CMD_BME | PCI_CMD_MAE | PCI_CMD_MWIE);
4394978Sgd78059 
4404978Sgd78059 	/* we're done with this now, drop it */
4414978Sgd78059 	pci_config_teardown(&pci);
4424978Sgd78059 
4434978Sgd78059 	/*
4444978Sgd78059 	 * Initialize interrupt kstat.  This should not normally fail, since
4454978Sgd78059 	 * we don't use a persistent stat.  We do it this way to avoid having
4464978Sgd78059 	 * to test for it at run time on the hot path.
4474978Sgd78059 	 */
4484978Sgd78059 	mxfep->mxfe_intrstat = kstat_create("mxfe", inst, "intr", "controller",
4494978Sgd78059 	    KSTAT_TYPE_INTR, 1, 0);
4504978Sgd78059 	if (mxfep->mxfe_intrstat == NULL) {
4514978Sgd78059 		mxfe_error(dip, "kstat_create failed");
4524978Sgd78059 		goto failed;
4534978Sgd78059 	}
4544978Sgd78059 	kstat_install(mxfep->mxfe_intrstat);
4554978Sgd78059 
4564978Sgd78059 	/*
4574978Sgd78059 	 * Map in the device registers.
4584978Sgd78059 	 */
4594978Sgd78059 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mxfep->mxfe_regs,
4604978Sgd78059 	    0, 0, &mxfe_devattr, &mxfep->mxfe_regshandle)) {
4614978Sgd78059 		mxfe_error(dip, "ddi_regs_map_setup failed");
4624978Sgd78059 		goto failed;
4634978Sgd78059 	}
4644978Sgd78059 
4654978Sgd78059 	/*
4664978Sgd78059 	 * Allocate DMA resources (descriptor rings and buffers).
4674978Sgd78059 	 */
4684978Sgd78059 	if ((mxfe_allocrxring(mxfep) != DDI_SUCCESS) ||
4694978Sgd78059 	    (mxfe_alloctxring(mxfep) != DDI_SUCCESS)) {
4704978Sgd78059 		mxfe_error(dip, "unable to allocate DMA resources");
4714978Sgd78059 		goto failed;
4724978Sgd78059 	}
4734978Sgd78059 
4744978Sgd78059 	/* Initialize the chip. */
4754978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
4764978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
4774978Sgd78059 	if (!mxfe_initialize(mxfep)) {
4784978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
4794978Sgd78059 		mutex_exit(&mxfep->mxfe_intrlock);
4804978Sgd78059 		goto failed;
4814978Sgd78059 	}
4824978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
4834978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
4844978Sgd78059 
4854978Sgd78059 	/* Determine the number of address bits to our EEPROM. */
4864978Sgd78059 	mxfep->mxfe_sromwidth = mxfe_sromwidth(mxfep);
4874978Sgd78059 
4884978Sgd78059 	/*
4894978Sgd78059 	 * Get the factory ethernet address.  This becomes the current
4904978Sgd78059 	 * ethernet address (it can be overridden later via ifconfig).
4914978Sgd78059 	 */
4924978Sgd78059 	mxfe_getfactaddr(mxfep, mxfep->mxfe_curraddr);
4934978Sgd78059 	mxfep->mxfe_promisc = B_FALSE;
4944978Sgd78059 
4954978Sgd78059 	/*
4964978Sgd78059 	 * Establish interrupt handler.
4974978Sgd78059 	 */
4984978Sgd78059 	if (ddi_add_intr(dip, 0, NULL, NULL, mxfe_intr, (caddr_t)mxfep) !=
4994978Sgd78059 	    DDI_SUCCESS) {
5004978Sgd78059 		mxfe_error(dip, "unable to add interrupt");
5014978Sgd78059 		goto failed;
5024978Sgd78059 	}
5034978Sgd78059 
5044978Sgd78059 	/* TODO: do the power management stuff */
5054978Sgd78059 
5064978Sgd78059 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
5074978Sgd78059 		mxfe_error(dip, "mac_alloc failed");
5084978Sgd78059 		goto failed;
5094978Sgd78059 	}
5104978Sgd78059 
5114978Sgd78059 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
5124978Sgd78059 	macp->m_driver = mxfep;
5134978Sgd78059 	macp->m_dip = dip;
5144978Sgd78059 	macp->m_src_addr = mxfep->mxfe_curraddr;
5154978Sgd78059 	macp->m_callbacks = &mxfe_m_callbacks;
5164978Sgd78059 	macp->m_min_sdu = 0;
5174978Sgd78059 	macp->m_max_sdu = ETHERMTU;
5185895Syz147064 	macp->m_margin = VLAN_TAGSZ;
5194978Sgd78059 
5204978Sgd78059 	if (mac_register(macp, &mxfep->mxfe_mh) == DDI_SUCCESS) {
5214978Sgd78059 		mac_free(macp);
5224978Sgd78059 		return (DDI_SUCCESS);
5234978Sgd78059 	}
5244978Sgd78059 
5254978Sgd78059 	/* failed to register with MAC */
5264978Sgd78059 	mac_free(macp);
5274978Sgd78059 failed:
5284978Sgd78059 	if (mxfep->mxfe_icookie != NULL) {
5294978Sgd78059 		ddi_remove_intr(dip, 0, mxfep->mxfe_icookie);
5304978Sgd78059 	}
5314978Sgd78059 	if (mxfep->mxfe_intrstat) {
5324978Sgd78059 		kstat_delete(mxfep->mxfe_intrstat);
5334978Sgd78059 	}
5344978Sgd78059 	mutex_destroy(&mxfep->mxfe_intrlock);
5354978Sgd78059 	mutex_destroy(&mxfep->mxfe_xmtlock);
5364978Sgd78059 
5374978Sgd78059 	mxfe_freerxring(mxfep);
5384978Sgd78059 	mxfe_freetxring(mxfep);
5394978Sgd78059 
5404978Sgd78059 	if (mxfep->mxfe_regshandle != NULL) {
5414978Sgd78059 		ddi_regs_map_free(&mxfep->mxfe_regshandle);
5424978Sgd78059 	}
5434978Sgd78059 	kmem_free(mxfep, sizeof (mxfe_t));
5444978Sgd78059 	return (DDI_FAILURE);
5454978Sgd78059 }
5464978Sgd78059 
5474978Sgd78059 int
mxfe_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)5484978Sgd78059 mxfe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5494978Sgd78059 {
5504978Sgd78059 	mxfe_t		*mxfep;
5514978Sgd78059 
5524978Sgd78059 	mxfep = ddi_get_driver_private(dip);
5534978Sgd78059 	if (mxfep == NULL) {
5544978Sgd78059 		mxfe_error(dip, "no soft state in detach!");
5554978Sgd78059 		return (DDI_FAILURE);
5564978Sgd78059 	}
5574978Sgd78059 
5584978Sgd78059 	switch (cmd) {
5594978Sgd78059 	case DDI_DETACH:
5604978Sgd78059 
5614978Sgd78059 		if (mac_unregister(mxfep->mxfe_mh) != 0) {
5624978Sgd78059 			return (DDI_FAILURE);
5634978Sgd78059 		}
5644978Sgd78059 
5654978Sgd78059 		/* make sure hardware is quiesced */
5664978Sgd78059 		mutex_enter(&mxfep->mxfe_intrlock);
5674978Sgd78059 		mutex_enter(&mxfep->mxfe_xmtlock);
5684978Sgd78059 		mxfep->mxfe_flags &= ~MXFE_RUNNING;
5694978Sgd78059 		mxfe_stopall(mxfep);
5704978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
5714978Sgd78059 		mutex_exit(&mxfep->mxfe_intrlock);
5724978Sgd78059 
5734978Sgd78059 		/* clean up and shut down device */
5744978Sgd78059 		ddi_remove_intr(dip, 0, mxfep->mxfe_icookie);
5754978Sgd78059 
5764978Sgd78059 		/* clean up kstats */
5774978Sgd78059 		kstat_delete(mxfep->mxfe_intrstat);
5784978Sgd78059 
5794978Sgd78059 		ddi_prop_remove_all(dip);
5804978Sgd78059 
5814978Sgd78059 		/* free up any left over buffers or DMA resources */
5824978Sgd78059 		mxfe_freerxring(mxfep);
5834978Sgd78059 		mxfe_freetxring(mxfep);
5844978Sgd78059 
5854978Sgd78059 		ddi_regs_map_free(&mxfep->mxfe_regshandle);
5864978Sgd78059 		mutex_destroy(&mxfep->mxfe_intrlock);
5874978Sgd78059 		mutex_destroy(&mxfep->mxfe_xmtlock);
5884978Sgd78059 
5894978Sgd78059 		kmem_free(mxfep, sizeof (mxfe_t));
5904978Sgd78059 		return (DDI_SUCCESS);
5914978Sgd78059 
5924978Sgd78059 	case DDI_SUSPEND:
5934978Sgd78059 		/* quiesce the hardware */
5944978Sgd78059 		mutex_enter(&mxfep->mxfe_intrlock);
5954978Sgd78059 		mutex_enter(&mxfep->mxfe_xmtlock);
5964978Sgd78059 		mxfep->mxfe_flags |= MXFE_SUSPENDED;
5974978Sgd78059 		mxfe_stopall(mxfep);
5984978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
5994978Sgd78059 		mutex_exit(&mxfep->mxfe_intrlock);
6004978Sgd78059 		return (DDI_SUCCESS);
6014978Sgd78059 	default:
6024978Sgd78059 		return (DDI_FAILURE);
6034978Sgd78059 	}
6044978Sgd78059 }
6054978Sgd78059 
6064978Sgd78059 int
mxfe_resume(dev_info_t * dip)6074978Sgd78059 mxfe_resume(dev_info_t *dip)
6084978Sgd78059 {
6094978Sgd78059 	mxfe_t		*mxfep;
6104978Sgd78059 
6114978Sgd78059 	if ((mxfep = ddi_get_driver_private(dip)) == NULL) {
6124978Sgd78059 		return (DDI_FAILURE);
6134978Sgd78059 	}
6144978Sgd78059 
6154978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
6164978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
6174978Sgd78059 
6184978Sgd78059 	mxfep->mxfe_flags &= ~MXFE_SUSPENDED;
6194978Sgd78059 
6204978Sgd78059 	/* re-initialize chip */
6214978Sgd78059 	if (!mxfe_initialize(mxfep)) {
6224978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "unable to resume chip!");
6234978Sgd78059 		mxfep->mxfe_flags |= MXFE_SUSPENDED;
6244978Sgd78059 		mutex_exit(&mxfep->mxfe_intrlock);
6254978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
6264978Sgd78059 		return (DDI_SUCCESS);
6274978Sgd78059 	}
6284978Sgd78059 
6294978Sgd78059 	/* start the chip */
6304978Sgd78059 	if (mxfep->mxfe_flags & MXFE_RUNNING) {
6314978Sgd78059 		mxfe_startall(mxfep);
6324978Sgd78059 	}
6334978Sgd78059 
6344978Sgd78059 	/* drop locks */
6354978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
6364978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
6374978Sgd78059 
6384978Sgd78059 	return (DDI_SUCCESS);
6394978Sgd78059 }
6404978Sgd78059 
6419199Sgdamore@opensolaris.org int
mxfe_quiesce(dev_info_t * dip)6429199Sgdamore@opensolaris.org mxfe_quiesce(dev_info_t *dip)
6439199Sgdamore@opensolaris.org {
6449199Sgdamore@opensolaris.org 	mxfe_t	*mxfep;
6459199Sgdamore@opensolaris.org 
6469199Sgdamore@opensolaris.org 	if ((mxfep = ddi_get_driver_private(dip)) == NULL) {
6479199Sgdamore@opensolaris.org 		return (DDI_FAILURE);
6489199Sgdamore@opensolaris.org 	}
6499199Sgdamore@opensolaris.org 
6509199Sgdamore@opensolaris.org 	/* just do a hard reset of everything */
6519199Sgdamore@opensolaris.org 	SETBIT(mxfep, CSR_PAR, PAR_RESET);
6529199Sgdamore@opensolaris.org 
6539199Sgdamore@opensolaris.org 	return (DDI_SUCCESS);
6549199Sgdamore@opensolaris.org }
6559199Sgdamore@opensolaris.org 
6564978Sgd78059 /*ARGSUSED*/
6574978Sgd78059 int
mxfe_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)6584978Sgd78059 mxfe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
6594978Sgd78059 {
6604978Sgd78059 	/* we already receive all multicast frames */
6614978Sgd78059 	return (0);
6624978Sgd78059 }
6634978Sgd78059 
6644978Sgd78059 int
mxfe_m_promisc(void * arg,boolean_t on)6654978Sgd78059 mxfe_m_promisc(void *arg, boolean_t on)
6664978Sgd78059 {
6674978Sgd78059 	mxfe_t		*mxfep = arg;
6684978Sgd78059 
6694978Sgd78059 	/* exclusive access to the card while we reprogram it */
6704978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
6714978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
6724978Sgd78059 	/* save current promiscuous mode state for replay in resume */
6734978Sgd78059 	mxfep->mxfe_promisc = on;
6744978Sgd78059 
6754978Sgd78059 	if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) ==
6764978Sgd78059 	    MXFE_RUNNING) {
6774978Sgd78059 		if (on)
6784978Sgd78059 			SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
6794978Sgd78059 		else
6804978Sgd78059 			CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
6814978Sgd78059 	}
6824978Sgd78059 
6834978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
6844978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
6854978Sgd78059 
6864978Sgd78059 	return (0);
6874978Sgd78059 }
6884978Sgd78059 
6894978Sgd78059 int
mxfe_m_unicst(void * arg,const uint8_t * macaddr)6904978Sgd78059 mxfe_m_unicst(void *arg, const uint8_t *macaddr)
6914978Sgd78059 {
6924978Sgd78059 	mxfe_t		*mxfep = arg;
6934978Sgd78059 
6944978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
6954978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
6964978Sgd78059 	bcopy(macaddr, mxfep->mxfe_curraddr, ETHERADDRL);
6974978Sgd78059 
6984978Sgd78059 	mxfe_resetall(mxfep);
6994978Sgd78059 
7004978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
7014978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
7024978Sgd78059 
7034978Sgd78059 	return (0);
7044978Sgd78059 }
7054978Sgd78059 
7064978Sgd78059 mblk_t *
mxfe_m_tx(void * arg,mblk_t * mp)7074978Sgd78059 mxfe_m_tx(void *arg, mblk_t *mp)
7084978Sgd78059 {
7094978Sgd78059 	mxfe_t	*mxfep = arg;
7104978Sgd78059 	mblk_t	*nmp;
7114978Sgd78059 
7124978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
7134978Sgd78059 
7144978Sgd78059 	if (mxfep->mxfe_flags & MXFE_SUSPENDED) {
7154978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
7164978Sgd78059 		return (mp);
7174978Sgd78059 	}
7184978Sgd78059 
7194978Sgd78059 	while (mp != NULL) {
7204978Sgd78059 		nmp = mp->b_next;
7214978Sgd78059 		mp->b_next = NULL;
7224978Sgd78059 
7234978Sgd78059 		if (!mxfe_send(mxfep, mp)) {
7244978Sgd78059 			mp->b_next = nmp;
7254978Sgd78059 			break;
7264978Sgd78059 		}
7274978Sgd78059 		mp = nmp;
7284978Sgd78059 	}
7294978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
7304978Sgd78059 
7314978Sgd78059 	return (mp);
7324978Sgd78059 }
7334978Sgd78059 
7344978Sgd78059 /*
7354978Sgd78059  * Hardware management.
7364978Sgd78059  */
7374978Sgd78059 boolean_t
mxfe_initialize(mxfe_t * mxfep)7384978Sgd78059 mxfe_initialize(mxfe_t *mxfep)
7394978Sgd78059 {
7404978Sgd78059 	int		i;
7414978Sgd78059 	unsigned	val;
7424978Sgd78059 	uint32_t	par, nar;
7434978Sgd78059 
7444978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
7454978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
7464978Sgd78059 
7474978Sgd78059 	DBG(DCHATTY, "resetting!");
7484978Sgd78059 	SETBIT(mxfep, CSR_PAR, PAR_RESET);
7494978Sgd78059 	for (i = 1; i < 10; i++) {
7504978Sgd78059 		drv_usecwait(5);
7514978Sgd78059 		val = GETCSR(mxfep, CSR_PAR);
7524978Sgd78059 		if (!(val & PAR_RESET)) {
7534978Sgd78059 			break;
7544978Sgd78059 		}
7554978Sgd78059 	}
7564978Sgd78059 	if (i == 10) {
7574978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "timed out waiting for reset!");
7584978Sgd78059 		return (B_FALSE);
7594978Sgd78059 	}
7604978Sgd78059 
7614978Sgd78059 	/* initialize busctl register */
7624978Sgd78059 	par = PAR_BAR | PAR_MRME | PAR_MRLE | PAR_MWIE;
7634978Sgd78059 
7644978Sgd78059 	/* set the cache alignment if its supported */
7654978Sgd78059 	switch (mxfep->mxfe_cachesize) {
7664978Sgd78059 	case 8:
7674978Sgd78059 		par |= PAR_CALIGN_8;
7684978Sgd78059 		break;
7694978Sgd78059 	case 16:
7704978Sgd78059 		par |= PAR_CALIGN_16;
7714978Sgd78059 		break;
7724978Sgd78059 	case 32:
7734978Sgd78059 		par |= PAR_CALIGN_32;
7744978Sgd78059 		break;
7754978Sgd78059 	default:
7764978Sgd78059 		par &= ~(PAR_MWIE | PAR_MRME | PAR_MRLE);
7774978Sgd78059 	}
7784978Sgd78059 
7794978Sgd78059 	/* leave the burst length at zero, indicating infinite burst */
7804978Sgd78059 	PUTCSR(mxfep, CSR_PAR, par);
7814978Sgd78059 
7824978Sgd78059 	mxfe_resetrings(mxfep);
7834978Sgd78059 
7844978Sgd78059 	/* clear the lost packet counter (cleared on read) */
7854978Sgd78059 	(void) GETCSR(mxfep, CSR_LPC);
7864978Sgd78059 
7874978Sgd78059 	/* a few other NAR bits */
7884978Sgd78059 	nar = GETCSR(mxfep, CSR_NAR);
7894978Sgd78059 	nar &= ~NAR_RX_HO;	/* disable hash only filtering */
7904978Sgd78059 	nar |= NAR_RX_HP;	/* hash perfect forwarding */
7914978Sgd78059 	nar |= NAR_RX_MULTI;	/* receive all multicast */
7924978Sgd78059 	nar |= NAR_SF;	/* store-and-forward */
7934978Sgd78059 
7944978Sgd78059 	if (mxfep->mxfe_promisc) {
7954978Sgd78059 		nar |= NAR_RX_PROMISC;
7964978Sgd78059 	} else {
7974978Sgd78059 		nar &= ~NAR_RX_PROMISC;
7984978Sgd78059 	}
7994978Sgd78059 	PUTCSR(mxfep, CSR_NAR, nar);
8004978Sgd78059 
8014978Sgd78059 	mxfe_send_setup(mxfep);
8024978Sgd78059 
8034978Sgd78059 	return (B_TRUE);
8044978Sgd78059 }
8054978Sgd78059 
8064978Sgd78059 /*
8074978Sgd78059  * Serial EEPROM access - inspired by the FreeBSD implementation.
8084978Sgd78059  */
8094978Sgd78059 
8104978Sgd78059 uint8_t
mxfe_sromwidth(mxfe_t * mxfep)8114978Sgd78059 mxfe_sromwidth(mxfe_t *mxfep)
8124978Sgd78059 {
8134978Sgd78059 	int		i;
8144978Sgd78059 	int		eeread;
8154978Sgd78059 	uint8_t		addrlen = 8;
8164978Sgd78059 
8174978Sgd78059 	eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
8184978Sgd78059 
8194978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
8204978Sgd78059 	drv_usecwait(1);
8214978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread);
8224978Sgd78059 
8234978Sgd78059 	/* command bits first */
8244978Sgd78059 	for (i = 4; i != 0; i >>= 1) {
8254978Sgd78059 		unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0;
8264978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread | val);
8274978Sgd78059 		drv_usecwait(1);
8284978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
8294978Sgd78059 		drv_usecwait(1);
8304978Sgd78059 	}
8314978Sgd78059 
8324978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread);
8334978Sgd78059 
8344978Sgd78059 	for (addrlen = 1; addrlen <= 12; addrlen++) {
8354978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK);
8364978Sgd78059 		drv_usecwait(1);
8374978Sgd78059 		if (!(GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT)) {
8384978Sgd78059 			PUTCSR(mxfep, CSR_SPR, eeread);
8394978Sgd78059 			drv_usecwait(1);
8404978Sgd78059 			break;
8414978Sgd78059 		}
8424978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread);
8434978Sgd78059 		drv_usecwait(1);
8444978Sgd78059 	}
8454978Sgd78059 
8464978Sgd78059 	/* turn off accesses to the EEPROM */
8474978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
8484978Sgd78059 
8494978Sgd78059 	DBG(DSROM, "detected srom width = %d bits", addrlen);
8504978Sgd78059 
8514978Sgd78059 	return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen);
8524978Sgd78059 }
8534978Sgd78059 
8544978Sgd78059 /*
8554978Sgd78059  * The words in EEPROM are stored in little endian order.  We
8564978Sgd78059  * shift bits out in big endian order, though.  This requires
8574978Sgd78059  * a byte swap on some platforms.
8584978Sgd78059  */
8594978Sgd78059 uint16_t
mxfe_readsromword(mxfe_t * mxfep,unsigned romaddr)8604978Sgd78059 mxfe_readsromword(mxfe_t *mxfep, unsigned romaddr)
8614978Sgd78059 {
8624978Sgd78059 	int		i;
8634978Sgd78059 	uint16_t	word = 0;
8644978Sgd78059 	uint16_t	retval;
8654978Sgd78059 	int		eeread;
8664978Sgd78059 	uint8_t		addrlen;
8674978Sgd78059 	int		readcmd;
8684978Sgd78059 	uchar_t		*ptr;
8694978Sgd78059 
8704978Sgd78059 	eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
8714978Sgd78059 	addrlen = mxfep->mxfe_sromwidth;
8724978Sgd78059 	readcmd = (SROM_READCMD << addrlen) | romaddr;
8734978Sgd78059 
8744978Sgd78059 	if (romaddr >= (1 << addrlen)) {
8754978Sgd78059 		/* too big to fit! */
8764978Sgd78059 		return (0);
8774978Sgd78059 	}
8784978Sgd78059 
8794978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
8804978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread);
8814978Sgd78059 
8824978Sgd78059 	/* command and address bits */
8834978Sgd78059 	for (i = 4 + addrlen; i >= 0; i--) {
8844978Sgd78059 		short val = (readcmd & (1 << i)) ?  SPR_SROM_DIN : 0;
8854978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread | val);
8864978Sgd78059 		drv_usecwait(1);
8874978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
8884978Sgd78059 		drv_usecwait(1);
8894978Sgd78059 	}
8904978Sgd78059 
8914978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread);
8924978Sgd78059 
8934978Sgd78059 	for (i = 0; i < 16; i++) {
8944978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread | SPR_SROM_CLOCK);
8954978Sgd78059 		drv_usecwait(1);
8964978Sgd78059 		word <<= 1;
8974978Sgd78059 		if (GETCSR(mxfep, CSR_SPR) & SPR_SROM_DOUT) {
8984978Sgd78059 			word |= 1;
8994978Sgd78059 		}
9004978Sgd78059 		PUTCSR(mxfep, CSR_SPR, eeread);
9014978Sgd78059 		drv_usecwait(1);
9024978Sgd78059 	}
9034978Sgd78059 
9044978Sgd78059 	/* turn off accesses to the EEPROM */
9054978Sgd78059 	PUTCSR(mxfep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
9064978Sgd78059 
9074978Sgd78059 	/*
9084978Sgd78059 	 * Fix up the endianness thing.  Note that the values
9094978Sgd78059 	 * are stored in little endian format on the SROM.
9104978Sgd78059 	 */
9114978Sgd78059 	DBG(DSROM, "got value %d from SROM (before swap)", word);
9124978Sgd78059 	ptr = (uchar_t *)&word;
9134978Sgd78059 	retval = (ptr[1] << 8) | ptr[0];
9144978Sgd78059 	return (retval);
9154978Sgd78059 }
9164978Sgd78059 
9174978Sgd78059 void
mxfe_readsrom(mxfe_t * mxfep,unsigned romaddr,unsigned len,void * dest)9184978Sgd78059 mxfe_readsrom(mxfe_t *mxfep, unsigned romaddr, unsigned len, void *dest)
9194978Sgd78059 {
9204978Sgd78059 	char		*ptr = dest;
9214978Sgd78059 	int		i;
9224978Sgd78059 	uint16_t	word;
9234978Sgd78059 
9244978Sgd78059 	for (i = 0; i < len; i++) {
9254978Sgd78059 		word = mxfe_readsromword(mxfep, romaddr + i);
9264978Sgd78059 		bcopy(&word, ptr, 2);
9274978Sgd78059 		ptr += 2;
9284978Sgd78059 		DBG(DSROM, "word at %d is 0x%x", romaddr + i, word);
9294978Sgd78059 	}
9304978Sgd78059 }
9314978Sgd78059 
9324978Sgd78059 void
mxfe_getfactaddr(mxfe_t * mxfep,uchar_t * eaddr)9334978Sgd78059 mxfe_getfactaddr(mxfe_t *mxfep, uchar_t *eaddr)
9344978Sgd78059 {
9354978Sgd78059 	uint16_t	word;
9364978Sgd78059 	uchar_t		*ptr;
9374978Sgd78059 
9384978Sgd78059 	/* first read to get the location of mac address in srom */
9394978Sgd78059 	word = mxfe_readsromword(mxfep, SROM_ENADDR / 2);
9404978Sgd78059 	ptr = (uchar_t *)&word;
9414978Sgd78059 	word = (ptr[1] << 8) | ptr[0];
9424978Sgd78059 
9434978Sgd78059 	/* then read the actual mac address */
9444978Sgd78059 	mxfe_readsrom(mxfep, word / 2, ETHERADDRL / 2, eaddr);
9454978Sgd78059 	DBG(DMACID,
9464978Sgd78059 	    "factory ethernet address = %02x:%02x:%02x:%02x:%02x:%02x",
9474978Sgd78059 	    eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
9484978Sgd78059 }
9494978Sgd78059 
9504978Sgd78059 void
mxfe_startphy(mxfe_t * mxfep)9514978Sgd78059 mxfe_startphy(mxfe_t *mxfep)
9524978Sgd78059 {
9534978Sgd78059 	switch (MXFE_MODEL(mxfep)) {
9544978Sgd78059 	case MXFE_98713A:
9554978Sgd78059 		mxfe_startphymii(mxfep);
9564978Sgd78059 		break;
9574978Sgd78059 	default:
9584978Sgd78059 		mxfe_startphynway(mxfep);
9594978Sgd78059 		break;
9604978Sgd78059 	}
9614978Sgd78059 }
9624978Sgd78059 
9634978Sgd78059 void
mxfe_stopphy(mxfe_t * mxfep)9644978Sgd78059 mxfe_stopphy(mxfe_t *mxfep)
9654978Sgd78059 {
9664978Sgd78059 	uint32_t	nar;
9674978Sgd78059 	int		i;
9684978Sgd78059 
9694978Sgd78059 	/* stop the phy timer */
9704978Sgd78059 	PUTCSR(mxfep, CSR_TIMER, 0);
9714978Sgd78059 
9724978Sgd78059 	switch (MXFE_MODEL(mxfep)) {
9734978Sgd78059 	case MXFE_98713A:
9744978Sgd78059 		for (i = 0; i < 32; i++) {
9754978Sgd78059 			mxfe_miiwrite(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL,
9764978Sgd78059 			    MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
9774978Sgd78059 		}
9784978Sgd78059 		break;
9794978Sgd78059 	default:
9804978Sgd78059 		DBG(DPHY, "resetting SIA");
9814978Sgd78059 		PUTCSR(mxfep, CSR_SIA, SIA_RESET);
9824978Sgd78059 		drv_usecwait(500);
9834978Sgd78059 		CLRBIT(mxfep, CSR_TCTL, TCTL_PWR | TCTL_ANE);
9844978Sgd78059 		nar = GETCSR(mxfep, CSR_NAR);
9854978Sgd78059 		nar &= ~(NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX);
9864978Sgd78059 		nar |= NAR_SPEED;
9874978Sgd78059 		PUTCSR(mxfep, CSR_NAR, nar);
9884978Sgd78059 		break;
9894978Sgd78059 	}
9904978Sgd78059 
9914978Sgd78059 	/*
9924978Sgd78059 	 * mark the link state unknown
9934978Sgd78059 	 */
9944978Sgd78059 	if (!mxfep->mxfe_resetting) {
9954978Sgd78059 		mxfep->mxfe_linkup = LINK_STATE_UNKNOWN;
9964978Sgd78059 		mxfep->mxfe_ifspeed = 0;
9974978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
9984978Sgd78059 		if (mxfep->mxfe_flags & MXFE_RUNNING)
9994978Sgd78059 			mxfe_reportlink(mxfep);
10004978Sgd78059 	}
10014978Sgd78059 }
10024978Sgd78059 
10034978Sgd78059 /*
10044978Sgd78059  * NWay support.
10054978Sgd78059  */
10064978Sgd78059 void
mxfe_startnway(mxfe_t * mxfep)10074978Sgd78059 mxfe_startnway(mxfe_t *mxfep)
10084978Sgd78059 {
10094978Sgd78059 	unsigned	nar;
10104978Sgd78059 	unsigned	tctl;
10114978Sgd78059 	unsigned	restart;
10124978Sgd78059 
10134978Sgd78059 	/* this should not happen in a healthy system */
10146684Sgd78059 	if (mxfep->mxfe_nwaystate != MXFE_NOLINK) {
10154978Sgd78059 		DBG(DWARN, "link start called out of state (%x)",
10166684Sgd78059 		    mxfep->mxfe_nwaystate);
10174978Sgd78059 		return;
10184978Sgd78059 	}
10194978Sgd78059 
10204978Sgd78059 	if (mxfep->mxfe_adv_aneg == 0) {
10214978Sgd78059 		/* not done for forced mode */
10224978Sgd78059 		return;
10234978Sgd78059 	}
10244978Sgd78059 
10254978Sgd78059 	nar = GETCSR(mxfep, CSR_NAR);
10264978Sgd78059 	restart = nar & (NAR_TX_ENABLE | NAR_RX_ENABLE);
10274978Sgd78059 	nar &= ~restart;
10284978Sgd78059 
10294978Sgd78059 	if (restart != 0)
10304978Sgd78059 		mxfe_stopmac(mxfep);
10314978Sgd78059 
10324978Sgd78059 	nar |= NAR_SCR | NAR_PCS | NAR_HBD;
10334978Sgd78059 	nar &= ~(NAR_FDX);
10344978Sgd78059 
10354978Sgd78059 	tctl = GETCSR(mxfep, CSR_TCTL);
10364978Sgd78059 	tctl &= ~(TCTL_100FDX | TCTL_100HDX | TCTL_HDX);
10374978Sgd78059 
10384978Sgd78059 	if (mxfep->mxfe_adv_100fdx) {
10394978Sgd78059 		tctl |= TCTL_100FDX;
10404978Sgd78059 	}
10414978Sgd78059 	if (mxfep->mxfe_adv_100hdx) {
10424978Sgd78059 		tctl |= TCTL_100HDX;
10434978Sgd78059 	}
10444978Sgd78059 	if (mxfep->mxfe_adv_10fdx) {
10454978Sgd78059 		nar |= NAR_FDX;
10464978Sgd78059 	}
10474978Sgd78059 	if (mxfep->mxfe_adv_10hdx) {
10484978Sgd78059 		tctl |= TCTL_HDX;
10494978Sgd78059 	}
10504978Sgd78059 	tctl |= TCTL_PWR | TCTL_ANE | TCTL_LTE | TCTL_RSQ;
10514978Sgd78059 
10524978Sgd78059 	/* possibly we should add in support for PAUSE frames */
10534978Sgd78059 	DBG(DPHY, "writing nar = 0x%x", nar);
10544978Sgd78059 	PUTCSR(mxfep, CSR_NAR, nar);
10554978Sgd78059 
10564978Sgd78059 	DBG(DPHY, "writing tctl = 0x%x", tctl);
10574978Sgd78059 	PUTCSR(mxfep, CSR_TCTL, tctl);
10584978Sgd78059 
10594978Sgd78059 	/* restart autonegotation */
10604978Sgd78059 	DBG(DPHY, "writing tstat = 0x%x", TSTAT_ANS_START);
10614978Sgd78059 	PUTCSR(mxfep, CSR_TSTAT, TSTAT_ANS_START);
10624978Sgd78059 
10634978Sgd78059 	/* restart tx/rx processes... */
10644978Sgd78059 	if (restart != 0)
10654978Sgd78059 		mxfe_startmac(mxfep);
10664978Sgd78059 
10674978Sgd78059 	/* Macronix initializations from Bolo Tsai */
10684978Sgd78059 	PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000);
10694978Sgd78059 	PUTCSR(mxfep, CSR_ACOMP, 0x11000);
10704978Sgd78059 
10716684Sgd78059 	mxfep->mxfe_nwaystate = MXFE_NWAYCHECK;
10724978Sgd78059 }
10734978Sgd78059 
10744978Sgd78059 void
mxfe_checklinknway(mxfe_t * mxfep)10754978Sgd78059 mxfe_checklinknway(mxfe_t *mxfep)
10764978Sgd78059 {
10776684Sgd78059 	unsigned	tstat;
10786684Sgd78059 	uint16_t	lpar;
10796684Sgd78059 
10806684Sgd78059 	DBG(DPHY, "NWay check, state %x", mxfep->mxfe_nwaystate);
10814978Sgd78059 	tstat = GETCSR(mxfep, CSR_TSTAT);
10824978Sgd78059 	lpar = TSTAT_LPAR(tstat);
10834978Sgd78059 
10844978Sgd78059 	mxfep->mxfe_anlpar = lpar;
10854978Sgd78059 	if (tstat & TSTAT_LPN) {
10864978Sgd78059 		mxfep->mxfe_aner |= MII_AN_EXP_LPCANAN;
10874978Sgd78059 	} else {
10884978Sgd78059 		mxfep->mxfe_aner &= ~(MII_AN_EXP_LPCANAN);
10894978Sgd78059 	}
10904978Sgd78059 
10914978Sgd78059 	DBG(DPHY, "tstat(CSR12) = 0x%x", tstat);
10924978Sgd78059 	DBG(DPHY, "ANEG state = 0x%x", (tstat & TSTAT_ANS) >> 12);
10934978Sgd78059 
10944978Sgd78059 	if ((tstat & TSTAT_ANS) != TSTAT_ANS_OK) {
10954978Sgd78059 		/* autoneg did not complete */
10964978Sgd78059 		mxfep->mxfe_bmsr &= ~MII_STATUS_ANDONE;
10974978Sgd78059 	} else {
10984978Sgd78059 		mxfep->mxfe_bmsr |= ~MII_STATUS_ANDONE;
10994978Sgd78059 	}
11004978Sgd78059 
11014978Sgd78059 	if ((tstat & TSTAT_100F) && (tstat & TSTAT_10F)) {
11024978Sgd78059 		mxfep->mxfe_linkup = LINK_STATE_DOWN;
11034978Sgd78059 		mxfep->mxfe_ifspeed = 0;
11044978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
11056684Sgd78059 		mxfep->mxfe_nwaystate = MXFE_NOLINK;
11064978Sgd78059 		mxfe_reportlink(mxfep);
11074978Sgd78059 		mxfe_startnway(mxfep);
11084978Sgd78059 		return;
11094978Sgd78059 	}
11104978Sgd78059 
11114978Sgd78059 	/*
11124978Sgd78059 	 * if the link is newly up, then we might need to set various
11134978Sgd78059 	 * mode bits, or negotiate for parameters, etc.
11144978Sgd78059 	 */
11154978Sgd78059 	if (mxfep->mxfe_adv_aneg) {
11164978Sgd78059 
11174978Sgd78059 		uint16_t	anlpar;
11184978Sgd78059 
11194978Sgd78059 		mxfep->mxfe_linkup = LINK_STATE_UP;
11204978Sgd78059 		anlpar = mxfep->mxfe_anlpar;
11214978Sgd78059 
11224978Sgd78059 		if (tstat & TSTAT_LPN) {
11234978Sgd78059 			/* partner has NWay */
11244978Sgd78059 
11254978Sgd78059 			if ((anlpar & MII_ABILITY_100BASE_TX_FD) &&
11264978Sgd78059 			    mxfep->mxfe_adv_100fdx) {
11274978Sgd78059 				mxfep->mxfe_ifspeed = 100000000;
11284978Sgd78059 				mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11294978Sgd78059 			} else if ((anlpar & MII_ABILITY_100BASE_TX) &&
11304978Sgd78059 			    mxfep->mxfe_adv_100hdx) {
11314978Sgd78059 				mxfep->mxfe_ifspeed = 100000000;
11324978Sgd78059 				mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11334978Sgd78059 			} else if ((anlpar & MII_ABILITY_10BASE_T_FD) &&
11344978Sgd78059 			    mxfep->mxfe_adv_10fdx) {
11354978Sgd78059 				mxfep->mxfe_ifspeed = 10000000;
11364978Sgd78059 				mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11374978Sgd78059 			} else if ((anlpar & MII_ABILITY_10BASE_T) &&
11384978Sgd78059 			    mxfep->mxfe_adv_10hdx) {
11394978Sgd78059 				mxfep->mxfe_ifspeed = 10000000;
11404978Sgd78059 				mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11414978Sgd78059 			} else {
11424978Sgd78059 				mxfep->mxfe_ifspeed = 0;
11434978Sgd78059 			}
11444978Sgd78059 		} else {
11454978Sgd78059 			/* link partner does not have NWay */
11464978Sgd78059 			/* just assume half duplex, since we can't detect */
11474978Sgd78059 			mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11484978Sgd78059 			if (!(tstat & TSTAT_100F)) {
11494978Sgd78059 				DBG(DPHY, "Partner doesn't have NWAY");
11504978Sgd78059 				mxfep->mxfe_ifspeed = 100000000;
11514978Sgd78059 			} else {
11524978Sgd78059 				mxfep->mxfe_ifspeed = 10000000;
11534978Sgd78059 			}
11544978Sgd78059 		}
11554978Sgd78059 	} else {
11564978Sgd78059 		/* forced modes */
11574978Sgd78059 		mxfep->mxfe_linkup = LINK_STATE_UP;
11584978Sgd78059 		if (mxfep->mxfe_adv_100fdx) {
11594978Sgd78059 			mxfep->mxfe_ifspeed = 100000000;
11604978Sgd78059 			mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11614978Sgd78059 		} else if (mxfep->mxfe_adv_100hdx) {
11624978Sgd78059 			mxfep->mxfe_ifspeed = 100000000;
11634978Sgd78059 			mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11644978Sgd78059 		} else if (mxfep->mxfe_adv_10fdx) {
11654978Sgd78059 			mxfep->mxfe_ifspeed = 10000000;
11664978Sgd78059 			mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
11674978Sgd78059 		} else if (mxfep->mxfe_adv_10hdx) {
11684978Sgd78059 			mxfep->mxfe_ifspeed = 10000000;
11694978Sgd78059 			mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
11704978Sgd78059 		} else {
11714978Sgd78059 			mxfep->mxfe_ifspeed = 0;
11724978Sgd78059 		}
11734978Sgd78059 	}
11744978Sgd78059 	mxfe_reportlink(mxfep);
11756684Sgd78059 	mxfep->mxfe_nwaystate = MXFE_GOODLINK;
11764978Sgd78059 }
11774978Sgd78059 
11784978Sgd78059 void
mxfe_startphynway(mxfe_t * mxfep)11794978Sgd78059 mxfe_startphynway(mxfe_t *mxfep)
11804978Sgd78059 {
11814978Sgd78059 	/* take NWay and PHY out of reset */
11824978Sgd78059 	PUTCSR(mxfep, CSR_SIA, SIA_NRESET);
11834978Sgd78059 	drv_usecwait(500);
11844978Sgd78059 
11856684Sgd78059 	mxfep->mxfe_nwaystate = MXFE_NOLINK;
11864978Sgd78059 	mxfep->mxfe_bmsr = MII_STATUS_CANAUTONEG |
11874978Sgd78059 	    MII_STATUS_100_BASEX_FD | MII_STATUS_100_BASEX |
11884978Sgd78059 	    MII_STATUS_10_FD | MII_STATUS_10;
11896684Sgd78059 	mxfep->mxfe_cap_aneg =
11906684Sgd78059 	    mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx =
11916684Sgd78059 	    mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1;
11924978Sgd78059 
11934978Sgd78059 	/* lie about the transceiver... its not really 802.3u compliant */
11944978Sgd78059 	mxfep->mxfe_phyaddr = 0;
11954978Sgd78059 	mxfep->mxfe_phyinuse = XCVR_100X;
11964978Sgd78059 	mxfep->mxfe_phyid = 0;
11974978Sgd78059 
11984978Sgd78059 	/* 100-T4 not supported with NWay */
11994978Sgd78059 	mxfep->mxfe_adv_100T4 = 0;
12006684Sgd78059 	mxfep->mxfe_cap_100T4 = 0;
12014978Sgd78059 
12024978Sgd78059 	/* make sure at least one valid mode is selected */
12034978Sgd78059 	if ((!mxfep->mxfe_adv_100fdx) &&
12044978Sgd78059 	    (!mxfep->mxfe_adv_100hdx) &&
12054978Sgd78059 	    (!mxfep->mxfe_adv_10fdx) &&
12064978Sgd78059 	    (!mxfep->mxfe_adv_10hdx)) {
12074978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "No valid link mode selected.");
12084978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "Powering down PHY.");
12094978Sgd78059 		mxfe_stopphy(mxfep);
12104978Sgd78059 		mxfep->mxfe_linkup = LINK_STATE_DOWN;
12114978Sgd78059 		if (mxfep->mxfe_flags & MXFE_RUNNING)
12124978Sgd78059 			mxfe_reportlink(mxfep);
12134978Sgd78059 		return;
12144978Sgd78059 	}
12154978Sgd78059 
12164978Sgd78059 	if (mxfep->mxfe_adv_aneg == 0) {
12174978Sgd78059 		/* forced mode */
12184978Sgd78059 		unsigned	nar;
12194978Sgd78059 		unsigned	tctl;
12204978Sgd78059 
12214978Sgd78059 		nar = GETCSR(mxfep, CSR_NAR);
12224978Sgd78059 		tctl = GETCSR(mxfep, CSR_TCTL);
12234978Sgd78059 
12244978Sgd78059 		ASSERT((nar & (NAR_TX_ENABLE | NAR_RX_ENABLE)) == 0);
12254978Sgd78059 
12264978Sgd78059 		nar &= ~(NAR_FDX | NAR_PORTSEL | NAR_SCR | NAR_SPEED);
12274978Sgd78059 		tctl &= ~TCTL_ANE;
12284978Sgd78059 		if (mxfep->mxfe_adv_100fdx) {
12294978Sgd78059 			nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR | NAR_FDX;
12304978Sgd78059 		} else if (mxfep->mxfe_adv_100hdx) {
12314978Sgd78059 			nar |= NAR_PORTSEL | NAR_PCS | NAR_SCR;
12324978Sgd78059 		} else if (mxfep->mxfe_adv_10fdx) {
12334978Sgd78059 			nar |= NAR_FDX | NAR_SPEED;
12344978Sgd78059 		} else { /* mxfep->mxfe_adv_10hdx */
12354978Sgd78059 			nar |= NAR_SPEED;
12364978Sgd78059 		}
12374978Sgd78059 
12384978Sgd78059 		PUTCSR(mxfep, CSR_NAR, nar);
12394978Sgd78059 		PUTCSR(mxfep, CSR_TCTL, tctl);
12404978Sgd78059 
12414978Sgd78059 		/* Macronix initializations from Bolo Tsai */
12424978Sgd78059 		PUTCSR(mxfep, CSR_MXMAGIC, 0x0b2c0000);
12434978Sgd78059 		PUTCSR(mxfep, CSR_ACOMP, 0x11000);
12444978Sgd78059 	} else {
12454978Sgd78059 		mxfe_startnway(mxfep);
12464978Sgd78059 	}
12474978Sgd78059 	PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP |
12484978Sgd78059 	    (MXFE_LINKTIMER * 1000 / TIMER_USEC));
12494978Sgd78059 }
12504978Sgd78059 
12514978Sgd78059 /*
12524978Sgd78059  * MII management.
12534978Sgd78059  */
12544978Sgd78059 void
mxfe_startphymii(mxfe_t * mxfep)12554978Sgd78059 mxfe_startphymii(mxfe_t *mxfep)
12564978Sgd78059 {
12574978Sgd78059 	unsigned	phyaddr;
12584978Sgd78059 	unsigned	bmcr;
12594978Sgd78059 	unsigned	bmsr;
12604978Sgd78059 	unsigned	anar;
12614978Sgd78059 	unsigned	phyidr1;
12624978Sgd78059 	unsigned	phyidr2;
12634978Sgd78059 	int		retries;
12644978Sgd78059 	int		cnt;
12654978Sgd78059 
12664978Sgd78059 	mxfep->mxfe_phyaddr = -1;
12674978Sgd78059 
12684978Sgd78059 	/* search for first PHY we can find */
12694978Sgd78059 	for (phyaddr = 0; phyaddr < 32; phyaddr++) {
12704978Sgd78059 		bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS);
12714978Sgd78059 		if ((bmsr != 0) && (bmsr != 0xffff)) {
12724978Sgd78059 			mxfep->mxfe_phyaddr = phyaddr;
12734978Sgd78059 			break;
12744978Sgd78059 		}
12754978Sgd78059 	}
12764978Sgd78059 
12774978Sgd78059 	phyidr1 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDH);
12784978Sgd78059 	phyidr2 = mxfe_miiread(mxfep, phyaddr, MII_PHYIDL);
12794978Sgd78059 	mxfep->mxfe_phyid = (phyidr1 << 16) | (phyidr2);
12804978Sgd78059 
12814978Sgd78059 	/*
12824978Sgd78059 	 * Generally, all Macronix based devices use an internal
12834978Sgd78059 	 * 100BASE-TX internal transceiver.  If we ever run into a
12844978Sgd78059 	 * variation on this, then the following logic will need to be
12854978Sgd78059 	 * enhanced.
12864978Sgd78059 	 *
12874978Sgd78059 	 * One could question the value of the XCVR_INUSE field in the
12884978Sgd78059 	 * MII statistics.
12894978Sgd78059 	 */
12904978Sgd78059 	if (bmsr & MII_STATUS_100_BASE_T4) {
12914978Sgd78059 		mxfep->mxfe_phyinuse = XCVR_100T4;
12924978Sgd78059 	} else {
12934978Sgd78059 		mxfep->mxfe_phyinuse = XCVR_100X;
12944978Sgd78059 	}
12954978Sgd78059 
12966684Sgd78059 	/* assume we support everything to start */
12976684Sgd78059 	mxfep->mxfe_cap_aneg = mxfep->mxfe_cap_100T4 =
12986684Sgd78059 	    mxfep->mxfe_cap_100fdx = mxfep->mxfe_cap_100hdx =
12996684Sgd78059 	    mxfep->mxfe_cap_10fdx = mxfep->mxfe_cap_10hdx = 1;
13006684Sgd78059 
13014978Sgd78059 	DBG(DPHY, "phy at %d: %x,%x", phyaddr, phyidr1, phyidr2);
13024978Sgd78059 	DBG(DPHY, "bmsr = %x", mxfe_miiread(mxfep,
13034978Sgd78059 	    mxfep->mxfe_phyaddr, MII_STATUS));
13044978Sgd78059 	DBG(DPHY, "anar = %x", mxfe_miiread(mxfep,
13054978Sgd78059 	    mxfep->mxfe_phyaddr, MII_AN_ADVERT));
13064978Sgd78059 	DBG(DPHY, "anlpar = %x", mxfe_miiread(mxfep,
13074978Sgd78059 	    mxfep->mxfe_phyaddr, MII_AN_LPABLE));
13084978Sgd78059 	DBG(DPHY, "aner = %x", mxfe_miiread(mxfep,
13094978Sgd78059 	    mxfep->mxfe_phyaddr, MII_AN_EXPANSION));
13104978Sgd78059 
13114978Sgd78059 	DBG(DPHY, "resetting phy");
13124978Sgd78059 
13134978Sgd78059 	/* we reset the phy block */
13144978Sgd78059 	mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, MII_CONTROL_RESET);
13154978Sgd78059 	/*
13164978Sgd78059 	 * wait for it to complete -- 500usec is still to short to
13174978Sgd78059 	 * bother getting the system clock involved.
13184978Sgd78059 	 */
13194978Sgd78059 	drv_usecwait(500);
13204978Sgd78059 	for (retries = 0; retries < 10; retries++) {
13214978Sgd78059 		if (mxfe_miiread(mxfep, phyaddr, MII_CONTROL) &
13224978Sgd78059 		    MII_CONTROL_RESET) {
13234978Sgd78059 			drv_usecwait(500);
13244978Sgd78059 			continue;
13254978Sgd78059 		}
13264978Sgd78059 		break;
13274978Sgd78059 	}
13284978Sgd78059 	if (retries == 100) {
13294978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "timeout waiting on phy to reset");
13304978Sgd78059 		return;
13314978Sgd78059 	}
13324978Sgd78059 
13334978Sgd78059 	DBG(DPHY, "phy reset complete");
13344978Sgd78059 
13354978Sgd78059 	bmsr = mxfe_miiread(mxfep, phyaddr, MII_STATUS);
13364978Sgd78059 	bmcr = mxfe_miiread(mxfep, phyaddr, MII_CONTROL);
13374978Sgd78059 	anar = mxfe_miiread(mxfep, phyaddr, MII_AN_ADVERT);
13384978Sgd78059 
13394978Sgd78059 	anar &= ~(MII_ABILITY_100BASE_T4 |
13404978Sgd78059 	    MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX |
13414978Sgd78059 	    MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T);
13424978Sgd78059 
13434978Sgd78059 	/* disable modes not supported in hardware */
13444978Sgd78059 	if (!(bmsr & MII_STATUS_100_BASE_T4)) {
13454978Sgd78059 		mxfep->mxfe_adv_100T4 = 0;
13466684Sgd78059 		mxfep->mxfe_cap_100T4 = 0;
13474978Sgd78059 	}
13484978Sgd78059 	if (!(bmsr & MII_STATUS_100_BASEX_FD)) {
13494978Sgd78059 		mxfep->mxfe_adv_100fdx = 0;
13506684Sgd78059 		mxfep->mxfe_cap_100fdx = 0;
13514978Sgd78059 	}
13524978Sgd78059 	if (!(bmsr & MII_STATUS_100_BASEX)) {
13534978Sgd78059 		mxfep->mxfe_adv_100hdx = 0;
13546684Sgd78059 		mxfep->mxfe_cap_100hdx = 0;
13554978Sgd78059 	}
13564978Sgd78059 	if (!(bmsr & MII_STATUS_10_FD)) {
13574978Sgd78059 		mxfep->mxfe_adv_10fdx = 0;
13586684Sgd78059 		mxfep->mxfe_cap_10fdx = 0;
13594978Sgd78059 	}
13604978Sgd78059 	if (!(bmsr & MII_STATUS_10)) {
13614978Sgd78059 		mxfep->mxfe_adv_10hdx = 0;
13626684Sgd78059 		mxfep->mxfe_cap_10hdx = 0;
13634978Sgd78059 	}
13644978Sgd78059 	if (!(bmsr & MII_STATUS_CANAUTONEG)) {
13654978Sgd78059 		mxfep->mxfe_adv_aneg = 0;
13666684Sgd78059 		mxfep->mxfe_cap_aneg = 0;
13674978Sgd78059 	}
13684978Sgd78059 
13694978Sgd78059 	cnt = 0;
13704978Sgd78059 	if (mxfep->mxfe_adv_100T4) {
13714978Sgd78059 		anar |= MII_ABILITY_100BASE_T4;
13724978Sgd78059 		cnt++;
13734978Sgd78059 	}
13744978Sgd78059 	if (mxfep->mxfe_adv_100fdx) {
13754978Sgd78059 		anar |= MII_ABILITY_100BASE_TX_FD;
13764978Sgd78059 		cnt++;
13774978Sgd78059 	}
13784978Sgd78059 	if (mxfep->mxfe_adv_100hdx) {
13794978Sgd78059 		anar |= MII_ABILITY_100BASE_TX;
13804978Sgd78059 		cnt++;
13814978Sgd78059 	}
13824978Sgd78059 	if (mxfep->mxfe_adv_10fdx) {
13834978Sgd78059 		anar |= MII_ABILITY_10BASE_T_FD;
13844978Sgd78059 		cnt++;
13854978Sgd78059 	}
13864978Sgd78059 	if (mxfep->mxfe_adv_10hdx) {
13874978Sgd78059 		anar |= MII_ABILITY_10BASE_T;
13884978Sgd78059 		cnt++;
13894978Sgd78059 	}
13904978Sgd78059 
13914978Sgd78059 	/*
13924978Sgd78059 	 * Make certain at least one valid link mode is selected.
13934978Sgd78059 	 */
13944978Sgd78059 	if (!cnt) {
13954978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "No valid link mode selected.");
13964978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "Powering down PHY.");
13974978Sgd78059 		mxfe_stopphy(mxfep);
13984978Sgd78059 		mxfep->mxfe_linkup = LINK_STATE_DOWN;
13994978Sgd78059 		if (mxfep->mxfe_flags & MXFE_RUNNING)
14004978Sgd78059 			mxfe_reportlink(mxfep);
14014978Sgd78059 		return;
14024978Sgd78059 	}
14034978Sgd78059 
14044978Sgd78059 	if ((mxfep->mxfe_adv_aneg) && (bmsr & MII_STATUS_CANAUTONEG)) {
14054978Sgd78059 		DBG(DPHY, "using autoneg mode");
14064978Sgd78059 		bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN);
14074978Sgd78059 	} else {
14084978Sgd78059 		DBG(DPHY, "using forced mode");
14094978Sgd78059 		if (mxfep->mxfe_adv_100fdx) {
14104978Sgd78059 			bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
14114978Sgd78059 		} else if (mxfep->mxfe_adv_100hdx) {
14124978Sgd78059 			bmcr = MII_CONTROL_100MB;
14134978Sgd78059 		} else if (mxfep->mxfe_adv_10fdx) {
14144978Sgd78059 			bmcr = MII_CONTROL_FDUPLEX;
14154978Sgd78059 		} else {
14164978Sgd78059 			/* 10HDX */
14174978Sgd78059 			bmcr = 0;
14184978Sgd78059 		}
14194978Sgd78059 	}
14204978Sgd78059 
14214978Sgd78059 	DBG(DPHY, "programming anar to 0x%x", anar);
14224978Sgd78059 	mxfe_miiwrite(mxfep, phyaddr, MII_AN_ADVERT, anar);
14234978Sgd78059 	DBG(DPHY, "programming bmcr to 0x%x", bmcr);
14244978Sgd78059 	mxfe_miiwrite(mxfep, phyaddr, MII_CONTROL, bmcr);
14254978Sgd78059 
14264978Sgd78059 	/*
14274978Sgd78059 	 * schedule a query of the link status
14284978Sgd78059 	 */
14294978Sgd78059 	PUTCSR(mxfep, CSR_TIMER, TIMER_LOOP |
14304978Sgd78059 	    (MXFE_LINKTIMER * 1000 / TIMER_USEC));
14314978Sgd78059 }
14324978Sgd78059 
14334978Sgd78059 void
mxfe_reportlink(mxfe_t * mxfep)14344978Sgd78059 mxfe_reportlink(mxfe_t *mxfep)
14354978Sgd78059 {
14364978Sgd78059 	int changed = 0;
14374978Sgd78059 
14384978Sgd78059 	if (mxfep->mxfe_ifspeed != mxfep->mxfe_lastifspeed) {
14394978Sgd78059 		mxfep->mxfe_lastifspeed = mxfep->mxfe_ifspeed;
14404978Sgd78059 		changed++;
14414978Sgd78059 	}
14424978Sgd78059 	if (mxfep->mxfe_duplex != mxfep->mxfe_lastduplex) {
14434978Sgd78059 		mxfep->mxfe_lastduplex = mxfep->mxfe_duplex;
14444978Sgd78059 		changed++;
14454978Sgd78059 	}
14464978Sgd78059 	if (mxfep->mxfe_linkup != mxfep->mxfe_lastlinkup) {
14474978Sgd78059 		mxfep->mxfe_lastlinkup = mxfep->mxfe_linkup;
14484978Sgd78059 		changed++;
14494978Sgd78059 	}
14504978Sgd78059 	if (changed)
14514978Sgd78059 		mac_link_update(mxfep->mxfe_mh, mxfep->mxfe_linkup);
14524978Sgd78059 }
14534978Sgd78059 
14544978Sgd78059 void
mxfe_checklink(mxfe_t * mxfep)14554978Sgd78059 mxfe_checklink(mxfe_t *mxfep)
14564978Sgd78059 {
14574978Sgd78059 	if ((mxfep->mxfe_flags & MXFE_RUNNING) == 0)
14584978Sgd78059 		return;
14594978Sgd78059 
14604978Sgd78059 	if ((mxfep->mxfe_txstall_time != 0) &&
14614978Sgd78059 	    (gethrtime() > mxfep->mxfe_txstall_time) &&
14624978Sgd78059 	    (mxfep->mxfe_txavail != MXFE_TXRING)) {
14634978Sgd78059 		mxfep->mxfe_txstall_time = 0;
14644978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "TX stall detected!");
14654978Sgd78059 		mxfe_resetall(mxfep);
14664978Sgd78059 		return;
14674978Sgd78059 	}
14684978Sgd78059 
14694978Sgd78059 	switch (MXFE_MODEL(mxfep)) {
14704978Sgd78059 	case MXFE_98713A:
14714978Sgd78059 		mxfe_checklinkmii(mxfep);
14724978Sgd78059 		break;
14734978Sgd78059 	default:
14744978Sgd78059 		mxfe_checklinknway(mxfep);
14754978Sgd78059 	}
14764978Sgd78059 }
14774978Sgd78059 
14784978Sgd78059 void
mxfe_checklinkmii(mxfe_t * mxfep)14794978Sgd78059 mxfe_checklinkmii(mxfe_t *mxfep)
14804978Sgd78059 {
14814978Sgd78059 	/* read MII state registers */
14824978Sgd78059 	uint16_t 	bmsr;
14834978Sgd78059 	uint16_t 	bmcr;
14844978Sgd78059 	uint16_t 	anar;
14854978Sgd78059 	uint16_t 	anlpar;
14864978Sgd78059 	uint16_t 	aner;
14874978Sgd78059 
14884978Sgd78059 	/* read this twice, to clear latched link state */
14894978Sgd78059 	bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS);
14904978Sgd78059 	bmsr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_STATUS);
14914978Sgd78059 	bmcr = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_CONTROL);
14924978Sgd78059 	anar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_ADVERT);
14934978Sgd78059 	anlpar = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_LPABLE);
14944978Sgd78059 	aner = mxfe_miiread(mxfep, mxfep->mxfe_phyaddr, MII_AN_EXPANSION);
14954978Sgd78059 
14964978Sgd78059 	mxfep->mxfe_bmsr = bmsr;
14974978Sgd78059 	mxfep->mxfe_anlpar = anlpar;
14984978Sgd78059 	mxfep->mxfe_aner = aner;
14994978Sgd78059 
15004978Sgd78059 	if (bmsr & MII_STATUS_REMFAULT) {
15014978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "Remote fault detected.");
15024978Sgd78059 	}
15034978Sgd78059 	if (bmsr & MII_STATUS_JABBERING) {
15044978Sgd78059 		mxfe_error(mxfep->mxfe_dip, "Jabber condition detected.");
15054978Sgd78059 	}
15064978Sgd78059 	if ((bmsr & MII_STATUS_LINKUP) == 0) {
15074978Sgd78059 		/* no link */
15084978Sgd78059 		mxfep->mxfe_ifspeed = 0;
15094978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
15104978Sgd78059 		mxfep->mxfe_linkup = LINK_STATE_DOWN;
15114978Sgd78059 		mxfe_reportlink(mxfep);
15124978Sgd78059 		return;
15134978Sgd78059 	}
15144978Sgd78059 
15154978Sgd78059 	DBG(DCHATTY, "link up!");
15164978Sgd78059 	mxfep->mxfe_linkup = LINK_STATE_UP;
15174978Sgd78059 
15184978Sgd78059 	if (!(bmcr & MII_CONTROL_ANE)) {
15194978Sgd78059 		/* forced mode */
15204978Sgd78059 		if (bmcr & MII_CONTROL_100MB) {
15214978Sgd78059 			mxfep->mxfe_ifspeed = 100000000;
15224978Sgd78059 		} else {
15234978Sgd78059 			mxfep->mxfe_ifspeed = 10000000;
15244978Sgd78059 		}
15254978Sgd78059 		if (bmcr & MII_CONTROL_FDUPLEX) {
15264978Sgd78059 			mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
15274978Sgd78059 		} else {
15284978Sgd78059 			mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15294978Sgd78059 		}
15304978Sgd78059 	} else if ((!(bmsr & MII_STATUS_CANAUTONEG)) ||
15314978Sgd78059 	    (!(bmsr & MII_STATUS_ANDONE))) {
15324978Sgd78059 		mxfep->mxfe_ifspeed = 0;
15334978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
15344978Sgd78059 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) {
15354978Sgd78059 		mxfep->mxfe_ifspeed = 100000000;
15364978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
15374978Sgd78059 	} else if (anar & anlpar & MII_ABILITY_100BASE_T4) {
15384978Sgd78059 		mxfep->mxfe_ifspeed = 100000000;
15394978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15404978Sgd78059 	} else if (anar & anlpar & MII_ABILITY_100BASE_TX) {
15414978Sgd78059 		mxfep->mxfe_ifspeed = 100000000;
15424978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15434978Sgd78059 	} else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) {
15444978Sgd78059 		mxfep->mxfe_ifspeed = 10000000;
15454978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_FULL;
15464978Sgd78059 	} else if (anar & anlpar & MII_ABILITY_10BASE_T) {
15474978Sgd78059 		mxfep->mxfe_ifspeed = 10000000;
15484978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_HALF;
15494978Sgd78059 	} else {
15504978Sgd78059 		mxfep->mxfe_ifspeed = 0;
15514978Sgd78059 		mxfep->mxfe_duplex = LINK_DUPLEX_UNKNOWN;
15524978Sgd78059 	}
15534978Sgd78059 
15544978Sgd78059 	mxfe_reportlink(mxfep);
15554978Sgd78059 }
15564978Sgd78059 
15574978Sgd78059 void
mxfe_miitristate(mxfe_t * mxfep)15584978Sgd78059 mxfe_miitristate(mxfe_t *mxfep)
15594978Sgd78059 {
15604978Sgd78059 	unsigned val = SPR_SROM_WRITE | SPR_MII_CTRL;
15614978Sgd78059 	PUTCSR(mxfep, CSR_SPR, val);
15624978Sgd78059 	drv_usecwait(1);
15634978Sgd78059 	PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
15644978Sgd78059 	drv_usecwait(1);
15654978Sgd78059 }
15664978Sgd78059 
15674978Sgd78059 void
mxfe_miiwritebit(mxfe_t * mxfep,uint8_t bit)15686684Sgd78059 mxfe_miiwritebit(mxfe_t *mxfep, uint8_t bit)
15694978Sgd78059 {
15704978Sgd78059 	unsigned val = bit ? SPR_MII_DOUT : 0;
15714978Sgd78059 	PUTCSR(mxfep, CSR_SPR, val);
15724978Sgd78059 	drv_usecwait(1);
15734978Sgd78059 	PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
15744978Sgd78059 	drv_usecwait(1);
15754978Sgd78059 }
15764978Sgd78059 
15776684Sgd78059 uint8_t
mxfe_miireadbit(mxfe_t * mxfep)15784978Sgd78059 mxfe_miireadbit(mxfe_t *mxfep)
15794978Sgd78059 {
15804978Sgd78059 	unsigned val = SPR_MII_CTRL | SPR_SROM_READ;
15816684Sgd78059 	uint8_t bit;
15824978Sgd78059 	PUTCSR(mxfep, CSR_SPR, val);
15834978Sgd78059 	drv_usecwait(1);
15844978Sgd78059 	bit = (GETCSR(mxfep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0;
15854978Sgd78059 	PUTCSR(mxfep, CSR_SPR, val | SPR_MII_CLOCK);
15864978Sgd78059 	drv_usecwait(1);
15874978Sgd78059 	return (bit);
15884978Sgd78059 }
15894978Sgd78059 
15906684Sgd78059 uint16_t
mxfe_miiread(mxfe_t * mxfep,int phy,int reg)15914978Sgd78059 mxfe_miiread(mxfe_t *mxfep, int phy, int reg)
15924978Sgd78059 {
15934978Sgd78059 	switch (MXFE_MODEL(mxfep)) {
15944978Sgd78059 	case MXFE_98713A:
15954978Sgd78059 		return (mxfe_miiread98713(mxfep, phy, reg));
15964978Sgd78059 	default:
15974978Sgd78059 		return (0xffff);
15984978Sgd78059 	}
15994978Sgd78059 }
16004978Sgd78059 
16016684Sgd78059 uint16_t
mxfe_miireadgeneral(mxfe_t * mxfep,int phy,int reg)16024978Sgd78059 mxfe_miireadgeneral(mxfe_t *mxfep, int phy, int reg)
16034978Sgd78059 {
16046684Sgd78059 	uint16_t	value = 0;
16054978Sgd78059 	int		i;
16064978Sgd78059 
16074978Sgd78059 	/* send the 32 bit preamble */
16084978Sgd78059 	for (i = 0; i < 32; i++) {
16094978Sgd78059 		mxfe_miiwritebit(mxfep, 1);
16104978Sgd78059 	}
16114978Sgd78059 
16124978Sgd78059 	/* send the start code - 01b */
16134978Sgd78059 	mxfe_miiwritebit(mxfep, 0);
16144978Sgd78059 	mxfe_miiwritebit(mxfep, 1);
16154978Sgd78059 
16164978Sgd78059 	/* send the opcode for read, - 10b */
16174978Sgd78059 	mxfe_miiwritebit(mxfep, 1);
16184978Sgd78059 	mxfe_miiwritebit(mxfep, 0);
16194978Sgd78059 
16204978Sgd78059 	/* next we send the 5 bit phy address */
16214978Sgd78059 	for (i = 0x10; i > 0; i >>= 1) {
16224978Sgd78059 		mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0);
16234978Sgd78059 	}
16244978Sgd78059 
16254978Sgd78059 	/* the 5 bit register address goes next */
16264978Sgd78059 	for (i = 0x10; i > 0; i >>= 1) {
16274978Sgd78059 		mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0);
16284978Sgd78059 	}
16294978Sgd78059 
16304978Sgd78059 	/* turnaround - tristate followed by logic 0 */
16314978Sgd78059 	mxfe_miitristate(mxfep);
16324978Sgd78059 	mxfe_miiwritebit(mxfep, 0);
16334978Sgd78059 
16344978Sgd78059 	/* read the 16 bit register value */
16354978Sgd78059 	for (i = 0x8000; i > 0; i >>= 1) {
16364978Sgd78059 		value <<= 1;
16374978Sgd78059 		value |= mxfe_miireadbit(mxfep);
16384978Sgd78059 	}
16394978Sgd78059 	mxfe_miitristate(mxfep);
16404978Sgd78059 	return (value);
16414978Sgd78059 }
16424978Sgd78059 
16436684Sgd78059 uint16_t
mxfe_miiread98713(mxfe_t * mxfep,int phy,int reg)16444978Sgd78059 mxfe_miiread98713(mxfe_t *mxfep, int phy, int reg)
16454978Sgd78059 {
16464978Sgd78059 	unsigned nar;
16476684Sgd78059 	uint16_t retval;
16484978Sgd78059 	/*
16494978Sgd78059 	 * like an ordinary MII, but we have to turn off portsel while
16504978Sgd78059 	 * we read it.
16514978Sgd78059 	 */
16524978Sgd78059 	nar = GETCSR(mxfep, CSR_NAR);
16534978Sgd78059 	PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL);
16544978Sgd78059 	retval = mxfe_miireadgeneral(mxfep, phy, reg);
16554978Sgd78059 	PUTCSR(mxfep, CSR_NAR, nar);
16564978Sgd78059 	return (retval);
16574978Sgd78059 }
16584978Sgd78059 
16594978Sgd78059 void
mxfe_miiwrite(mxfe_t * mxfep,int phy,int reg,uint16_t val)16604978Sgd78059 mxfe_miiwrite(mxfe_t *mxfep, int phy, int reg, uint16_t val)
16614978Sgd78059 {
16624978Sgd78059 	switch (MXFE_MODEL(mxfep)) {
16634978Sgd78059 	case MXFE_98713A:
16644978Sgd78059 		mxfe_miiwrite98713(mxfep, phy, reg, val);
16654978Sgd78059 		break;
16664978Sgd78059 	default:
16674978Sgd78059 		break;
16684978Sgd78059 	}
16694978Sgd78059 }
16704978Sgd78059 
16714978Sgd78059 void
mxfe_miiwritegeneral(mxfe_t * mxfep,int phy,int reg,uint16_t val)16724978Sgd78059 mxfe_miiwritegeneral(mxfe_t *mxfep, int phy, int reg, uint16_t val)
16734978Sgd78059 {
16744978Sgd78059 	int i;
16754978Sgd78059 
16764978Sgd78059 	/* send the 32 bit preamble */
16774978Sgd78059 	for (i = 0; i < 32; i++) {
16784978Sgd78059 		mxfe_miiwritebit(mxfep, 1);
16794978Sgd78059 	}
16804978Sgd78059 
16814978Sgd78059 	/* send the start code - 01b */
16824978Sgd78059 	mxfe_miiwritebit(mxfep, 0);
16834978Sgd78059 	mxfe_miiwritebit(mxfep, 1);
16844978Sgd78059 
16854978Sgd78059 	/* send the opcode for write, - 01b */
16864978Sgd78059 	mxfe_miiwritebit(mxfep, 0);
16874978Sgd78059 	mxfe_miiwritebit(mxfep, 1);
16884978Sgd78059 
16894978Sgd78059 	/* next we send the 5 bit phy address */
16904978Sgd78059 	for (i = 0x10; i > 0; i >>= 1) {
16914978Sgd78059 		mxfe_miiwritebit(mxfep, (phy & i) ? 1 : 0);
16924978Sgd78059 	}
16934978Sgd78059 
16944978Sgd78059 	/* the 5 bit register address goes next */
16954978Sgd78059 	for (i = 0x10; i > 0; i >>= 1) {
16964978Sgd78059 		mxfe_miiwritebit(mxfep, (reg & i) ? 1 : 0);
16974978Sgd78059 	}
16984978Sgd78059 
16994978Sgd78059 	/* turnaround - tristate followed by logic 0 */
17004978Sgd78059 	mxfe_miitristate(mxfep);
17014978Sgd78059 	mxfe_miiwritebit(mxfep, 0);
17024978Sgd78059 
17034978Sgd78059 	/* now write out our data (16 bits) */
17044978Sgd78059 	for (i = 0x8000; i > 0; i >>= 1) {
17054978Sgd78059 		mxfe_miiwritebit(mxfep, (val & i) ? 1 : 0);
17064978Sgd78059 	}
17074978Sgd78059 
17084978Sgd78059 	/* idle mode */
17094978Sgd78059 	mxfe_miitristate(mxfep);
17104978Sgd78059 }
17114978Sgd78059 
17124978Sgd78059 void
mxfe_miiwrite98713(mxfe_t * mxfep,int phy,int reg,uint16_t val)17134978Sgd78059 mxfe_miiwrite98713(mxfe_t *mxfep, int phy, int reg, uint16_t val)
17144978Sgd78059 {
17154978Sgd78059 	unsigned nar;
17164978Sgd78059 	/*
17174978Sgd78059 	 * like an ordinary MII, but we have to turn off portsel while
17184978Sgd78059 	 * we read it.
17194978Sgd78059 	 */
17204978Sgd78059 	nar = GETCSR(mxfep, CSR_NAR);
17214978Sgd78059 	PUTCSR(mxfep, CSR_NAR, nar & ~NAR_PORTSEL);
17224978Sgd78059 	mxfe_miiwritegeneral(mxfep, phy, reg, val);
17234978Sgd78059 	PUTCSR(mxfep, CSR_NAR, nar);
17244978Sgd78059 }
17254978Sgd78059 
17264978Sgd78059 int
mxfe_m_start(void * arg)17274978Sgd78059 mxfe_m_start(void *arg)
17284978Sgd78059 {
17294978Sgd78059 	mxfe_t	*mxfep = arg;
17304978Sgd78059 
17314978Sgd78059 	/* grab exclusive access to the card */
17324978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
17334978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
17344978Sgd78059 
17354978Sgd78059 	mxfe_startall(mxfep);
17364978Sgd78059 	mxfep->mxfe_flags |= MXFE_RUNNING;
17374978Sgd78059 
17384978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
17394978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
17404978Sgd78059 	return (0);
17414978Sgd78059 }
17424978Sgd78059 
17434978Sgd78059 void
mxfe_m_stop(void * arg)17444978Sgd78059 mxfe_m_stop(void *arg)
17454978Sgd78059 {
17464978Sgd78059 	mxfe_t	*mxfep = arg;
17474978Sgd78059 
17484978Sgd78059 	/* exclusive access to the hardware! */
17494978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
17504978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
17514978Sgd78059 
17524978Sgd78059 	mxfe_stopall(mxfep);
17534978Sgd78059 	mxfep->mxfe_flags &= ~MXFE_RUNNING;
17544978Sgd78059 
17554978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
17564978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
17574978Sgd78059 }
17584978Sgd78059 
17594978Sgd78059 void
mxfe_startmac(mxfe_t * mxfep)17604978Sgd78059 mxfe_startmac(mxfe_t *mxfep)
17614978Sgd78059 {
17624978Sgd78059 	/* verify exclusive access to the card */
17634978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
17644978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
17654978Sgd78059 
17664978Sgd78059 	/* start the card */
17674978Sgd78059 	SETBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
17684978Sgd78059 
17694978Sgd78059 	if (mxfep->mxfe_txavail != MXFE_TXRING)
17704978Sgd78059 		PUTCSR(mxfep, CSR_TDR, 0);
17714978Sgd78059 
17724978Sgd78059 	/* tell the mac that we are ready to go! */
17734978Sgd78059 	if (mxfep->mxfe_flags & MXFE_RUNNING)
17744978Sgd78059 		mac_tx_update(mxfep->mxfe_mh);
17754978Sgd78059 }
17764978Sgd78059 
17774978Sgd78059 void
mxfe_stopmac(mxfe_t * mxfep)17784978Sgd78059 mxfe_stopmac(mxfe_t *mxfep)
17794978Sgd78059 {
17804978Sgd78059 	int		i;
17814978Sgd78059 
17824978Sgd78059 	/* exclusive access to the hardware! */
17834978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
17844978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
17854978Sgd78059 
17864978Sgd78059 	CLRBIT(mxfep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
17874978Sgd78059 
17884978Sgd78059 	/*
17894978Sgd78059 	 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain.
17904978Sgd78059 	 * We just add up to the nearest msec (2), which should be
17914978Sgd78059 	 * plenty to complete.
17924978Sgd78059 	 *
17934978Sgd78059 	 * Note that some chips never seem to indicate the transition to
17944978Sgd78059 	 * the stopped state properly.  Experience shows that we can safely
17954978Sgd78059 	 * proceed anyway, after waiting the requisite timeout.
17964978Sgd78059 	 */
17974978Sgd78059 	for (i = 2000; i != 0; i -= 10) {
17984978Sgd78059 		if ((GETCSR(mxfep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0)
17994978Sgd78059 			break;
18004978Sgd78059 		drv_usecwait(10);
18014978Sgd78059 	}
18024978Sgd78059 
18034978Sgd78059 	/* prevent an interrupt */
18044978Sgd78059 	PUTCSR(mxfep, CSR_SR, INT_RXSTOPPED | INT_TXSTOPPED);
18054978Sgd78059 }
18064978Sgd78059 
18074978Sgd78059 void
mxfe_resetrings(mxfe_t * mxfep)18084978Sgd78059 mxfe_resetrings(mxfe_t *mxfep)
18094978Sgd78059 {
18104978Sgd78059 	int	i;
18114978Sgd78059 
18124978Sgd78059 	/* now we need to reset the pointers... */
18134978Sgd78059 	PUTCSR(mxfep, CSR_RDB, 0);
18144978Sgd78059 	PUTCSR(mxfep, CSR_TDB, 0);
18154978Sgd78059 
18164978Sgd78059 	/* reset the descriptor ring pointers */
18174978Sgd78059 	mxfep->mxfe_rxhead = 0;
18184978Sgd78059 	mxfep->mxfe_txreclaim = 0;
18194978Sgd78059 	mxfep->mxfe_txsend = 0;
18204978Sgd78059 	mxfep->mxfe_txavail = MXFE_TXRING;
18214978Sgd78059 
18224978Sgd78059 	/* set up transmit descriptor ring */
18234978Sgd78059 	for (i = 0; i < MXFE_TXRING; i++) {
18244978Sgd78059 		mxfe_desc_t	*tmdp = &mxfep->mxfe_txdescp[i];
18254978Sgd78059 		unsigned	control = 0;
18264978Sgd78059 		if (i == (MXFE_TXRING - 1)) {
18274978Sgd78059 			control |= TXCTL_ENDRING;
18284978Sgd78059 		}
18294978Sgd78059 		PUTTXDESC(mxfep, tmdp->desc_status, 0);
18304978Sgd78059 		PUTTXDESC(mxfep, tmdp->desc_control, control);
18314978Sgd78059 		PUTTXDESC(mxfep, tmdp->desc_buffer1, 0);
18324978Sgd78059 		PUTTXDESC(mxfep, tmdp->desc_buffer2, 0);
18334978Sgd78059 		SYNCTXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV);
18344978Sgd78059 	}
18354978Sgd78059 	PUTCSR(mxfep, CSR_TDB, mxfep->mxfe_txdesc_paddr);
18364978Sgd78059 
18374978Sgd78059 	/* make the receive buffers available */
18384978Sgd78059 	for (i = 0; i < MXFE_RXRING; i++) {
18394978Sgd78059 		mxfe_rxbuf_t	*rxb = mxfep->mxfe_rxbufs[i];
18404978Sgd78059 		mxfe_desc_t	*rmdp = &mxfep->mxfe_rxdescp[i];
18414978Sgd78059 		unsigned	control;
18424978Sgd78059 
18434978Sgd78059 		control = MXFE_BUFSZ & RXCTL_BUFLEN1;
18444978Sgd78059 		if (i == (MXFE_RXRING - 1)) {
18454978Sgd78059 			control |= RXCTL_ENDRING;
18464978Sgd78059 		}
18474978Sgd78059 		PUTRXDESC(mxfep, rmdp->desc_buffer1, rxb->rxb_paddr);
18484978Sgd78059 		PUTRXDESC(mxfep, rmdp->desc_buffer2, 0);
18494978Sgd78059 		PUTRXDESC(mxfep, rmdp->desc_control, control);
18504978Sgd78059 		PUTRXDESC(mxfep, rmdp->desc_status, RXSTAT_OWN);
18514978Sgd78059 		SYNCRXDESC(mxfep, i, DDI_DMA_SYNC_FORDEV);
18524978Sgd78059 	}
18534978Sgd78059 	PUTCSR(mxfep, CSR_RDB, mxfep->mxfe_rxdesc_paddr);
18544978Sgd78059 }
18554978Sgd78059 
18564978Sgd78059 void
mxfe_stopall(mxfe_t * mxfep)18574978Sgd78059 mxfe_stopall(mxfe_t *mxfep)
18584978Sgd78059 {
18594978Sgd78059 	mxfe_disableinterrupts(mxfep);
18604978Sgd78059 
18614978Sgd78059 	mxfe_stopmac(mxfep);
18624978Sgd78059 
18634978Sgd78059 	/* stop the phy */
18644978Sgd78059 	mxfe_stopphy(mxfep);
18654978Sgd78059 }
18664978Sgd78059 
18674978Sgd78059 void
mxfe_startall(mxfe_t * mxfep)18684978Sgd78059 mxfe_startall(mxfe_t *mxfep)
18694978Sgd78059 {
18704978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_intrlock));
18714978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
18724978Sgd78059 
18734978Sgd78059 	/* make sure interrupts are disabled to begin */
18744978Sgd78059 	mxfe_disableinterrupts(mxfep);
18754978Sgd78059 
18764978Sgd78059 	/* initialize the chip */
18774978Sgd78059 	(void) mxfe_initialize(mxfep);
18784978Sgd78059 
18794978Sgd78059 	/* now we can enable interrupts */
18804978Sgd78059 	mxfe_enableinterrupts(mxfep);
18814978Sgd78059 
18824978Sgd78059 	/* start up the phy */
18834978Sgd78059 	mxfe_startphy(mxfep);
18844978Sgd78059 
18854978Sgd78059 	/* start up the mac */
18864978Sgd78059 	mxfe_startmac(mxfep);
18874978Sgd78059 }
18884978Sgd78059 
18894978Sgd78059 void
mxfe_resetall(mxfe_t * mxfep)18904978Sgd78059 mxfe_resetall(mxfe_t *mxfep)
18914978Sgd78059 {
18924978Sgd78059 	mxfep->mxfe_resetting = B_TRUE;
18934978Sgd78059 	mxfe_stopall(mxfep);
18944978Sgd78059 	mxfep->mxfe_resetting = B_FALSE;
18954978Sgd78059 	mxfe_startall(mxfep);
18964978Sgd78059 }
18974978Sgd78059 
18984978Sgd78059 mxfe_txbuf_t *
mxfe_alloctxbuf(mxfe_t * mxfep)18994978Sgd78059 mxfe_alloctxbuf(mxfe_t *mxfep)
19004978Sgd78059 {
19014978Sgd78059 	ddi_dma_cookie_t	dmac;
19024978Sgd78059 	unsigned		ncookies;
19034978Sgd78059 	mxfe_txbuf_t		*txb;
19044978Sgd78059 	size_t			len;
19054978Sgd78059 
19064978Sgd78059 	txb = kmem_zalloc(sizeof (*txb), KM_SLEEP);
19074978Sgd78059 
19084978Sgd78059 	if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_txattr,
19094978Sgd78059 	    DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) {
19104978Sgd78059 		return (NULL);
19114978Sgd78059 	}
19124978Sgd78059 
19134978Sgd78059 	if (ddi_dma_mem_alloc(txb->txb_dmah, MXFE_BUFSZ, &mxfe_bufattr,
19144978Sgd78059 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf,
19154978Sgd78059 	    &len, &txb->txb_acch) != DDI_SUCCESS) {
19164978Sgd78059 		return (NULL);
19174978Sgd78059 	}
19184978Sgd78059 	if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf,
19194978Sgd78059 	    len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
19204978Sgd78059 	    &dmac, &ncookies) != DDI_DMA_MAPPED) {
19214978Sgd78059 		return (NULL);
19224978Sgd78059 	}
19234978Sgd78059 	txb->txb_paddr = dmac.dmac_address;
19244978Sgd78059 
19254978Sgd78059 	return (txb);
19264978Sgd78059 }
19274978Sgd78059 
19284978Sgd78059 void
mxfe_destroytxbuf(mxfe_txbuf_t * txb)19294978Sgd78059 mxfe_destroytxbuf(mxfe_txbuf_t *txb)
19304978Sgd78059 {
19314978Sgd78059 	if (txb != NULL) {
19324978Sgd78059 		if (txb->txb_paddr)
19334978Sgd78059 			(void) ddi_dma_unbind_handle(txb->txb_dmah);
19344978Sgd78059 		if (txb->txb_acch)
19354978Sgd78059 			ddi_dma_mem_free(&txb->txb_acch);
19364978Sgd78059 		if (txb->txb_dmah)
19374978Sgd78059 			ddi_dma_free_handle(&txb->txb_dmah);
19384978Sgd78059 		kmem_free(txb, sizeof (*txb));
19394978Sgd78059 	}
19404978Sgd78059 }
19414978Sgd78059 
19424978Sgd78059 mxfe_rxbuf_t *
mxfe_allocrxbuf(mxfe_t * mxfep)19434978Sgd78059 mxfe_allocrxbuf(mxfe_t *mxfep)
19444978Sgd78059 {
19454978Sgd78059 	mxfe_rxbuf_t 		*rxb;
19464978Sgd78059 	size_t			len;
19474978Sgd78059 	unsigned		ccnt;
19484978Sgd78059 	ddi_dma_cookie_t	dmac;
19494978Sgd78059 
19504978Sgd78059 	rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP);
19514978Sgd78059 
19524978Sgd78059 	if (ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
19534978Sgd78059 	    DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) {
19544978Sgd78059 		kmem_free(rxb, sizeof (*rxb));
19554978Sgd78059 		return (NULL);
19564978Sgd78059 	}
19574978Sgd78059 	if (ddi_dma_mem_alloc(rxb->rxb_dmah, MXFE_BUFSZ, &mxfe_bufattr,
19584978Sgd78059 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
19594978Sgd78059 	    &rxb->rxb_buf, &len, &rxb->rxb_acch) != DDI_SUCCESS) {
19604978Sgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
19614978Sgd78059 		kmem_free(rxb, sizeof (*rxb));
19624978Sgd78059 		return (NULL);
19634978Sgd78059 	}
19644978Sgd78059 	if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len,
19654978Sgd78059 	    DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
19664978Sgd78059 	    &ccnt) != DDI_DMA_MAPPED) {
19674978Sgd78059 		ddi_dma_mem_free(&rxb->rxb_acch);
19684978Sgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
19694978Sgd78059 		kmem_free(rxb, sizeof (*rxb));
19704978Sgd78059 		return (NULL);
19714978Sgd78059 	}
19724978Sgd78059 	rxb->rxb_paddr = dmac.dmac_address;
19734978Sgd78059 
19744978Sgd78059 	return (rxb);
19754978Sgd78059 }
19764978Sgd78059 
19774978Sgd78059 void
mxfe_destroyrxbuf(mxfe_rxbuf_t * rxb)19784978Sgd78059 mxfe_destroyrxbuf(mxfe_rxbuf_t *rxb)
19794978Sgd78059 {
19804978Sgd78059 	if (rxb != NULL) {
19814978Sgd78059 		(void) ddi_dma_unbind_handle(rxb->rxb_dmah);
19824978Sgd78059 		ddi_dma_mem_free(&rxb->rxb_acch);
19834978Sgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
19844978Sgd78059 		kmem_free(rxb, sizeof (*rxb));
19854978Sgd78059 	}
19864978Sgd78059 }
19874978Sgd78059 
19884978Sgd78059 /*
19894978Sgd78059  * Allocate receive resources.
19904978Sgd78059  */
19914978Sgd78059 int
mxfe_allocrxring(mxfe_t * mxfep)19924978Sgd78059 mxfe_allocrxring(mxfe_t *mxfep)
19934978Sgd78059 {
19944978Sgd78059 	int			rval;
19954978Sgd78059 	int			i;
19964978Sgd78059 	size_t			size;
19974978Sgd78059 	size_t			len;
19984978Sgd78059 	ddi_dma_cookie_t	dmac;
19994978Sgd78059 	unsigned		ncookies;
20004978Sgd78059 	caddr_t			kaddr;
20014978Sgd78059 
20024978Sgd78059 	size = MXFE_RXRING * sizeof (mxfe_desc_t);
20034978Sgd78059 
20044978Sgd78059 	rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
20054978Sgd78059 	    DDI_DMA_SLEEP, NULL, &mxfep->mxfe_rxdesc_dmah);
20064978Sgd78059 	if (rval != DDI_SUCCESS) {
20074978Sgd78059 		mxfe_error(mxfep->mxfe_dip,
20084978Sgd78059 		    "unable to allocate DMA handle for rx descriptors");
20094978Sgd78059 		return (DDI_FAILURE);
20104978Sgd78059 	}
20114978Sgd78059 
20124978Sgd78059 	rval = ddi_dma_mem_alloc(mxfep->mxfe_rxdesc_dmah, size, &mxfe_devattr,
20134978Sgd78059 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
20144978Sgd78059 	    &mxfep->mxfe_rxdesc_acch);
20154978Sgd78059 	if (rval != DDI_SUCCESS) {
20164978Sgd78059 		mxfe_error(mxfep->mxfe_dip,
20174978Sgd78059 		    "unable to allocate DMA memory for rx descriptors");
20184978Sgd78059 		return (DDI_FAILURE);
20194978Sgd78059 	}
20204978Sgd78059 
20214978Sgd78059 	rval = ddi_dma_addr_bind_handle(mxfep->mxfe_rxdesc_dmah, NULL, kaddr,
20224978Sgd78059 	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
20234978Sgd78059 	    &dmac, &ncookies);
20244978Sgd78059 	if (rval != DDI_DMA_MAPPED) {
20254978Sgd78059 		mxfe_error(mxfep->mxfe_dip,
20264978Sgd78059 		    "unable to bind DMA for rx descriptors");
20274978Sgd78059 		return (DDI_FAILURE);
20284978Sgd78059 	}
20294978Sgd78059 
20304978Sgd78059 	/* because of mxfe_dma_attr */
20314978Sgd78059 	ASSERT(ncookies == 1);
20324978Sgd78059 
20334978Sgd78059 	/* we take the 32-bit physical address out of the cookie */
20344978Sgd78059 	mxfep->mxfe_rxdesc_paddr = dmac.dmac_address;
20354978Sgd78059 	mxfep->mxfe_rxdescp = (void *)kaddr;
20364978Sgd78059 
20374978Sgd78059 	/* allocate buffer pointers (not the buffers themselves, yet) */
20384978Sgd78059 	mxfep->mxfe_rxbufs = kmem_zalloc(MXFE_RXRING * sizeof (mxfe_rxbuf_t *),
20394978Sgd78059 	    KM_SLEEP);
20404978Sgd78059 
20414978Sgd78059 	/* now allocate rx buffers */
20424978Sgd78059 	for (i = 0; i < MXFE_RXRING; i++) {
20434978Sgd78059 		mxfe_rxbuf_t *rxb = mxfe_allocrxbuf(mxfep);
20444978Sgd78059 		if (rxb == NULL)
20454978Sgd78059 			return (DDI_FAILURE);
20464978Sgd78059 		mxfep->mxfe_rxbufs[i] = rxb;
20474978Sgd78059 	}
20484978Sgd78059 
20494978Sgd78059 	return (DDI_SUCCESS);
20504978Sgd78059 }
20514978Sgd78059 
20524978Sgd78059 /*
20534978Sgd78059  * Allocate transmit resources.
20544978Sgd78059  */
20554978Sgd78059 int
mxfe_alloctxring(mxfe_t * mxfep)20564978Sgd78059 mxfe_alloctxring(mxfe_t *mxfep)
20574978Sgd78059 {
20584978Sgd78059 	int			rval;
20594978Sgd78059 	int			i;
20604978Sgd78059 	size_t			size;
20614978Sgd78059 	size_t			len;
20624978Sgd78059 	ddi_dma_cookie_t	dmac;
20634978Sgd78059 	unsigned		ncookies;
20644978Sgd78059 	caddr_t			kaddr;
20654978Sgd78059 
20664978Sgd78059 	size = MXFE_TXRING * sizeof (mxfe_desc_t);
20674978Sgd78059 
20684978Sgd78059 	rval = ddi_dma_alloc_handle(mxfep->mxfe_dip, &mxfe_dma_attr,
20694978Sgd78059 	    DDI_DMA_SLEEP, NULL, &mxfep->mxfe_txdesc_dmah);
20704978Sgd78059 	if (rval != DDI_SUCCESS) {
20714978Sgd78059 		mxfe_error(mxfep->mxfe_dip,
20724978Sgd78059 		    "unable to allocate DMA handle for tx descriptors");
20734978Sgd78059 		return (DDI_FAILURE);
20744978Sgd78059 	}
20754978Sgd78059 
20764978Sgd78059 	rval = ddi_dma_mem_alloc(mxfep->mxfe_txdesc_dmah, size, &mxfe_devattr,
20774978Sgd78059 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
20784978Sgd78059 	    &mxfep->mxfe_txdesc_acch);
20794978Sgd78059 	if (rval != DDI_SUCCESS) {
20804978Sgd78059 		mxfe_error(mxfep->mxfe_dip,
20814978Sgd78059 		    "unable to allocate DMA memory for tx descriptors");
20824978Sgd78059 		return (DDI_FAILURE);
20834978Sgd78059 	}
20844978Sgd78059 
20854978Sgd78059 	rval = ddi_dma_addr_bind_handle(mxfep->mxfe_txdesc_dmah, NULL, kaddr,
20864978Sgd78059 	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
20874978Sgd78059 	    &dmac, &ncookies);
20884978Sgd78059 	if (rval != DDI_DMA_MAPPED) {
20894978Sgd78059 		mxfe_error(mxfep->mxfe_dip,
20904978Sgd78059 		    "unable to bind DMA for tx descriptors");
20914978Sgd78059 		return (DDI_FAILURE);
20924978Sgd78059 	}
20934978Sgd78059 
20944978Sgd78059 	/* because of mxfe_dma_attr */
20954978Sgd78059 	ASSERT(ncookies == 1);
20964978Sgd78059 
20974978Sgd78059 	/* we take the 32-bit physical address out of the cookie */
20984978Sgd78059 	mxfep->mxfe_txdesc_paddr = dmac.dmac_address;
20994978Sgd78059 	mxfep->mxfe_txdescp = (void *)kaddr;
21004978Sgd78059 
21014978Sgd78059 	/* allocate buffer pointers (not the buffers themselves, yet) */
21024978Sgd78059 	mxfep->mxfe_txbufs = kmem_zalloc(MXFE_TXRING * sizeof (mxfe_txbuf_t *),
21034978Sgd78059 	    KM_SLEEP);
21044978Sgd78059 
21054978Sgd78059 	/* now allocate tx buffers */
21064978Sgd78059 	for (i = 0; i < MXFE_TXRING; i++) {
21074978Sgd78059 		mxfe_txbuf_t *txb = mxfe_alloctxbuf(mxfep);
21084978Sgd78059 		if (txb == NULL)
21094978Sgd78059 			return (DDI_FAILURE);
21104978Sgd78059 		/* stick it in the stack */
21114978Sgd78059 		mxfep->mxfe_txbufs[i] = txb;
21124978Sgd78059 	}
21134978Sgd78059 
21144978Sgd78059 	return (DDI_SUCCESS);
21154978Sgd78059 }
21164978Sgd78059 
21174978Sgd78059 void
mxfe_freerxring(mxfe_t * mxfep)21184978Sgd78059 mxfe_freerxring(mxfe_t *mxfep)
21194978Sgd78059 {
21204978Sgd78059 	int		i;
21214978Sgd78059 
21224978Sgd78059 	for (i = 0; i < MXFE_RXRING; i++) {
21234978Sgd78059 		mxfe_destroyrxbuf(mxfep->mxfe_rxbufs[i]);
21244978Sgd78059 	}
21254978Sgd78059 
21264978Sgd78059 	if (mxfep->mxfe_rxbufs) {
21274978Sgd78059 		kmem_free(mxfep->mxfe_rxbufs,
21284978Sgd78059 		    MXFE_RXRING * sizeof (mxfe_rxbuf_t *));
21294978Sgd78059 	}
21304978Sgd78059 
21314978Sgd78059 	if (mxfep->mxfe_rxdesc_paddr)
21324978Sgd78059 		(void) ddi_dma_unbind_handle(mxfep->mxfe_rxdesc_dmah);
21334978Sgd78059 	if (mxfep->mxfe_rxdesc_acch)
21344978Sgd78059 		ddi_dma_mem_free(&mxfep->mxfe_rxdesc_acch);
21354978Sgd78059 	if (mxfep->mxfe_rxdesc_dmah)
21364978Sgd78059 		ddi_dma_free_handle(&mxfep->mxfe_rxdesc_dmah);
21374978Sgd78059 }
21384978Sgd78059 
21394978Sgd78059 void
mxfe_freetxring(mxfe_t * mxfep)21404978Sgd78059 mxfe_freetxring(mxfe_t *mxfep)
21414978Sgd78059 {
21424978Sgd78059 	int			i;
21434978Sgd78059 
21444978Sgd78059 	for (i = 0; i < MXFE_TXRING; i++) {
21454978Sgd78059 		mxfe_destroytxbuf(mxfep->mxfe_txbufs[i]);
21464978Sgd78059 	}
21474978Sgd78059 
21484978Sgd78059 	if (mxfep->mxfe_txbufs) {
21494978Sgd78059 		kmem_free(mxfep->mxfe_txbufs,
21504978Sgd78059 		    MXFE_TXRING * sizeof (mxfe_txbuf_t *));
21514978Sgd78059 	}
21524978Sgd78059 	if (mxfep->mxfe_txdesc_paddr)
21534978Sgd78059 		(void) ddi_dma_unbind_handle(mxfep->mxfe_txdesc_dmah);
21544978Sgd78059 	if (mxfep->mxfe_txdesc_acch)
21554978Sgd78059 		ddi_dma_mem_free(&mxfep->mxfe_txdesc_acch);
21564978Sgd78059 	if (mxfep->mxfe_txdesc_dmah)
21574978Sgd78059 		ddi_dma_free_handle(&mxfep->mxfe_txdesc_dmah);
21584978Sgd78059 }
21594978Sgd78059 
21604978Sgd78059 /*
21614978Sgd78059  * Interrupt service routine.
21624978Sgd78059  */
21634978Sgd78059 unsigned
mxfe_intr(caddr_t arg)21644978Sgd78059 mxfe_intr(caddr_t arg)
21654978Sgd78059 {
21664978Sgd78059 	mxfe_t		*mxfep = (void *)arg;
21674978Sgd78059 	uint32_t	status;
21684978Sgd78059 	mblk_t		*mp = NULL;
21699199Sgdamore@opensolaris.org 	boolean_t	error = B_FALSE;
21704978Sgd78059 
21714978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
21724978Sgd78059 
21734978Sgd78059 	if (mxfep->mxfe_flags & MXFE_SUSPENDED) {
21744978Sgd78059 		/* we cannot receive interrupts! */
21754978Sgd78059 		mutex_exit(&mxfep->mxfe_intrlock);
21764978Sgd78059 		return (DDI_INTR_UNCLAIMED);
21774978Sgd78059 	}
21784978Sgd78059 
21794978Sgd78059 	/* check interrupt status bits, did we interrupt? */
21804978Sgd78059 	status = GETCSR(mxfep, CSR_SR) & INT_ALL;
21814978Sgd78059 
21824978Sgd78059 	if (status == 0) {
21834978Sgd78059 		KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
21844978Sgd78059 		mutex_exit(&mxfep->mxfe_intrlock);
21854978Sgd78059 		return (DDI_INTR_UNCLAIMED);
21864978Sgd78059 	}
21874978Sgd78059 	/* ack the interrupt */
21884978Sgd78059 	PUTCSR(mxfep, CSR_SR, status);
21894978Sgd78059 	KIOIP->intrs[KSTAT_INTR_HARD]++;
21904978Sgd78059 
21914978Sgd78059 	if (!(mxfep->mxfe_flags & MXFE_RUNNING)) {
21924978Sgd78059 		/* not running, don't touch anything */
21934978Sgd78059 		mutex_exit(&mxfep->mxfe_intrlock);
21944978Sgd78059 		return (DDI_INTR_CLAIMED);
21954978Sgd78059 	}
21964978Sgd78059 
21974978Sgd78059 	if (status & INT_RXOK) {
21984978Sgd78059 		/* receive packets */
21999199Sgdamore@opensolaris.org 		if (mxfe_receive(mxfep, &mp)) {
22009199Sgdamore@opensolaris.org 			error = B_TRUE;
22019199Sgdamore@opensolaris.org 		}
22024978Sgd78059 	}
22034978Sgd78059 
22044978Sgd78059 	if (status & INT_TXOK) {
22054978Sgd78059 		/* transmit completed */
22064978Sgd78059 		mutex_enter(&mxfep->mxfe_xmtlock);
22074978Sgd78059 		mxfe_reclaim(mxfep);
22084978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
22094978Sgd78059 	}
22104978Sgd78059 
22114978Sgd78059 	if (((status & (INT_TIMER|INT_ANEG)) != 0) ||
22124978Sgd78059 	    ((mxfep->mxfe_linkup == LINK_STATE_UP) &&
22134978Sgd78059 	    ((status & (INT_10LINK|INT_100LINK)) != 0))) {
22144978Sgd78059 		/* rescan the link */
22154978Sgd78059 		mutex_enter(&mxfep->mxfe_xmtlock);
22164978Sgd78059 		mxfe_checklink(mxfep);
22174978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
22184978Sgd78059 	}
22194978Sgd78059 
22204978Sgd78059 	if (status & (INT_RXSTOPPED|INT_TXSTOPPED|INT_RXNOBUF|
22214978Sgd78059 	    INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) {
22224978Sgd78059 
22234978Sgd78059 		if (status & (INT_RXJABBER | INT_TXJABBER)) {
22244978Sgd78059 			mxfep->mxfe_jabber++;
22254978Sgd78059 		}
22269199Sgdamore@opensolaris.org 		DBG(DWARN, "error interrupt: status %x", status);
22279199Sgdamore@opensolaris.org 		error = B_TRUE;
22284978Sgd78059 	}
22294978Sgd78059 
22304978Sgd78059 	if (status & INT_BUSERR) {
22314978Sgd78059 		switch (status & SR_BERR_TYPE) {
22324978Sgd78059 		case SR_BERR_PARITY:
22334978Sgd78059 			mxfe_error(mxfep->mxfe_dip, "PCI parity error");
22344978Sgd78059 			break;
22354978Sgd78059 		case SR_BERR_TARGET_ABORT:
22364978Sgd78059 			mxfe_error(mxfep->mxfe_dip, "PCI target abort");
22374978Sgd78059 			break;
22384978Sgd78059 		case SR_BERR_MASTER_ABORT:
22394978Sgd78059 			mxfe_error(mxfep->mxfe_dip, "PCI master abort");
22404978Sgd78059 			break;
22414978Sgd78059 		default:
22424978Sgd78059 			mxfe_error(mxfep->mxfe_dip, "Unknown PCI error");
22434978Sgd78059 			break;
22444978Sgd78059 		}
22454978Sgd78059 
22469199Sgdamore@opensolaris.org 		error = B_TRUE;
22479199Sgdamore@opensolaris.org 	}
22489199Sgdamore@opensolaris.org 
22499199Sgdamore@opensolaris.org 	if (error) {
22504978Sgd78059 		/* reset the chip in an attempt to fix things */
22514978Sgd78059 		mutex_enter(&mxfep->mxfe_xmtlock);
22524978Sgd78059 		mxfe_resetall(mxfep);
22534978Sgd78059 		mutex_exit(&mxfep->mxfe_xmtlock);
22544978Sgd78059 	}
22554978Sgd78059 
22564978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
22574978Sgd78059 
22584978Sgd78059 	/*
22594978Sgd78059 	 * Send up packets.  We do this outside of the intrlock.
22604978Sgd78059 	 */
22614978Sgd78059 	if (mp) {
22624978Sgd78059 		mac_rx(mxfep->mxfe_mh, NULL, mp);
22634978Sgd78059 	}
22644978Sgd78059 
22654978Sgd78059 	return (DDI_INTR_CLAIMED);
22664978Sgd78059 }
22674978Sgd78059 
22684978Sgd78059 void
mxfe_enableinterrupts(mxfe_t * mxfep)22694978Sgd78059 mxfe_enableinterrupts(mxfe_t *mxfep)
22704978Sgd78059 {
22714978Sgd78059 	unsigned mask = INT_WANTED;
22724978Sgd78059 
22734978Sgd78059 	if (mxfep->mxfe_wantw)
22744978Sgd78059 		mask |= INT_TXOK;
22754978Sgd78059 
22764978Sgd78059 	if (MXFE_MODEL(mxfep) != MXFE_98713A)
22774978Sgd78059 		mask |= INT_LINKSTATUS;
22784978Sgd78059 
22794978Sgd78059 	DBG(DINTR, "setting int mask to 0x%x", mask);
22804978Sgd78059 	PUTCSR(mxfep, CSR_IER, mask);
22814978Sgd78059 }
22824978Sgd78059 
22834978Sgd78059 void
mxfe_disableinterrupts(mxfe_t * mxfep)22844978Sgd78059 mxfe_disableinterrupts(mxfe_t *mxfep)
22854978Sgd78059 {
22864978Sgd78059 	/* disable further interrupts */
22874978Sgd78059 	PUTCSR(mxfep, CSR_IER, 0);
22884978Sgd78059 
22894978Sgd78059 	/* clear any pending interrupts */
22904978Sgd78059 	PUTCSR(mxfep, CSR_SR, INT_ALL);
22914978Sgd78059 }
22924978Sgd78059 
22934978Sgd78059 void
mxfe_send_setup(mxfe_t * mxfep)22944978Sgd78059 mxfe_send_setup(mxfe_t *mxfep)
22954978Sgd78059 {
22964978Sgd78059 	mxfe_txbuf_t	*txb;
22974978Sgd78059 	mxfe_desc_t	*tmdp;
22984978Sgd78059 
22994978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
23004978Sgd78059 
23014978Sgd78059 	/* setup frame -- must be at head of list -- guaranteed by caller! */
23024978Sgd78059 	ASSERT(mxfep->mxfe_txsend == 0);
23034978Sgd78059 
23044978Sgd78059 	txb = mxfep->mxfe_txbufs[0];
23054978Sgd78059 	tmdp = &mxfep->mxfe_txdescp[0];
23064978Sgd78059 
23074978Sgd78059 	bzero(txb->txb_buf, MXFE_SETUP_LEN);
23084978Sgd78059 
23094978Sgd78059 	/* program the unicast address */
23104978Sgd78059 	txb->txb_buf[156] = mxfep->mxfe_curraddr[0];
23114978Sgd78059 	txb->txb_buf[157] = mxfep->mxfe_curraddr[1];
23124978Sgd78059 	txb->txb_buf[160] = mxfep->mxfe_curraddr[2];
23134978Sgd78059 	txb->txb_buf[161] = mxfep->mxfe_curraddr[3];
23144978Sgd78059 	txb->txb_buf[164] = mxfep->mxfe_curraddr[4];
23154978Sgd78059 	txb->txb_buf[165] = mxfep->mxfe_curraddr[5];
23164978Sgd78059 
23174978Sgd78059 	/* make sure that the hardware can see it */
23184978Sgd78059 	SYNCTXBUF(txb, MXFE_SETUP_LEN, DDI_DMA_SYNC_FORDEV);
23194978Sgd78059 
23204978Sgd78059 	PUTTXDESC(mxfep, tmdp->desc_control,
23214978Sgd78059 	    TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE | TXCTL_HASHPERF |
23224978Sgd78059 	    TXCTL_SETUP | MXFE_SETUP_LEN);
23234978Sgd78059 
23244978Sgd78059 	PUTTXDESC(mxfep, tmdp->desc_buffer1, txb->txb_paddr);
23254978Sgd78059 	PUTTXDESC(mxfep, tmdp->desc_buffer2, 0);
23264978Sgd78059 	PUTTXDESC(mxfep, tmdp->desc_status, TXSTAT_OWN);
23274978Sgd78059 
23284978Sgd78059 	/* sync the descriptor out to the device */
23294978Sgd78059 	SYNCTXDESC(mxfep, 0, DDI_DMA_SYNC_FORDEV);
23304978Sgd78059 
23314978Sgd78059 	/*
23324978Sgd78059 	 * wake up the chip ... inside the lock to protect against DR suspend,
23334978Sgd78059 	 * etc.
23344978Sgd78059 	 */
23354978Sgd78059 	PUTCSR(mxfep, CSR_TDR, 0);
23364978Sgd78059 	mxfep->mxfe_txsend++;
23374978Sgd78059 	mxfep->mxfe_txavail--;
23384978Sgd78059 
23394978Sgd78059 	/*
23404978Sgd78059 	 * Program promiscuous mode.
23414978Sgd78059 	 */
23424978Sgd78059 	if (mxfep->mxfe_promisc) {
23434978Sgd78059 		SETBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
23444978Sgd78059 	} else {
23454978Sgd78059 		CLRBIT(mxfep, CSR_NAR, NAR_RX_PROMISC);
23464978Sgd78059 	}
23474978Sgd78059 }
23484978Sgd78059 
23494978Sgd78059 boolean_t
mxfe_send(mxfe_t * mxfep,mblk_t * mp)23504978Sgd78059 mxfe_send(mxfe_t *mxfep, mblk_t *mp)
23514978Sgd78059 {
23524978Sgd78059 	size_t			len;
23534978Sgd78059 	mxfe_txbuf_t		*txb;
23544978Sgd78059 	mxfe_desc_t		*tmd;
23554978Sgd78059 	uint32_t		control;
23564978Sgd78059 	int			txsend;
23574978Sgd78059 
23584978Sgd78059 	ASSERT(mutex_owned(&mxfep->mxfe_xmtlock));
23594978Sgd78059 	ASSERT(mp != NULL);
23604978Sgd78059 
23614978Sgd78059 	len = msgsize(mp);
23624978Sgd78059 	if (len > ETHERVLANMTU) {
23634978Sgd78059 		DBG(DXMIT, "frame too long: %d", len);
23644978Sgd78059 		mxfep->mxfe_macxmt_errors++;
23654978Sgd78059 		freemsg(mp);
23664978Sgd78059 		return (B_TRUE);
23674978Sgd78059 	}
23684978Sgd78059 
23694978Sgd78059 	if (mxfep->mxfe_txavail < MXFE_TXRECLAIM)
23704978Sgd78059 		mxfe_reclaim(mxfep);
23714978Sgd78059 
23724978Sgd78059 	if (mxfep->mxfe_txavail == 0) {
23734978Sgd78059 		/* no more tmds */
23744978Sgd78059 		mxfep->mxfe_wantw = B_TRUE;
23754978Sgd78059 		/* enable TX interrupt */
23764978Sgd78059 		mxfe_enableinterrupts(mxfep);
23774978Sgd78059 		return (B_FALSE);
23784978Sgd78059 	}
23794978Sgd78059 
23804978Sgd78059 	txsend = mxfep->mxfe_txsend;
23814978Sgd78059 
23824978Sgd78059 	/*
23834978Sgd78059 	 * For simplicity, we just do a copy into a preallocated
23844978Sgd78059 	 * DMA buffer.
23854978Sgd78059 	 */
23864978Sgd78059 
23874978Sgd78059 	txb = mxfep->mxfe_txbufs[txsend];
23884978Sgd78059 	mcopymsg(mp, txb->txb_buf);	/* frees mp! */
23894978Sgd78059 
23904978Sgd78059 	/*
23914978Sgd78059 	 * Statistics.
23924978Sgd78059 	 */
23934978Sgd78059 	mxfep->mxfe_opackets++;
23944978Sgd78059 	mxfep->mxfe_obytes += len;
23954978Sgd78059 	if (txb->txb_buf[0] & 0x1) {
23964978Sgd78059 		if (bcmp(txb->txb_buf, mxfe_broadcast, ETHERADDRL) != 0)
23974978Sgd78059 			mxfep->mxfe_multixmt++;
23984978Sgd78059 		else
23994978Sgd78059 			mxfep->mxfe_brdcstxmt++;
24004978Sgd78059 	}
24014978Sgd78059 
24024978Sgd78059 	/* note len is already known to be a small unsigned */
24034978Sgd78059 	control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE;
24044978Sgd78059 
24054978Sgd78059 	if (txsend == (MXFE_TXRING - 1))
24064978Sgd78059 		control |= TXCTL_ENDRING;
24074978Sgd78059 
24084978Sgd78059 	tmd = &mxfep->mxfe_txdescp[txsend];
24094978Sgd78059 
24104978Sgd78059 	SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV);
24114978Sgd78059 	PUTTXDESC(mxfep, tmd->desc_control, control);
24124978Sgd78059 	PUTTXDESC(mxfep, tmd->desc_buffer1, txb->txb_paddr);
24134978Sgd78059 	PUTTXDESC(mxfep, tmd->desc_buffer2, 0);
24144978Sgd78059 	PUTTXDESC(mxfep, tmd->desc_status, TXSTAT_OWN);
24154978Sgd78059 	/* sync the descriptor out to the device */
24164978Sgd78059 	SYNCTXDESC(mxfep, txsend, DDI_DMA_SYNC_FORDEV);
24174978Sgd78059 
24184978Sgd78059 	/*
24194978Sgd78059 	 * Note the new values of txavail and txsend.
24204978Sgd78059 	 */
24214978Sgd78059 	mxfep->mxfe_txavail--;
24224978Sgd78059 	mxfep->mxfe_txsend = (txsend + 1) % MXFE_TXRING;
24234978Sgd78059 
24244978Sgd78059 	/*
24254978Sgd78059 	 * It should never, ever take more than 5 seconds to drain
24264978Sgd78059 	 * the ring.  If it happens, then we are stuck!
24274978Sgd78059 	 */
24284978Sgd78059 	mxfep->mxfe_txstall_time = gethrtime() + (5 * 1000000000ULL);
24294978Sgd78059 
24304978Sgd78059 	/*
24314978Sgd78059 	 * wake up the chip ... inside the lock to protect against DR suspend,
24324978Sgd78059 	 * etc.
24334978Sgd78059 	 */
24344978Sgd78059 	PUTCSR(mxfep, CSR_TDR, 0);
24354978Sgd78059 
24364978Sgd78059 	return (B_TRUE);
24374978Sgd78059 }
24384978Sgd78059 
24394978Sgd78059 /*
24404978Sgd78059  * Reclaim buffers that have completed transmission.
24414978Sgd78059  */
24424978Sgd78059 void
mxfe_reclaim(mxfe_t * mxfep)24434978Sgd78059 mxfe_reclaim(mxfe_t *mxfep)
24444978Sgd78059 {
24454978Sgd78059 	mxfe_desc_t	*tmdp;
24464978Sgd78059 
24474978Sgd78059 	while (mxfep->mxfe_txavail != MXFE_TXRING) {
24484978Sgd78059 		uint32_t	status;
24494978Sgd78059 		uint32_t	control;
24504978Sgd78059 		int		index = mxfep->mxfe_txreclaim;
24514978Sgd78059 
24524978Sgd78059 		tmdp = &mxfep->mxfe_txdescp[index];
24534978Sgd78059 
24544978Sgd78059 		/* sync it before we read it */
24554978Sgd78059 		SYNCTXDESC(mxfep, index, DDI_DMA_SYNC_FORKERNEL);
24564978Sgd78059 
24574978Sgd78059 		control = GETTXDESC(mxfep, tmdp->desc_control);
24584978Sgd78059 		status = GETTXDESC(mxfep, tmdp->desc_status);
24594978Sgd78059 
24604978Sgd78059 		if (status & TXSTAT_OWN) {
24614978Sgd78059 			/* chip is still working on it, we're done */
24624978Sgd78059 			break;
24634978Sgd78059 		}
24644978Sgd78059 
24654978Sgd78059 		mxfep->mxfe_txavail++;
24664978Sgd78059 		mxfep->mxfe_txreclaim = (index + 1) % MXFE_TXRING;
24674978Sgd78059 
24684978Sgd78059 		/* in the most common successful case, all bits are clear */
24694978Sgd78059 		if (status == 0)
24704978Sgd78059 			continue;
24714978Sgd78059 
24724978Sgd78059 		if (((control & TXCTL_SETUP) != 0) ||
24734978Sgd78059 		    ((control & TXCTL_LAST) == 0)) {
24744978Sgd78059 			/* no interesting statistics here */
24754978Sgd78059 			continue;
24764978Sgd78059 		}
24774978Sgd78059 
24784978Sgd78059 		if (status & TXSTAT_TXERR) {
24794978Sgd78059 			mxfep->mxfe_errxmt++;
24804978Sgd78059 
24814978Sgd78059 			if (status & TXSTAT_JABBER) {
24824978Sgd78059 				/* transmit jabber timeout */
24834978Sgd78059 				mxfep->mxfe_macxmt_errors++;
24844978Sgd78059 			}
24854978Sgd78059 			if (status & (TXSTAT_CARRLOST | TXSTAT_NOCARR)) {
24864978Sgd78059 				mxfep->mxfe_carrier_errors++;
24874978Sgd78059 			}
24884978Sgd78059 			if (status & TXSTAT_UFLOW) {
24894978Sgd78059 				mxfep->mxfe_underflow++;
24904978Sgd78059 			}
24914978Sgd78059 			if (status & TXSTAT_LATECOL) {
24924978Sgd78059 				mxfep->mxfe_tx_late_collisions++;
24934978Sgd78059 			}
24944978Sgd78059 			if (status & TXSTAT_EXCOLL) {
24954978Sgd78059 				mxfep->mxfe_ex_collisions++;
24964978Sgd78059 				mxfep->mxfe_collisions += 16;
24974978Sgd78059 			}
24984978Sgd78059 		}
24994978Sgd78059 
25004978Sgd78059 		if (status & TXSTAT_DEFER) {
25014978Sgd78059 			mxfep->mxfe_defer_xmts++;
25024978Sgd78059 		}
25034978Sgd78059 
25044978Sgd78059 		/* collision counting */
25054978Sgd78059 		if (TXCOLLCNT(status) == 1) {
25064978Sgd78059 			mxfep->mxfe_collisions++;
25074978Sgd78059 			mxfep->mxfe_first_collisions++;
25084978Sgd78059 		} else if (TXCOLLCNT(status)) {
25094978Sgd78059 			mxfep->mxfe_collisions += TXCOLLCNT(status);
25104978Sgd78059 			mxfep->mxfe_multi_collisions += TXCOLLCNT(status);
25114978Sgd78059 		}
25124978Sgd78059 	}
25134978Sgd78059 
25144978Sgd78059 	if (mxfep->mxfe_txavail >= MXFE_TXRESCHED) {
25154978Sgd78059 		if (mxfep->mxfe_wantw) {
25164978Sgd78059 			/*
25174978Sgd78059 			 * we were able to reclaim some packets, so
25184978Sgd78059 			 * disable tx interrupts
25194978Sgd78059 			 */
25204978Sgd78059 			mxfep->mxfe_wantw = B_FALSE;
25214978Sgd78059 			mxfe_enableinterrupts(mxfep);
25224978Sgd78059 			mac_tx_update(mxfep->mxfe_mh);
25234978Sgd78059 		}
25244978Sgd78059 	}
25254978Sgd78059 }
25264978Sgd78059 
25279199Sgdamore@opensolaris.org boolean_t
mxfe_receive(mxfe_t * mxfep,mblk_t ** rxchain)25289199Sgdamore@opensolaris.org mxfe_receive(mxfe_t *mxfep, mblk_t **rxchain)
25294978Sgd78059 {
25304978Sgd78059 	unsigned		len;
25314978Sgd78059 	mxfe_rxbuf_t		*rxb;
25324978Sgd78059 	mxfe_desc_t		*rmd;
25334978Sgd78059 	uint32_t		status;
25344978Sgd78059 	mblk_t			*mpchain, **mpp, *mp;
25354978Sgd78059 	int			head, cnt;
25369199Sgdamore@opensolaris.org 	boolean_t		error = B_FALSE;
25374978Sgd78059 
25384978Sgd78059 	mpchain = NULL;
25394978Sgd78059 	mpp = &mpchain;
25404978Sgd78059 	head = mxfep->mxfe_rxhead;
25414978Sgd78059 
25424978Sgd78059 	/* limit the number of packets we process to a ring size */
25434978Sgd78059 	for (cnt = 0; cnt < MXFE_RXRING; cnt++) {
25444978Sgd78059 
25454978Sgd78059 		DBG(DRECV, "receive at index %d", head);
25464978Sgd78059 
25474978Sgd78059 		rmd = &mxfep->mxfe_rxdescp[head];
25484978Sgd78059 		rxb = mxfep->mxfe_rxbufs[head];
25494978Sgd78059 
25504978Sgd78059 		SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORKERNEL);
25514978Sgd78059 		status = GETRXDESC(mxfep, rmd->desc_status);
25524978Sgd78059 		if (status & RXSTAT_OWN) {
25534978Sgd78059 			/* chip is still chewing on it */
25544978Sgd78059 			break;
25554978Sgd78059 		}
25564978Sgd78059 
25574978Sgd78059 		/* discard the ethernet frame checksum */
25584978Sgd78059 		len = RXLENGTH(status) - ETHERFCSL;
25594978Sgd78059 
25604978Sgd78059 		DBG(DRECV, "recv length %d, status %x", len, status);
25614978Sgd78059 
25624978Sgd78059 		if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) !=
25634978Sgd78059 		    (RXSTAT_FIRST | RXSTAT_LAST)) {
25644978Sgd78059 
25654978Sgd78059 			mxfep->mxfe_errrcv++;
25664978Sgd78059 
25674978Sgd78059 			/*
25684978Sgd78059 			 * Abnormal status bits detected, analyze further.
25694978Sgd78059 			 */
25704978Sgd78059 			if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) !=
25714978Sgd78059 			    (RXSTAT_LAST|RXSTAT_FIRST)) {
25729199Sgdamore@opensolaris.org 				/* someone trying to send jumbo frames? */
25734978Sgd78059 				DBG(DRECV, "rx packet overspill");
25744978Sgd78059 				if (status & RXSTAT_FIRST) {
25754978Sgd78059 					mxfep->mxfe_toolong_errors++;
25764978Sgd78059 				}
25774978Sgd78059 			} else if (status & RXSTAT_DESCERR) {
25789199Sgdamore@opensolaris.org 				/* this should never occur! */
25794978Sgd78059 				mxfep->mxfe_macrcv_errors++;
25809199Sgdamore@opensolaris.org 				error = B_TRUE;
25814978Sgd78059 
25824978Sgd78059 			} else if (status & RXSTAT_RUNT) {
25834978Sgd78059 				mxfep->mxfe_runt++;
25844978Sgd78059 
25854978Sgd78059 			} else if (status & RXSTAT_COLLSEEN) {
25864978Sgd78059 				/* this should really be rx_late_collisions */
25874978Sgd78059 				mxfep->mxfe_macrcv_errors++;
25884978Sgd78059 
25894978Sgd78059 			} else if (status & RXSTAT_DRIBBLE) {
25904978Sgd78059 				mxfep->mxfe_align_errors++;
25914978Sgd78059 
25924978Sgd78059 			} else if (status & RXSTAT_CRCERR) {
25934978Sgd78059 				mxfep->mxfe_fcs_errors++;
25944978Sgd78059 
25954978Sgd78059 			} else if (status & RXSTAT_OFLOW) {
25969199Sgdamore@opensolaris.org 				/* this is a MAC FIFO error, need to reset */
25974978Sgd78059 				mxfep->mxfe_overflow++;
25989199Sgdamore@opensolaris.org 				error = B_TRUE;
25994978Sgd78059 			}
26004978Sgd78059 		}
26014978Sgd78059 
26024978Sgd78059 		else if (len > ETHERVLANMTU) {
26034978Sgd78059 			mxfep->mxfe_errrcv++;
26044978Sgd78059 			mxfep->mxfe_toolong_errors++;
26054978Sgd78059 		}
26064978Sgd78059 
26074978Sgd78059 		/*
26084978Sgd78059 		 * At this point, the chip thinks the packet is OK.
26094978Sgd78059 		 */
26104978Sgd78059 		else {
26114978Sgd78059 			mp = allocb(len + MXFE_HEADROOM, 0);
26124978Sgd78059 			if (mp == NULL) {
26134978Sgd78059 				mxfep->mxfe_errrcv++;
26144978Sgd78059 				mxfep->mxfe_norcvbuf++;
26154978Sgd78059 				goto skip;
26164978Sgd78059 			}
26174978Sgd78059 
26184978Sgd78059 			/* sync the buffer before we look at it */
26194978Sgd78059 			SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL);
26204978Sgd78059 			mp->b_rptr += MXFE_HEADROOM;
26214978Sgd78059 			mp->b_wptr = mp->b_rptr + len;
26224978Sgd78059 			bcopy((char *)rxb->rxb_buf, mp->b_rptr, len);
26234978Sgd78059 
26244978Sgd78059 			mxfep->mxfe_ipackets++;
26254978Sgd78059 			mxfep->mxfe_rbytes += len;
26264978Sgd78059 			if (status & RXSTAT_GROUP) {
26274978Sgd78059 				if (bcmp(mp->b_rptr, mxfe_broadcast,
26284978Sgd78059 				    ETHERADDRL) == 0)
26294978Sgd78059 					mxfep->mxfe_brdcstrcv++;
26304978Sgd78059 				else
26314978Sgd78059 					mxfep->mxfe_multircv++;
26324978Sgd78059 			}
26334978Sgd78059 			*mpp = mp;
26344978Sgd78059 			mpp = &mp->b_next;
26354978Sgd78059 		}
26364978Sgd78059 
26374978Sgd78059 skip:
26384978Sgd78059 		/* return ring entry to the hardware */
26394978Sgd78059 		PUTRXDESC(mxfep, rmd->desc_status, RXSTAT_OWN);
26404978Sgd78059 		SYNCRXDESC(mxfep, head, DDI_DMA_SYNC_FORDEV);
26414978Sgd78059 
26424978Sgd78059 		/* advance to next RMD */
26434978Sgd78059 		head = (head + 1) % MXFE_RXRING;
26444978Sgd78059 	}
26454978Sgd78059 
26464978Sgd78059 	mxfep->mxfe_rxhead = head;
26474978Sgd78059 
26489199Sgdamore@opensolaris.org 	*rxchain = mpchain;
26499199Sgdamore@opensolaris.org 	return (error);
26504978Sgd78059 }
26514978Sgd78059 
26524978Sgd78059 int
mxfe_m_stat(void * arg,uint_t stat,uint64_t * val)26534978Sgd78059 mxfe_m_stat(void *arg, uint_t stat, uint64_t *val)
26544978Sgd78059 {
26554978Sgd78059 	mxfe_t	*mxfep = arg;
26564978Sgd78059 
26574978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
26584978Sgd78059 	if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) == MXFE_RUNNING)
26594978Sgd78059 		mxfe_reclaim(mxfep);
26604978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
26614978Sgd78059 
26624978Sgd78059 	switch (stat) {
26634978Sgd78059 	case MAC_STAT_IFSPEED:
26644978Sgd78059 		*val = mxfep->mxfe_ifspeed;
26654978Sgd78059 		break;
26664978Sgd78059 
26674978Sgd78059 	case MAC_STAT_MULTIRCV:
26684978Sgd78059 		*val = mxfep->mxfe_multircv;
26694978Sgd78059 		break;
26704978Sgd78059 
26714978Sgd78059 	case MAC_STAT_BRDCSTRCV:
26724978Sgd78059 		*val = mxfep->mxfe_brdcstrcv;
26734978Sgd78059 		break;
26744978Sgd78059 
26754978Sgd78059 	case MAC_STAT_MULTIXMT:
26764978Sgd78059 		*val = mxfep->mxfe_multixmt;
26774978Sgd78059 		break;
26784978Sgd78059 
26794978Sgd78059 	case MAC_STAT_BRDCSTXMT:
26804978Sgd78059 		*val = mxfep->mxfe_brdcstxmt;
26814978Sgd78059 		break;
26824978Sgd78059 
26834978Sgd78059 	case MAC_STAT_IPACKETS:
26844978Sgd78059 		*val = mxfep->mxfe_ipackets;
26854978Sgd78059 		break;
26864978Sgd78059 
26874978Sgd78059 	case MAC_STAT_RBYTES:
26884978Sgd78059 		*val = mxfep->mxfe_rbytes;
26894978Sgd78059 		break;
26904978Sgd78059 
26914978Sgd78059 	case MAC_STAT_OPACKETS:
26924978Sgd78059 		*val = mxfep->mxfe_opackets;
26934978Sgd78059 		break;
26944978Sgd78059 
26954978Sgd78059 	case MAC_STAT_OBYTES:
26964978Sgd78059 		*val = mxfep->mxfe_obytes;
26974978Sgd78059 		break;
26984978Sgd78059 
26994978Sgd78059 	case MAC_STAT_NORCVBUF:
27004978Sgd78059 		*val = mxfep->mxfe_norcvbuf;
27014978Sgd78059 		break;
27024978Sgd78059 
27034978Sgd78059 	case MAC_STAT_NOXMTBUF:
27044978Sgd78059 		*val = mxfep->mxfe_noxmtbuf;
27054978Sgd78059 		break;
27064978Sgd78059 
27074978Sgd78059 	case MAC_STAT_COLLISIONS:
27084978Sgd78059 		*val = mxfep->mxfe_collisions;
27094978Sgd78059 		break;
27104978Sgd78059 
27114978Sgd78059 	case MAC_STAT_IERRORS:
27124978Sgd78059 		*val = mxfep->mxfe_errrcv;
27134978Sgd78059 		break;
27144978Sgd78059 
27154978Sgd78059 	case MAC_STAT_OERRORS:
27164978Sgd78059 		*val = mxfep->mxfe_errxmt;
27174978Sgd78059 		break;
27184978Sgd78059 
27194978Sgd78059 	case ETHER_STAT_LINK_DUPLEX:
27204978Sgd78059 		*val = mxfep->mxfe_duplex;
27214978Sgd78059 		break;
27224978Sgd78059 
27234978Sgd78059 	case ETHER_STAT_ALIGN_ERRORS:
27244978Sgd78059 		*val = mxfep->mxfe_align_errors;
27254978Sgd78059 		break;
27264978Sgd78059 
27274978Sgd78059 	case ETHER_STAT_FCS_ERRORS:
27284978Sgd78059 		*val = mxfep->mxfe_fcs_errors;
27294978Sgd78059 		break;
27304978Sgd78059 
27314978Sgd78059 	case ETHER_STAT_SQE_ERRORS:
27324978Sgd78059 		*val = mxfep->mxfe_sqe_errors;
27334978Sgd78059 		break;
27344978Sgd78059 
27354978Sgd78059 	case ETHER_STAT_DEFER_XMTS:
27364978Sgd78059 		*val = mxfep->mxfe_defer_xmts;
27374978Sgd78059 		break;
27384978Sgd78059 
27394978Sgd78059 	case ETHER_STAT_FIRST_COLLISIONS:
27404978Sgd78059 		*val  = mxfep->mxfe_first_collisions;
27414978Sgd78059 		break;
27424978Sgd78059 
27434978Sgd78059 	case ETHER_STAT_MULTI_COLLISIONS:
27444978Sgd78059 		*val = mxfep->mxfe_multi_collisions;
27454978Sgd78059 		break;
27464978Sgd78059 
27474978Sgd78059 	case ETHER_STAT_TX_LATE_COLLISIONS:
27484978Sgd78059 		*val = mxfep->mxfe_tx_late_collisions;
27494978Sgd78059 		break;
27504978Sgd78059 
27514978Sgd78059 	case ETHER_STAT_EX_COLLISIONS:
27524978Sgd78059 		*val = mxfep->mxfe_ex_collisions;
27534978Sgd78059 		break;
27544978Sgd78059 
27554978Sgd78059 	case ETHER_STAT_MACXMT_ERRORS:
27564978Sgd78059 		*val = mxfep->mxfe_macxmt_errors;
27574978Sgd78059 		break;
27584978Sgd78059 
27594978Sgd78059 	case ETHER_STAT_CARRIER_ERRORS:
27604978Sgd78059 		*val = mxfep->mxfe_carrier_errors;
27614978Sgd78059 		break;
27624978Sgd78059 
27634978Sgd78059 	case ETHER_STAT_TOOLONG_ERRORS:
27644978Sgd78059 		*val = mxfep->mxfe_toolong_errors;
27654978Sgd78059 		break;
27664978Sgd78059 
27674978Sgd78059 	case ETHER_STAT_MACRCV_ERRORS:
27684978Sgd78059 		*val = mxfep->mxfe_macrcv_errors;
27694978Sgd78059 		break;
27704978Sgd78059 
27714978Sgd78059 	case MAC_STAT_OVERFLOWS:
27724978Sgd78059 		*val = mxfep->mxfe_overflow;
27734978Sgd78059 		break;
27744978Sgd78059 
27754978Sgd78059 	case MAC_STAT_UNDERFLOWS:
27764978Sgd78059 		*val = mxfep->mxfe_underflow;
27774978Sgd78059 		break;
27784978Sgd78059 
27794978Sgd78059 	case ETHER_STAT_TOOSHORT_ERRORS:
27804978Sgd78059 		*val = mxfep->mxfe_runt;
27814978Sgd78059 		break;
27824978Sgd78059 
27834978Sgd78059 	case ETHER_STAT_JABBER_ERRORS:
27844978Sgd78059 		*val = mxfep->mxfe_jabber;
27854978Sgd78059 		break;
27864978Sgd78059 
27874978Sgd78059 	case ETHER_STAT_ADV_CAP_100T4:
27884978Sgd78059 		*val = mxfep->mxfe_adv_100T4;
27894978Sgd78059 		break;
27904978Sgd78059 
27914978Sgd78059 	case ETHER_STAT_LP_CAP_100T4:
27924978Sgd78059 		*val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_T4) ? 1 : 0;
27934978Sgd78059 		break;
27944978Sgd78059 
27956684Sgd78059 	case ETHER_STAT_CAP_100T4:
27966684Sgd78059 		*val = mxfep->mxfe_cap_100T4;
27976684Sgd78059 		break;
27986684Sgd78059 
27994978Sgd78059 	case ETHER_STAT_CAP_100FDX:
28006684Sgd78059 		*val = mxfep->mxfe_cap_100fdx;
28014978Sgd78059 		break;
28024978Sgd78059 
28034978Sgd78059 	case ETHER_STAT_CAP_100HDX:
28046684Sgd78059 		*val = mxfep->mxfe_cap_100hdx;
28054978Sgd78059 		break;
28064978Sgd78059 
28074978Sgd78059 	case ETHER_STAT_CAP_10FDX:
28086684Sgd78059 		*val = mxfep->mxfe_cap_10fdx;
28094978Sgd78059 		break;
28104978Sgd78059 
28114978Sgd78059 	case ETHER_STAT_CAP_10HDX:
28126684Sgd78059 		*val = mxfep->mxfe_cap_10hdx;
28134978Sgd78059 		break;
28144978Sgd78059 
28154978Sgd78059 	case ETHER_STAT_CAP_AUTONEG:
28166684Sgd78059 		*val = mxfep->mxfe_cap_aneg;
28174978Sgd78059 		break;
28184978Sgd78059 
28194978Sgd78059 	case ETHER_STAT_LINK_AUTONEG:
28204978Sgd78059 		*val = ((mxfep->mxfe_adv_aneg != 0) &&
28214978Sgd78059 		    ((mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) != 0));
28224978Sgd78059 		break;
28234978Sgd78059 
28244978Sgd78059 	case ETHER_STAT_ADV_CAP_100FDX:
28254978Sgd78059 		*val = mxfep->mxfe_adv_100fdx;
28264978Sgd78059 		break;
28274978Sgd78059 
28284978Sgd78059 	case ETHER_STAT_ADV_CAP_100HDX:
28294978Sgd78059 		*val = mxfep->mxfe_adv_100hdx;
28304978Sgd78059 		break;
28314978Sgd78059 
28324978Sgd78059 	case ETHER_STAT_ADV_CAP_10FDX:
28334978Sgd78059 		*val = mxfep->mxfe_adv_10fdx;
28344978Sgd78059 		break;
28354978Sgd78059 
28364978Sgd78059 	case ETHER_STAT_ADV_CAP_10HDX:
28374978Sgd78059 		*val = mxfep->mxfe_adv_10hdx;
28384978Sgd78059 		break;
28394978Sgd78059 
28404978Sgd78059 	case ETHER_STAT_ADV_CAP_AUTONEG:
28414978Sgd78059 		*val = mxfep->mxfe_adv_aneg;
28424978Sgd78059 		break;
28434978Sgd78059 
28444978Sgd78059 	case ETHER_STAT_LP_CAP_100FDX:
28454978Sgd78059 		*val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX_FD) ? 1 : 0;
28464978Sgd78059 		break;
28474978Sgd78059 
28484978Sgd78059 	case ETHER_STAT_LP_CAP_100HDX:
28494978Sgd78059 		*val = (mxfep->mxfe_anlpar & MII_ABILITY_100BASE_TX) ? 1 : 0;
28504978Sgd78059 		break;
28514978Sgd78059 
28524978Sgd78059 	case ETHER_STAT_LP_CAP_10FDX:
28534978Sgd78059 		*val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T_FD) ? 1 : 0;
28544978Sgd78059 		break;
28554978Sgd78059 
28564978Sgd78059 	case ETHER_STAT_LP_CAP_10HDX:
28574978Sgd78059 		*val = (mxfep->mxfe_anlpar & MII_ABILITY_10BASE_T) ? 1 : 0;
28584978Sgd78059 		break;
28594978Sgd78059 
28604978Sgd78059 	case ETHER_STAT_LP_CAP_AUTONEG:
28614978Sgd78059 		*val = (mxfep->mxfe_aner & MII_AN_EXP_LPCANAN) ? 1 : 0;
28624978Sgd78059 		break;
28634978Sgd78059 
28644978Sgd78059 	case ETHER_STAT_XCVR_ADDR:
28654978Sgd78059 		*val = mxfep->mxfe_phyaddr;
28664978Sgd78059 		break;
28674978Sgd78059 
28684978Sgd78059 	case ETHER_STAT_XCVR_ID:
28694978Sgd78059 		*val = mxfep->mxfe_phyid;
28704978Sgd78059 		break;
28714978Sgd78059 
28724978Sgd78059 	case ETHER_STAT_XCVR_INUSE:
28734978Sgd78059 		*val = mxfep->mxfe_phyinuse;
28744978Sgd78059 		break;
28754978Sgd78059 
28764978Sgd78059 	default:
28774978Sgd78059 		return (ENOTSUP);
28784978Sgd78059 	}
28794978Sgd78059 	return (0);
28804978Sgd78059 }
28814978Sgd78059 
28826684Sgd78059 /*ARGSUSED*/
28836684Sgd78059 int
mxfe_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)2884*11878SVenu.Iyer@Sun.COM mxfe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
2885*11878SVenu.Iyer@Sun.COM     void *val)
28864978Sgd78059 {
28876684Sgd78059 	mxfe_t		*mxfep = arg;
28886684Sgd78059 	int		err = 0;
2889*11878SVenu.Iyer@Sun.COM 
28906684Sgd78059 	switch (num) {
28916789Sam223141 	case MAC_PROP_DUPLEX:
2892*11878SVenu.Iyer@Sun.COM 		ASSERT(sz >= sizeof (link_duplex_t));
2893*11878SVenu.Iyer@Sun.COM 		bcopy(&mxfep->mxfe_duplex, val, sizeof (link_duplex_t));
28946684Sgd78059 		break;
28956684Sgd78059 
28966789Sam223141 	case MAC_PROP_SPEED:
2897*11878SVenu.Iyer@Sun.COM 		ASSERT(sz >= sizeof (uint64_t));
2898*11878SVenu.Iyer@Sun.COM 		bcopy(&mxfep->mxfe_ifspeed, val, sizeof (uint64_t));
28996684Sgd78059 		break;
29006684Sgd78059 
29016789Sam223141 	case MAC_PROP_AUTONEG:
2902*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = mxfep->mxfe_adv_aneg;
29036684Sgd78059 		break;
29046684Sgd78059 
29056789Sam223141 	case MAC_PROP_ADV_100FDX_CAP:
29066789Sam223141 	case MAC_PROP_EN_100FDX_CAP:
2907*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = mxfep->mxfe_adv_100fdx;
29086684Sgd78059 		break;
29096684Sgd78059 
29106789Sam223141 	case MAC_PROP_ADV_100HDX_CAP:
29116789Sam223141 	case MAC_PROP_EN_100HDX_CAP:
2912*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = mxfep->mxfe_adv_100hdx;
29136684Sgd78059 		break;
29146684Sgd78059 
29156789Sam223141 	case MAC_PROP_ADV_10FDX_CAP:
29166789Sam223141 	case MAC_PROP_EN_10FDX_CAP:
2917*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = mxfep->mxfe_adv_10fdx;
29186684Sgd78059 		break;
29196684Sgd78059 
29206789Sam223141 	case MAC_PROP_ADV_10HDX_CAP:
29216789Sam223141 	case MAC_PROP_EN_10HDX_CAP:
2922*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = mxfep->mxfe_adv_10hdx;
29236684Sgd78059 		break;
29246684Sgd78059 
29256789Sam223141 	case MAC_PROP_ADV_100T4_CAP:
29266789Sam223141 	case MAC_PROP_EN_100T4_CAP:
2927*11878SVenu.Iyer@Sun.COM 		*(uint8_t *)val = mxfep->mxfe_adv_100T4;
29286684Sgd78059 		break;
29296684Sgd78059 
29306684Sgd78059 	default:
29316684Sgd78059 		err = ENOTSUP;
29324978Sgd78059 	}
29336684Sgd78059 
29346684Sgd78059 	return (err);
29354978Sgd78059 }
29364978Sgd78059 
29374978Sgd78059 /*ARGSUSED*/
29384978Sgd78059 int
mxfe_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)29396684Sgd78059 mxfe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
29406684Sgd78059     const void *val)
29414978Sgd78059 {
29426684Sgd78059 	mxfe_t		*mxfep = arg;
29436684Sgd78059 	uint8_t		*advp;
29446684Sgd78059 	uint8_t		*capp;
29456684Sgd78059 
29466684Sgd78059 	switch (num) {
29476789Sam223141 	case MAC_PROP_EN_100FDX_CAP:
29486684Sgd78059 		advp = &mxfep->mxfe_adv_100fdx;
29496684Sgd78059 		capp = &mxfep->mxfe_cap_100fdx;
29506684Sgd78059 		break;
29516684Sgd78059 
29526789Sam223141 	case MAC_PROP_EN_100HDX_CAP:
29536684Sgd78059 		advp = &mxfep->mxfe_adv_100hdx;
29546684Sgd78059 		capp = &mxfep->mxfe_cap_100hdx;
29556684Sgd78059 		break;
29566684Sgd78059 
29576789Sam223141 	case MAC_PROP_EN_10FDX_CAP:
29586684Sgd78059 		advp = &mxfep->mxfe_adv_10fdx;
29596684Sgd78059 		capp = &mxfep->mxfe_cap_10fdx;
29606684Sgd78059 		break;
29616684Sgd78059 
29626789Sam223141 	case MAC_PROP_EN_10HDX_CAP:
29636684Sgd78059 		advp = &mxfep->mxfe_adv_10hdx;
29646684Sgd78059 		capp = &mxfep->mxfe_cap_10hdx;
29656684Sgd78059 		break;
29666684Sgd78059 
29676789Sam223141 	case MAC_PROP_EN_100T4_CAP:
29686684Sgd78059 		advp = &mxfep->mxfe_adv_100T4;
29696684Sgd78059 		capp = &mxfep->mxfe_cap_100T4;
29706684Sgd78059 		break;
29716684Sgd78059 
29726789Sam223141 	case MAC_PROP_AUTONEG:
29736684Sgd78059 		advp = &mxfep->mxfe_adv_aneg;
29746684Sgd78059 		capp = &mxfep->mxfe_cap_aneg;
29756684Sgd78059 		break;
29766684Sgd78059 
29776684Sgd78059 	default:
29786684Sgd78059 		return (ENOTSUP);
29796684Sgd78059 	}
29806684Sgd78059 
29816684Sgd78059 	if (*capp == 0)		/* ensure phy can support value */
29826684Sgd78059 		return (ENOTSUP);
29834978Sgd78059 
29844978Sgd78059 	mutex_enter(&mxfep->mxfe_intrlock);
29854978Sgd78059 	mutex_enter(&mxfep->mxfe_xmtlock);
29864978Sgd78059 
29876684Sgd78059 	if (*advp != *(const uint8_t *)val) {
29886684Sgd78059 		*advp = *(const uint8_t *)val;
29896684Sgd78059 
29904978Sgd78059 		if ((mxfep->mxfe_flags & (MXFE_RUNNING|MXFE_SUSPENDED)) ==
29914978Sgd78059 		    MXFE_RUNNING) {
29924978Sgd78059 			/*
29934978Sgd78059 			 * This re-initializes the phy, but it also
29944978Sgd78059 			 * restarts transmit and receive rings.
29954978Sgd78059 			 * Needless to say, changing the link
29964978Sgd78059 			 * parameters is destructive to traffic in
29974978Sgd78059 			 * progress.
29984978Sgd78059 			 */
29994978Sgd78059 			mxfe_resetall(mxfep);
30004978Sgd78059 		}
30014978Sgd78059 	}
30024978Sgd78059 	mutex_exit(&mxfep->mxfe_xmtlock);
30034978Sgd78059 	mutex_exit(&mxfep->mxfe_intrlock);
30044978Sgd78059 
30054978Sgd78059 	return (0);
30064978Sgd78059 }
30074978Sgd78059 
3008*11878SVenu.Iyer@Sun.COM static void
mxfe_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t mph)3009*11878SVenu.Iyer@Sun.COM mxfe_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
3010*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t mph)
3011*11878SVenu.Iyer@Sun.COM {
3012*11878SVenu.Iyer@Sun.COM 	mxfe_t		*mxfep = arg;
3013*11878SVenu.Iyer@Sun.COM 
3014*11878SVenu.Iyer@Sun.COM         _NOTE(ARGUNUSED(name));
3015*11878SVenu.Iyer@Sun.COM 
3016*11878SVenu.Iyer@Sun.COM 	switch (num) {
3017*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_DUPLEX:
3018*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_SPEED:
3019*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
3020*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
3021*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
3022*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
3023*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
3024*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ);
3025*11878SVenu.Iyer@Sun.COM 		break;
3026*11878SVenu.Iyer@Sun.COM 
3027*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_AUTONEG:
3028*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_aneg);
3029*11878SVenu.Iyer@Sun.COM 		break;
3030*11878SVenu.Iyer@Sun.COM 
3031*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
3032*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100fdx);
3033*11878SVenu.Iyer@Sun.COM 		break;
3034*11878SVenu.Iyer@Sun.COM 
3035*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
3036*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100hdx);
3037*11878SVenu.Iyer@Sun.COM 		break;
3038*11878SVenu.Iyer@Sun.COM 
3039*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
3040*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10fdx);
3041*11878SVenu.Iyer@Sun.COM 		break;
3042*11878SVenu.Iyer@Sun.COM 
3043*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
3044*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_10hdx);
3045*11878SVenu.Iyer@Sun.COM 		break;
3046*11878SVenu.Iyer@Sun.COM 
3047*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
3048*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(mph, mxfep->mxfe_cap_100T4);
3049*11878SVenu.Iyer@Sun.COM 		break;
3050*11878SVenu.Iyer@Sun.COM 	}
3051*11878SVenu.Iyer@Sun.COM }
3052*11878SVenu.Iyer@Sun.COM 
30534978Sgd78059 /*
30544978Sgd78059  * Debugging and error reporting.
30554978Sgd78059  */
30564978Sgd78059 void
mxfe_error(dev_info_t * dip,char * fmt,...)30574978Sgd78059 mxfe_error(dev_info_t *dip, char *fmt, ...)
30584978Sgd78059 {
30594978Sgd78059 	va_list	ap;
30604978Sgd78059 	char	buf[256];
30614978Sgd78059 
30624978Sgd78059 	va_start(ap, fmt);
30634978Sgd78059 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
30644978Sgd78059 	va_end(ap);
30654978Sgd78059 
30664978Sgd78059 	if (dip) {
30674978Sgd78059 		cmn_err(CE_WARN, "%s%d: %s",
30684978Sgd78059 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
30694978Sgd78059 	} else {
30704978Sgd78059 		cmn_err(CE_WARN, "mxfe: %s", buf);
30714978Sgd78059 	}
30724978Sgd78059 }
30734978Sgd78059 
30744978Sgd78059 #ifdef DEBUG
30754978Sgd78059 
30764978Sgd78059 void
mxfe_dprintf(mxfe_t * mxfep,const char * func,int level,char * fmt,...)30774978Sgd78059 mxfe_dprintf(mxfe_t *mxfep, const char *func, int level, char *fmt, ...)
30784978Sgd78059 {
30794978Sgd78059 	va_list	ap;
30804978Sgd78059 
30814978Sgd78059 	va_start(ap, fmt);
30824978Sgd78059 	if (mxfe_debug & level) {
30834978Sgd78059 		char	tag[64];
30844978Sgd78059 		char	buf[256];
30854978Sgd78059 
30864978Sgd78059 		if (mxfep && mxfep->mxfe_dip) {
30874978Sgd78059 			(void) snprintf(tag, sizeof (tag),
30884978Sgd78059 			    "%s%d", ddi_driver_name(mxfep->mxfe_dip),
30894978Sgd78059 			    ddi_get_instance(mxfep->mxfe_dip));
30904978Sgd78059 		} else {
30914978Sgd78059 			(void) snprintf(tag, sizeof (tag), "mxfe");
30924978Sgd78059 		}
30934978Sgd78059 
30944978Sgd78059 		(void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", tag,
30954978Sgd78059 		    func, fmt);
30964978Sgd78059 
30974978Sgd78059 		vcmn_err(CE_CONT, buf, ap);
30984978Sgd78059 	}
30994978Sgd78059 	va_end(ap);
31004978Sgd78059 }
31014978Sgd78059 
31024978Sgd78059 #endif
3103