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