xref: /titanic_51/usr/src/uts/common/io/afe/afe.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
11959748cSgd78059 /*
21959748cSgd78059  * Solaris driver for ethernet cards based on the ADMtek Centaur
31959748cSgd78059  *
41959748cSgd78059  * Copyright (c) 2007 by Garrett D'Amore <garrett@damore.org>.
51959748cSgd78059  * All rights reserved.
61959748cSgd78059  *
71959748cSgd78059  * Redistribution and use in source and binary forms, with or without
81959748cSgd78059  * modification, are permitted provided that the following conditions
91959748cSgd78059  * are met:
101959748cSgd78059  * 1. Redistributions of source code must retain the above copyright
111959748cSgd78059  *    notice, this list of conditions and the following disclaimer.
121959748cSgd78059  * 2. Redistributions in binary form must reproduce the above copyright
131959748cSgd78059  *    notice, this list of conditions and the following disclaimer in the
141959748cSgd78059  *    documentation and/or other materials provided with the distribution.
151959748cSgd78059  * 3. Neither the name of the author nor the names of any co-contributors
161959748cSgd78059  *    may be used to endorse or promote products derived from this software
171959748cSgd78059  *    without specific prior written permission.
181959748cSgd78059  *
191959748cSgd78059  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
201959748cSgd78059  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211959748cSgd78059  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221959748cSgd78059  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
231959748cSgd78059  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241959748cSgd78059  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251959748cSgd78059  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261959748cSgd78059  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271959748cSgd78059  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281959748cSgd78059  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291959748cSgd78059  * POSSIBILITY OF SUCH DAMAGE.
301959748cSgd78059  */
3196fb08b9Sgd78059 /*
32*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3396fb08b9Sgd78059  * Use is subject to license terms.
3496fb08b9Sgd78059  */
351959748cSgd78059 
361959748cSgd78059 
371959748cSgd78059 #include <sys/varargs.h>
381959748cSgd78059 #include <sys/types.h>
391959748cSgd78059 #include <sys/modctl.h>
401959748cSgd78059 #include <sys/conf.h>
411959748cSgd78059 #include <sys/devops.h>
421959748cSgd78059 #include <sys/stream.h>
431959748cSgd78059 #include <sys/strsun.h>
441959748cSgd78059 #include <sys/cmn_err.h>
451959748cSgd78059 #include <sys/ethernet.h>
461959748cSgd78059 #include <sys/kmem.h>
471959748cSgd78059 #include <sys/time.h>
481959748cSgd78059 #include <sys/crc32.h>
49bdb9230aSGarrett D'Amore #include <sys/mii.h>
501959748cSgd78059 #include <sys/miiregs.h>
511959748cSgd78059 #include <sys/mac.h>
521959748cSgd78059 #include <sys/mac_ether.h>
531959748cSgd78059 #include <sys/ddi.h>
541959748cSgd78059 #include <sys/sunddi.h>
55d62bc4baSyz147064 #include <sys/vlan.h>
561959748cSgd78059 
571959748cSgd78059 #include "afe.h"
581959748cSgd78059 #include "afeimpl.h"
591959748cSgd78059 
601959748cSgd78059 /*
611959748cSgd78059  * Driver globals.
621959748cSgd78059  */
631959748cSgd78059 
641959748cSgd78059 /* table of supported devices */
651959748cSgd78059 static afe_card_t afe_cards[] = {
661959748cSgd78059 
671959748cSgd78059 	/*
681959748cSgd78059 	 * ADMtek Centaur and Comet
691959748cSgd78059 	 */
701959748cSgd78059 	{ 0x1317, 0x0981, "ADMtek AL981", MODEL_COMET },
711959748cSgd78059 	{ 0x1317, 0x0985, "ADMtek AN983", MODEL_CENTAUR },
721959748cSgd78059 	{ 0x1317, 0x1985, "ADMtek AN985", MODEL_CENTAUR },
731959748cSgd78059 	{ 0x1317, 0x9511, "ADMtek ADM9511", MODEL_CENTAUR },
741959748cSgd78059 	{ 0x1317, 0x9513, "ADMtek ADM9513", MODEL_CENTAUR },
751959748cSgd78059 	/*
761959748cSgd78059 	 * Accton just relabels other companies' controllers
771959748cSgd78059 	 */
781959748cSgd78059 	{ 0x1113, 0x1216, "Accton EN5251", MODEL_CENTAUR },
791959748cSgd78059 	/*
801959748cSgd78059 	 * Models listed here.
811959748cSgd78059 	 */
821959748cSgd78059 	{ 0x10b7, 0x9300, "3Com 3CSOHO100B-TX", MODEL_CENTAUR },
831959748cSgd78059 	{ 0x1113, 0xec02, "SMC SMC1244TX", MODEL_CENTAUR },
841959748cSgd78059 	{ 0x10b8, 0x1255, "SMC SMC1255TX", MODEL_CENTAUR },
851959748cSgd78059 	{ 0x111a, 0x1020, "Siemens SpeedStream PCI 10/100", MODEL_CENTAUR },
861959748cSgd78059 	{ 0x1113, 0x1207, "Accton EN1207F", MODEL_CENTAUR },
871959748cSgd78059 	{ 0x1113, 0x2242, "Accton EN2242", MODEL_CENTAUR },
881959748cSgd78059 	{ 0x1113, 0x2220, "Accton EN2220", MODEL_CENTAUR },
891959748cSgd78059 	{ 0x1113, 0x9216, "3M VOL-N100VF+TX", MODEL_CENTAUR },
901959748cSgd78059 	{ 0x1317, 0x0574, "Linksys LNE100TX", MODEL_CENTAUR },
911959748cSgd78059 	{ 0x1317, 0x0570, "Linksys NC100", MODEL_CENTAUR },
921959748cSgd78059 	{ 0x1385, 0x511a, "Netgear FA511", MODEL_CENTAUR },
931959748cSgd78059 	{ 0x13d1, 0xab02, "AboCom FE2500", MODEL_CENTAUR },
941959748cSgd78059 	{ 0x13d1, 0xab03, "AboCom PCM200", MODEL_CENTAUR },
951959748cSgd78059 	{ 0x13d1, 0xab08, "AboCom FE2500MX", MODEL_CENTAUR },
961959748cSgd78059 	{ 0x1414, 0x0001, "Microsoft MN-120", MODEL_CENTAUR },
971959748cSgd78059 	{ 0x16ec, 0x00ed, "U.S. Robotics USR997900", MODEL_CENTAUR },
981959748cSgd78059 	{ 0x1734, 0x100c, "Fujitsu-Siemens D1961", MODEL_CENTAUR },
991959748cSgd78059 	{ 0x1737, 0xab08, "Linksys PCMPC200", MODEL_CENTAUR },
1001959748cSgd78059 	{ 0x1737, 0xab09, "Linksys PCM200", MODEL_CENTAUR },
1011959748cSgd78059 	{ 0x17b3, 0xab08, "Hawking PN672TX", MODEL_CENTAUR },
1021959748cSgd78059 };
1031959748cSgd78059 
1041959748cSgd78059 #define	ETHERVLANMTU	(ETHERMAX + 4)
1051959748cSgd78059 
1061959748cSgd78059 /*
1071959748cSgd78059  * Function prototypes
1081959748cSgd78059  */
1091959748cSgd78059 static int	afe_attach(dev_info_t *, ddi_attach_cmd_t);
1101959748cSgd78059 static int	afe_detach(dev_info_t *, ddi_detach_cmd_t);
1111959748cSgd78059 static int	afe_resume(dev_info_t *);
11238415b01SGarrett D'Amore static int	afe_quiesce(dev_info_t *);
1131959748cSgd78059 static int	afe_m_unicst(void *, const uint8_t *);
1141959748cSgd78059 static int	afe_m_multicst(void *, boolean_t, const uint8_t *);
1151959748cSgd78059 static int	afe_m_promisc(void *, boolean_t);
1161959748cSgd78059 static mblk_t	*afe_m_tx(void *, mblk_t *);
117bdb9230aSGarrett D'Amore static void	afe_m_ioctl(void *, queue_t *, mblk_t *);
1181959748cSgd78059 static int	afe_m_stat(void *, uint_t, uint64_t *);
1191959748cSgd78059 static int	afe_m_start(void *);
1201959748cSgd78059 static void	afe_m_stop(void *);
12196fb08b9Sgd78059 static int	afe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
122*0dc2366fSVenugopal Iyer     void *);
12396fb08b9Sgd78059 static int	afe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
12496fb08b9Sgd78059     const void *);
125*0dc2366fSVenugopal Iyer static void	afe_m_propinfo(void *, const char *, mac_prop_id_t,
126*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
1271959748cSgd78059 static unsigned	afe_intr(caddr_t);
1281959748cSgd78059 static void	afe_startmac(afe_t *);
1291959748cSgd78059 static void	afe_stopmac(afe_t *);
1301959748cSgd78059 static void	afe_resetrings(afe_t *);
1311959748cSgd78059 static boolean_t	afe_initialize(afe_t *);
1321959748cSgd78059 static void	afe_startall(afe_t *);
1331959748cSgd78059 static void	afe_stopall(afe_t *);
1341959748cSgd78059 static void	afe_resetall(afe_t *);
1351959748cSgd78059 static afe_txbuf_t *afe_alloctxbuf(afe_t *);
1361959748cSgd78059 static void	afe_destroytxbuf(afe_txbuf_t *);
1371959748cSgd78059 static afe_rxbuf_t *afe_allocrxbuf(afe_t *);
1381959748cSgd78059 static void	afe_destroyrxbuf(afe_rxbuf_t *);
1391959748cSgd78059 static boolean_t	afe_send(afe_t *, mblk_t *);
1401959748cSgd78059 static int	afe_allocrxring(afe_t *);
1411959748cSgd78059 static void	afe_freerxring(afe_t *);
1421959748cSgd78059 static int	afe_alloctxring(afe_t *);
1431959748cSgd78059 static void	afe_freetxring(afe_t *);
1441959748cSgd78059 static void	afe_error(dev_info_t *, char *, ...);
1451959748cSgd78059 static void	afe_setrxfilt(afe_t *);
146bdb9230aSGarrett D'Amore static int	afe_watchdog(afe_t *);
1471959748cSgd78059 static uint8_t	afe_sromwidth(afe_t *);
1481959748cSgd78059 static uint16_t	afe_readsromword(afe_t *, unsigned);
1491959748cSgd78059 static void	afe_readsrom(afe_t *, unsigned, unsigned, char *);
1501959748cSgd78059 static void	afe_getfactaddr(afe_t *, uchar_t *);
15196fb08b9Sgd78059 static uint8_t	afe_miireadbit(afe_t *);
15296fb08b9Sgd78059 static void	afe_miiwritebit(afe_t *, uint8_t);
1531959748cSgd78059 static void	afe_miitristate(afe_t *);
154bdb9230aSGarrett D'Amore static uint16_t	afe_miireadgeneral(afe_t *, uint8_t, uint8_t);
155bdb9230aSGarrett D'Amore static void	afe_miiwritegeneral(afe_t *, uint8_t, uint8_t, uint16_t);
156bdb9230aSGarrett D'Amore static uint16_t	afe_miireadcomet(afe_t *, uint8_t, uint8_t);
157bdb9230aSGarrett D'Amore static void	afe_miiwritecomet(afe_t *, uint8_t, uint8_t, uint16_t);
158bdb9230aSGarrett D'Amore static uint16_t	afe_mii_read(void *, uint8_t, uint8_t);
159bdb9230aSGarrett D'Amore static void	afe_mii_write(void *, uint8_t, uint8_t, uint16_t);
160bdb9230aSGarrett D'Amore static void	afe_mii_notify(void *, link_state_t);
161bdb9230aSGarrett D'Amore static void	afe_mii_reset(void *);
1621959748cSgd78059 static void	afe_disableinterrupts(afe_t *);
1631959748cSgd78059 static void	afe_enableinterrupts(afe_t *);
1641959748cSgd78059 static void	afe_reclaim(afe_t *);
1651959748cSgd78059 static mblk_t	*afe_receive(afe_t *);
1661959748cSgd78059 
1671959748cSgd78059 #define	KIOIP	KSTAT_INTR_PTR(afep->afe_intrstat)
1681959748cSgd78059 
169bdb9230aSGarrett D'Amore static mii_ops_t afe_mii_ops = {
170bdb9230aSGarrett D'Amore 	MII_OPS_VERSION,
171bdb9230aSGarrett D'Amore 	afe_mii_read,
172bdb9230aSGarrett D'Amore 	afe_mii_write,
173bdb9230aSGarrett D'Amore 	afe_mii_notify,
174bdb9230aSGarrett D'Amore 	afe_mii_reset
175bdb9230aSGarrett D'Amore };
176bdb9230aSGarrett D'Amore 
1771959748cSgd78059 static mac_callbacks_t afe_m_callbacks = {
178*0dc2366fSVenugopal Iyer 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
1791959748cSgd78059 	afe_m_stat,
1801959748cSgd78059 	afe_m_start,
1811959748cSgd78059 	afe_m_stop,
1821959748cSgd78059 	afe_m_promisc,
1831959748cSgd78059 	afe_m_multicst,
1841959748cSgd78059 	afe_m_unicst,
1851959748cSgd78059 	afe_m_tx,
186*0dc2366fSVenugopal Iyer 	NULL,
187bdb9230aSGarrett D'Amore 	afe_m_ioctl,	/* mc_ioctl */
18896fb08b9Sgd78059 	NULL,		/* mc_getcapab */
18996fb08b9Sgd78059 	NULL,		/* mc_open */
19096fb08b9Sgd78059 	NULL,		/* mc_close */
19196fb08b9Sgd78059 	afe_m_setprop,
19296fb08b9Sgd78059 	afe_m_getprop,
193*0dc2366fSVenugopal Iyer 	afe_m_propinfo
1941959748cSgd78059 };
1951959748cSgd78059 
1961959748cSgd78059 
1971959748cSgd78059 /*
1981959748cSgd78059  * Stream information
1991959748cSgd78059  */
2001959748cSgd78059 DDI_DEFINE_STREAM_OPS(afe_devops, nulldev, nulldev, afe_attach, afe_detach,
20138415b01SGarrett D'Amore     nodev, NULL, D_MP, NULL, afe_quiesce);
2021959748cSgd78059 
2031959748cSgd78059 /*
2041959748cSgd78059  * Module linkage information.
2051959748cSgd78059  */
2061959748cSgd78059 
2071959748cSgd78059 static struct modldrv afe_modldrv = {
2081959748cSgd78059 	&mod_driverops,			/* drv_modops */
2091959748cSgd78059 	"ADMtek Fast Ethernet",		/* drv_linkinfo */
2101959748cSgd78059 	&afe_devops			/* drv_dev_ops */
2111959748cSgd78059 };
2121959748cSgd78059 
2131959748cSgd78059 static struct modlinkage afe_modlinkage = {
2141959748cSgd78059 	MODREV_1,		/* ml_rev */
2151959748cSgd78059 	{ &afe_modldrv, NULL }	/* ml_linkage */
2161959748cSgd78059 };
2171959748cSgd78059 
2181959748cSgd78059 /*
2191959748cSgd78059  * Device attributes.
2201959748cSgd78059  */
2211959748cSgd78059 static ddi_device_acc_attr_t afe_devattr = {
2221959748cSgd78059 	DDI_DEVICE_ATTR_V0,
2231959748cSgd78059 	DDI_STRUCTURE_LE_ACC,
2241959748cSgd78059 	DDI_STRICTORDER_ACC
2251959748cSgd78059 };
2261959748cSgd78059 
2271959748cSgd78059 static ddi_device_acc_attr_t afe_bufattr = {
2281959748cSgd78059 	DDI_DEVICE_ATTR_V0,
2291959748cSgd78059 	DDI_NEVERSWAP_ACC,
2301959748cSgd78059 	DDI_STRICTORDER_ACC
2311959748cSgd78059 };
2321959748cSgd78059 
2331959748cSgd78059 static ddi_dma_attr_t afe_dma_attr = {
2341959748cSgd78059 	DMA_ATTR_V0,		/* dma_attr_version */
2351959748cSgd78059 	0,			/* dma_attr_addr_lo */
2361959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_addr_hi */
2371959748cSgd78059 	0x7FFFFFFFU,		/* dma_attr_count_max */
2381959748cSgd78059 	4,			/* dma_attr_align */
2391959748cSgd78059 	0x3F,			/* dma_attr_burstsizes */
2401959748cSgd78059 	1,			/* dma_attr_minxfer */
2411959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_maxxfer */
2421959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_seg */
2431959748cSgd78059 	1,			/* dma_attr_sgllen */
2441959748cSgd78059 	1,			/* dma_attr_granular */
2451959748cSgd78059 	0			/* dma_attr_flags */
2461959748cSgd78059 };
2471959748cSgd78059 
2481959748cSgd78059 /*
2491959748cSgd78059  * Tx buffers can be arbitrarily aligned.  Additionally, they can
2501959748cSgd78059  * cross a page boundary, so we use the two buffer addresses of the
2511959748cSgd78059  * chip to provide a two-entry scatter-gather list.
2521959748cSgd78059  */
2531959748cSgd78059 static ddi_dma_attr_t afe_dma_txattr = {
2541959748cSgd78059 	DMA_ATTR_V0,		/* dma_attr_version */
2551959748cSgd78059 	0,			/* dma_attr_addr_lo */
2561959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_addr_hi */
2571959748cSgd78059 	0x7FFFFFFFU,		/* dma_attr_count_max */
2581959748cSgd78059 	1,			/* dma_attr_align */
2591959748cSgd78059 	0x3F,			/* dma_attr_burstsizes */
2601959748cSgd78059 	1,			/* dma_attr_minxfer */
2611959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_maxxfer */
2621959748cSgd78059 	0xFFFFFFFFU,		/* dma_attr_seg */
2631959748cSgd78059 	2,			/* dma_attr_sgllen */
2641959748cSgd78059 	1,			/* dma_attr_granular */
2651959748cSgd78059 	0			/* dma_attr_flags */
2661959748cSgd78059 };
2671959748cSgd78059 
2681959748cSgd78059 /*
2691959748cSgd78059  * Ethernet addresses.
2701959748cSgd78059  */
2711959748cSgd78059 static uchar_t afe_broadcast[ETHERADDRL] = {
2721959748cSgd78059 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2731959748cSgd78059 };
2741959748cSgd78059 
2751959748cSgd78059 /*
2761959748cSgd78059  * DDI entry points.
2771959748cSgd78059  */
2781959748cSgd78059 int
2791959748cSgd78059 _init(void)
2801959748cSgd78059 {
2811959748cSgd78059 	int	rv;
2821959748cSgd78059 	mac_init_ops(&afe_devops, "afe");
2831959748cSgd78059 	if ((rv = mod_install(&afe_modlinkage)) != DDI_SUCCESS) {
2841959748cSgd78059 		mac_fini_ops(&afe_devops);
2851959748cSgd78059 	}
2861959748cSgd78059 	return (rv);
2871959748cSgd78059 }
2881959748cSgd78059 
2891959748cSgd78059 int
2901959748cSgd78059 _fini(void)
2911959748cSgd78059 {
2921959748cSgd78059 	int	rv;
2931959748cSgd78059 	if ((rv = mod_remove(&afe_modlinkage)) == DDI_SUCCESS) {
2941959748cSgd78059 		mac_fini_ops(&afe_devops);
2951959748cSgd78059 	}
2961959748cSgd78059 	return (rv);
2971959748cSgd78059 }
2981959748cSgd78059 
2991959748cSgd78059 int
3001959748cSgd78059 _info(struct modinfo *modinfop)
3011959748cSgd78059 {
3021959748cSgd78059 	return (mod_info(&afe_modlinkage, modinfop));
3031959748cSgd78059 }
3041959748cSgd78059 
3051959748cSgd78059 int
3061959748cSgd78059 afe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3071959748cSgd78059 {
3081959748cSgd78059 	afe_t			*afep;
3091959748cSgd78059 	mac_register_t		*macp;
3101959748cSgd78059 	int			inst = ddi_get_instance(dip);
3111959748cSgd78059 	ddi_acc_handle_t	pci;
3121959748cSgd78059 	uint16_t		venid;
3131959748cSgd78059 	uint16_t		devid;
3141959748cSgd78059 	uint16_t		svid;
3151959748cSgd78059 	uint16_t		ssid;
3161959748cSgd78059 	uint16_t		cachesize;
3171959748cSgd78059 	afe_card_t		*cardp;
3181959748cSgd78059 	int			i;
3191959748cSgd78059 
3201959748cSgd78059 	switch (cmd) {
3211959748cSgd78059 	case DDI_RESUME:
3221959748cSgd78059 		return (afe_resume(dip));
3231959748cSgd78059 
3241959748cSgd78059 	case DDI_ATTACH:
3251959748cSgd78059 		break;
3261959748cSgd78059 
3271959748cSgd78059 	default:
3281959748cSgd78059 		return (DDI_FAILURE);
3291959748cSgd78059 	}
3301959748cSgd78059 
3311959748cSgd78059 	/* this card is a bus master, reject any slave-only slot */
3321959748cSgd78059 	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
3331959748cSgd78059 		afe_error(dip, "slot does not support PCI bus-master");
3341959748cSgd78059 		return (DDI_FAILURE);
3351959748cSgd78059 	}
3361959748cSgd78059 	/* PCI devices shouldn't generate hilevel interrupts */
3371959748cSgd78059 	if (ddi_intr_hilevel(dip, 0) != 0) {
3381959748cSgd78059 		afe_error(dip, "hilevel interrupts not supported");
3391959748cSgd78059 		return (DDI_FAILURE);
3401959748cSgd78059 	}
3411959748cSgd78059 	if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
3421959748cSgd78059 		afe_error(dip, "unable to setup PCI config handle");
3431959748cSgd78059 		return (DDI_FAILURE);
3441959748cSgd78059 	}
3451959748cSgd78059 
3461959748cSgd78059 	venid = pci_config_get16(pci, PCI_VID);
3471959748cSgd78059 	devid = pci_config_get16(pci, PCI_DID);
3481959748cSgd78059 	svid = pci_config_get16(pci, PCI_SVID);
3491959748cSgd78059 	ssid = pci_config_get16(pci, PCI_SSID);
3501959748cSgd78059 
3511959748cSgd78059 	/*
3521959748cSgd78059 	 * Note: ADMtek boards seem to misprogram themselves with bogus
3531959748cSgd78059 	 * timings, which do not seem to work properly on SPARC.  We
3541959748cSgd78059 	 * reprogram them zero (but only if they appear to be broken),
3551959748cSgd78059 	 * which seems to at least work.  Its unclear that this is a
3561959748cSgd78059 	 * legal or wise practice to me, but it certainly works better
3571959748cSgd78059 	 * than the original values.  (I would love to hear
3581959748cSgd78059 	 * suggestions for better values, or a better strategy.)
3591959748cSgd78059 	 */
3601959748cSgd78059 	if ((pci_config_get8(pci, PCI_MINGNT) == 0xff) &&
3611959748cSgd78059 	    (pci_config_get8(pci, PCI_MAXLAT) == 0xff)) {
3621959748cSgd78059 		pci_config_put8(pci, PCI_MINGNT, 0);
3631959748cSgd78059 		pci_config_put8(pci, PCI_MAXLAT, 0);
3641959748cSgd78059 	}
3651959748cSgd78059 
3661959748cSgd78059 	/*
3671959748cSgd78059 	 * the last entry in the card table matches every possible
3681959748cSgd78059 	 * card, so the for-loop always terminates properly.
3691959748cSgd78059 	 */
3701959748cSgd78059 	cardp = NULL;
3711959748cSgd78059 	for (i = 0; i < (sizeof (afe_cards) / sizeof (afe_card_t)); i++) {
3721959748cSgd78059 		if ((venid == afe_cards[i].card_venid) &&
3731959748cSgd78059 		    (devid == afe_cards[i].card_devid)) {
3741959748cSgd78059 			cardp = &afe_cards[i];
3751959748cSgd78059 		}
3761959748cSgd78059 		if ((svid == afe_cards[i].card_venid) &&
3771959748cSgd78059 		    (ssid == afe_cards[i].card_devid)) {
3781959748cSgd78059 			cardp = &afe_cards[i];
3791959748cSgd78059 			break;
3801959748cSgd78059 		}
3811959748cSgd78059 	}
3821959748cSgd78059 
3831959748cSgd78059 	if (cardp == NULL) {
3841959748cSgd78059 		pci_config_teardown(&pci);
3851959748cSgd78059 		afe_error(dip, "Unable to identify PCI card");
3861959748cSgd78059 		return (DDI_FAILURE);
3871959748cSgd78059 	}
3881959748cSgd78059 
3891959748cSgd78059 	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
3901959748cSgd78059 	    cardp->card_cardname) != DDI_PROP_SUCCESS) {
3911959748cSgd78059 		pci_config_teardown(&pci);
3921959748cSgd78059 		afe_error(dip, "Unable to create model property");
3931959748cSgd78059 		return (DDI_FAILURE);
3941959748cSgd78059 	}
3951959748cSgd78059 
3961959748cSgd78059 	/*
3971959748cSgd78059 	 * Grab the PCI cachesize -- we use this to program the
3981959748cSgd78059 	 * cache-optimization bus access bits.
3991959748cSgd78059 	 */
4001959748cSgd78059 	cachesize = pci_config_get8(pci, PCI_CLS);
4011959748cSgd78059 
4021959748cSgd78059 	/* this cannot fail */
4031959748cSgd78059 	afep = kmem_zalloc(sizeof (afe_t), KM_SLEEP);
4041959748cSgd78059 	ddi_set_driver_private(dip, afep);
4051959748cSgd78059 
4061959748cSgd78059 	/* get the interrupt block cookie */
4071959748cSgd78059 	if (ddi_get_iblock_cookie(dip, 0, &afep->afe_icookie) != DDI_SUCCESS) {
4081959748cSgd78059 		afe_error(dip, "ddi_get_iblock_cookie failed");
4091959748cSgd78059 		pci_config_teardown(&pci);
4101959748cSgd78059 		kmem_free(afep, sizeof (afe_t));
4111959748cSgd78059 		return (DDI_FAILURE);
4121959748cSgd78059 	}
4131959748cSgd78059 
4141959748cSgd78059 	afep->afe_dip = dip;
4151959748cSgd78059 	afep->afe_cardp = cardp;
4161959748cSgd78059 	afep->afe_phyaddr = -1;
4171959748cSgd78059 	afep->afe_cachesize = cachesize;
4181959748cSgd78059 
4191959748cSgd78059 	afep->afe_forcefiber = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
4201959748cSgd78059 	    "fiber", 0);
4211959748cSgd78059 
4221959748cSgd78059 	mutex_init(&afep->afe_xmtlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
4231959748cSgd78059 	mutex_init(&afep->afe_intrlock, NULL, MUTEX_DRIVER, afep->afe_icookie);
4241959748cSgd78059 
4251959748cSgd78059 	/*
4261959748cSgd78059 	 * Enable bus master, IO space, and memory space accesses.
4271959748cSgd78059 	 */
4281959748cSgd78059 	pci_config_put16(pci, PCI_CMD,
4291959748cSgd78059 	    pci_config_get16(pci, PCI_CMD) | PCI_CMD_BME | PCI_CMD_MAE);
4301959748cSgd78059 
4311959748cSgd78059 	/* we're done with this now, drop it */
4321959748cSgd78059 	pci_config_teardown(&pci);
4331959748cSgd78059 
4341959748cSgd78059 	/*
4351959748cSgd78059 	 * Initialize interrupt kstat.  This should not normally fail, since
4361959748cSgd78059 	 * we don't use a persistent stat.  We do it this way to avoid having
4371959748cSgd78059 	 * to test for it at run time on the hot path.
4381959748cSgd78059 	 */
4391959748cSgd78059 	afep->afe_intrstat = kstat_create("afe", inst, "intr", "controller",
4401959748cSgd78059 	    KSTAT_TYPE_INTR, 1, 0);
4411959748cSgd78059 	if (afep->afe_intrstat == NULL) {
4421959748cSgd78059 		afe_error(dip, "kstat_create failed");
4431959748cSgd78059 		goto failed;
4441959748cSgd78059 	}
4451959748cSgd78059 	kstat_install(afep->afe_intrstat);
4461959748cSgd78059 
4471959748cSgd78059 	/*
448bdb9230aSGarrett D'Amore 	 * Set up the MII.
449bdb9230aSGarrett D'Amore 	 */
450bdb9230aSGarrett D'Amore 	if ((afep->afe_mii = mii_alloc(afep, dip, &afe_mii_ops)) == NULL) {
451bdb9230aSGarrett D'Amore 		goto failed;
452bdb9230aSGarrett D'Amore 	}
453bdb9230aSGarrett D'Amore 
454bdb9230aSGarrett D'Amore 	/*
455bdb9230aSGarrett D'Amore 	 * Centaur can support PAUSE, but Comet can't.
456bdb9230aSGarrett D'Amore 	 */
457bdb9230aSGarrett D'Amore 	if (AFE_MODEL(afep) == MODEL_CENTAUR) {
458bdb9230aSGarrett D'Amore 		mii_set_pauseable(afep->afe_mii, B_TRUE, B_FALSE);
459bdb9230aSGarrett D'Amore 	} else {
460bdb9230aSGarrett D'Amore 		mii_set_pauseable(afep->afe_mii, B_FALSE, B_FALSE);
461bdb9230aSGarrett D'Amore 	}
462bdb9230aSGarrett D'Amore 
463bdb9230aSGarrett D'Amore 	/*
4641959748cSgd78059 	 * Map in the device registers.
4651959748cSgd78059 	 */
4661959748cSgd78059 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&afep->afe_regs,
4671959748cSgd78059 	    0, 0, &afe_devattr, &afep->afe_regshandle)) {
4681959748cSgd78059 		afe_error(dip, "ddi_regs_map_setup failed");
4691959748cSgd78059 		goto failed;
4701959748cSgd78059 	}
4711959748cSgd78059 
4721959748cSgd78059 	/*
4731959748cSgd78059 	 * Allocate DMA resources (descriptor rings and buffers).
4741959748cSgd78059 	 */
4751959748cSgd78059 	if ((afe_allocrxring(afep) != DDI_SUCCESS) ||
4761959748cSgd78059 	    (afe_alloctxring(afep) != DDI_SUCCESS)) {
4771959748cSgd78059 		afe_error(dip, "unable to allocate DMA resources");
4781959748cSgd78059 		goto failed;
4791959748cSgd78059 	}
4801959748cSgd78059 
4811959748cSgd78059 	/* Initialize the chip. */
4821959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
4831959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
4841959748cSgd78059 	if (!afe_initialize(afep)) {
4851959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
4861959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
4871959748cSgd78059 		goto failed;
4881959748cSgd78059 	}
4891959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
4901959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
4911959748cSgd78059 
4921959748cSgd78059 	/* Determine the number of address bits to our EEPROM. */
4931959748cSgd78059 	afep->afe_sromwidth = afe_sromwidth(afep);
4941959748cSgd78059 
4951959748cSgd78059 	/*
4961959748cSgd78059 	 * Get the factory ethernet address.  This becomes the current
4971959748cSgd78059 	 * ethernet address (it can be overridden later via ifconfig).
4981959748cSgd78059 	 */
4991959748cSgd78059 	afe_getfactaddr(afep, afep->afe_curraddr);
5001959748cSgd78059 	afep->afe_promisc = B_FALSE;
5011959748cSgd78059 
5021959748cSgd78059 	/* make sure we add configure the initial filter */
5031959748cSgd78059 	(void) afe_m_unicst(afep, afep->afe_curraddr);
5041959748cSgd78059 	(void) afe_m_multicst(afep, B_TRUE, afe_broadcast);
5051959748cSgd78059 
5061959748cSgd78059 	/*
5071959748cSgd78059 	 * Establish interrupt handler.
5081959748cSgd78059 	 */
5091959748cSgd78059 	if (ddi_add_intr(dip, 0, NULL, NULL, afe_intr, (caddr_t)afep) !=
5101959748cSgd78059 	    DDI_SUCCESS) {
5111959748cSgd78059 		afe_error(dip, "unable to add interrupt");
5121959748cSgd78059 		goto failed;
5131959748cSgd78059 	}
5141959748cSgd78059 
5151959748cSgd78059 	/* TODO: do the power management stuff */
5161959748cSgd78059 
5171959748cSgd78059 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
5181959748cSgd78059 		afe_error(dip, "mac_alloc failed");
5191959748cSgd78059 		goto failed;
5201959748cSgd78059 	}
5211959748cSgd78059 
5221959748cSgd78059 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
5231959748cSgd78059 	macp->m_driver = afep;
5241959748cSgd78059 	macp->m_dip = dip;
5251959748cSgd78059 	macp->m_src_addr = afep->afe_curraddr;
5261959748cSgd78059 	macp->m_callbacks = &afe_m_callbacks;
5271959748cSgd78059 	macp->m_min_sdu = 0;
5281959748cSgd78059 	macp->m_max_sdu = ETHERMTU;
529d62bc4baSyz147064 	macp->m_margin = VLAN_TAGSZ;
5301959748cSgd78059 
5311959748cSgd78059 	if (mac_register(macp, &afep->afe_mh) == DDI_SUCCESS) {
5321959748cSgd78059 		mac_free(macp);
5331959748cSgd78059 		return (DDI_SUCCESS);
5341959748cSgd78059 	}
5351959748cSgd78059 
5361959748cSgd78059 	/* failed to register with MAC */
5371959748cSgd78059 	mac_free(macp);
5381959748cSgd78059 failed:
5391959748cSgd78059 	if (afep->afe_icookie != NULL) {
5401959748cSgd78059 		ddi_remove_intr(dip, 0, afep->afe_icookie);
5411959748cSgd78059 	}
5421959748cSgd78059 	if (afep->afe_intrstat) {
5431959748cSgd78059 		kstat_delete(afep->afe_intrstat);
5441959748cSgd78059 	}
5451959748cSgd78059 	mutex_destroy(&afep->afe_intrlock);
5461959748cSgd78059 	mutex_destroy(&afep->afe_xmtlock);
5471959748cSgd78059 
5481959748cSgd78059 	afe_freerxring(afep);
5491959748cSgd78059 	afe_freetxring(afep);
5501959748cSgd78059 
5511959748cSgd78059 	if (afep->afe_regshandle != NULL) {
5521959748cSgd78059 		ddi_regs_map_free(&afep->afe_regshandle);
5531959748cSgd78059 	}
5541959748cSgd78059 	kmem_free(afep, sizeof (afe_t));
5551959748cSgd78059 	return (DDI_FAILURE);
5561959748cSgd78059 }
5571959748cSgd78059 
5581959748cSgd78059 int
5591959748cSgd78059 afe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5601959748cSgd78059 {
5611959748cSgd78059 	afe_t		*afep;
5621959748cSgd78059 
5631959748cSgd78059 	afep = ddi_get_driver_private(dip);
5641959748cSgd78059 	if (afep == NULL) {
5651959748cSgd78059 		afe_error(dip, "no soft state in detach!");
5661959748cSgd78059 		return (DDI_FAILURE);
5671959748cSgd78059 	}
5681959748cSgd78059 
5691959748cSgd78059 	switch (cmd) {
5701959748cSgd78059 	case DDI_DETACH:
5711959748cSgd78059 
5721959748cSgd78059 		if (mac_unregister(afep->afe_mh) != 0) {
5731959748cSgd78059 			return (DDI_FAILURE);
5741959748cSgd78059 		}
5751959748cSgd78059 
5761959748cSgd78059 		/* make sure hardware is quiesced */
5771959748cSgd78059 		mutex_enter(&afep->afe_intrlock);
5781959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
5791959748cSgd78059 		afep->afe_flags &= ~AFE_RUNNING;
5801959748cSgd78059 		afe_stopall(afep);
5811959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
5821959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
5831959748cSgd78059 
5841959748cSgd78059 		/* clean up and shut down device */
5851959748cSgd78059 		ddi_remove_intr(dip, 0, afep->afe_icookie);
5861959748cSgd78059 
587bdb9230aSGarrett D'Amore 		/* clean up MII layer */
588bdb9230aSGarrett D'Amore 		mii_free(afep->afe_mii);
589bdb9230aSGarrett D'Amore 
5901959748cSgd78059 		/* clean up kstats */
5911959748cSgd78059 		kstat_delete(afep->afe_intrstat);
5921959748cSgd78059 
5931959748cSgd78059 		ddi_prop_remove_all(dip);
5941959748cSgd78059 
5951959748cSgd78059 		/* free up any left over buffers or DMA resources */
5961959748cSgd78059 		afe_freerxring(afep);
5971959748cSgd78059 		afe_freetxring(afep);
5981959748cSgd78059 
5991959748cSgd78059 		ddi_regs_map_free(&afep->afe_regshandle);
6001959748cSgd78059 		mutex_destroy(&afep->afe_intrlock);
6011959748cSgd78059 		mutex_destroy(&afep->afe_xmtlock);
6021959748cSgd78059 
6031959748cSgd78059 		kmem_free(afep, sizeof (afe_t));
6041959748cSgd78059 		return (DDI_SUCCESS);
6051959748cSgd78059 
6061959748cSgd78059 	case DDI_SUSPEND:
607bdb9230aSGarrett D'Amore 		/* stop MII monitoring */
608bdb9230aSGarrett D'Amore 		mii_suspend(afep->afe_mii);
609bdb9230aSGarrett D'Amore 
6101959748cSgd78059 		/* quiesce the hardware */
6111959748cSgd78059 		mutex_enter(&afep->afe_intrlock);
6121959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
6131959748cSgd78059 		afep->afe_flags |= AFE_SUSPENDED;
6141959748cSgd78059 		afe_stopall(afep);
6151959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
6161959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
6171959748cSgd78059 		return (DDI_SUCCESS);
6181959748cSgd78059 	default:
6191959748cSgd78059 		return (DDI_FAILURE);
6201959748cSgd78059 	}
6211959748cSgd78059 }
6221959748cSgd78059 
6231959748cSgd78059 int
6241959748cSgd78059 afe_resume(dev_info_t *dip)
6251959748cSgd78059 {
6261959748cSgd78059 	afe_t	*afep;
6271959748cSgd78059 
6281959748cSgd78059 	if ((afep = ddi_get_driver_private(dip)) == NULL) {
6291959748cSgd78059 		return (DDI_FAILURE);
6301959748cSgd78059 	}
6311959748cSgd78059 
6321959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
6331959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
6341959748cSgd78059 
6351959748cSgd78059 	afep->afe_flags &= ~AFE_SUSPENDED;
6361959748cSgd78059 
6371959748cSgd78059 	/* re-initialize chip */
6381959748cSgd78059 	if (!afe_initialize(afep)) {
6391959748cSgd78059 		afe_error(afep->afe_dip, "unable to resume chip!");
6401959748cSgd78059 		afep->afe_flags |= AFE_SUSPENDED;
6411959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
6421959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
6431959748cSgd78059 		return (DDI_SUCCESS);
6441959748cSgd78059 	}
6451959748cSgd78059 
6461959748cSgd78059 	/* start the chip */
6471959748cSgd78059 	if (afep->afe_flags & AFE_RUNNING) {
6481959748cSgd78059 		afe_startall(afep);
6491959748cSgd78059 	}
6501959748cSgd78059 
6511959748cSgd78059 	/* drop locks */
6521959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
6531959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
6541959748cSgd78059 
655bdb9230aSGarrett D'Amore 	mii_resume(afep->afe_mii);
656bdb9230aSGarrett D'Amore 
6571959748cSgd78059 	return (DDI_SUCCESS);
6581959748cSgd78059 }
6591959748cSgd78059 
66038415b01SGarrett D'Amore int
66138415b01SGarrett D'Amore afe_quiesce(dev_info_t *dip)
66238415b01SGarrett D'Amore {
66338415b01SGarrett D'Amore 	afe_t	*afep;
66438415b01SGarrett D'Amore 
66538415b01SGarrett D'Amore 	if ((afep = ddi_get_driver_private(dip)) == NULL) {
66638415b01SGarrett D'Amore 		return (DDI_FAILURE);
66738415b01SGarrett D'Amore 	}
66838415b01SGarrett D'Amore 
66938415b01SGarrett D'Amore 	SETBIT(afep, CSR_PAR, PAR_RESET);
67038415b01SGarrett D'Amore 	/*
67138415b01SGarrett D'Amore 	 * At 66 MHz it is 16 nsec per access or more (always more)
67238415b01SGarrett D'Amore 	 * So we need 3,333 times to retry for 50 usec.  We just
67338415b01SGarrett D'Amore 	 * round up to 5000 times.  Unless the hardware is horked,
67438415b01SGarrett D'Amore 	 * it will always terminate *well* before that anyway.
67538415b01SGarrett D'Amore 	 */
67638415b01SGarrett D'Amore 	for (int i = 0; i < 5000; i++) {
67738415b01SGarrett D'Amore 		if ((GETCSR(afep, CSR_PAR) & PAR_RESET) == 0) {
67838415b01SGarrett D'Amore 			return (DDI_SUCCESS);
67938415b01SGarrett D'Amore 		}
68038415b01SGarrett D'Amore 	}
68138415b01SGarrett D'Amore 
68238415b01SGarrett D'Amore 	/* hardware didn't quiesce - force a full reboot (PCI reset) */
68338415b01SGarrett D'Amore 	return (DDI_FAILURE);
68438415b01SGarrett D'Amore }
68538415b01SGarrett D'Amore 
6861959748cSgd78059 void
6871959748cSgd78059 afe_setrxfilt(afe_t *afep)
6881959748cSgd78059 {
6891959748cSgd78059 	unsigned rxen, pa0, pa1;
6901959748cSgd78059 
6911959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
6921959748cSgd78059 		/* don't touch a suspended interface */
6931959748cSgd78059 		return;
6941959748cSgd78059 	}
6951959748cSgd78059 
6961959748cSgd78059 	rxen = GETCSR(afep, CSR_NAR) & NAR_RX_ENABLE;
6971959748cSgd78059 
6981959748cSgd78059 	/* stop receiver */
6991959748cSgd78059 	if (rxen) {
7001959748cSgd78059 		afe_stopmac(afep);
7011959748cSgd78059 	}
7021959748cSgd78059 
7031959748cSgd78059 	/* program promiscuous mode */
7041959748cSgd78059 	if (afep->afe_promisc)
7051959748cSgd78059 		SETBIT(afep, CSR_NAR, NAR_RX_PROMISC);
7061959748cSgd78059 	else
7071959748cSgd78059 		CLRBIT(afep, CSR_NAR, NAR_RX_PROMISC);
7081959748cSgd78059 
7091959748cSgd78059 	/* program mac address */
7101959748cSgd78059 	pa0 = (afep->afe_curraddr[3] << 24) | (afep->afe_curraddr[2] << 16) |
7111959748cSgd78059 	    (afep->afe_curraddr[1] << 8) | afep->afe_curraddr[0];
7121959748cSgd78059 	pa1 = (afep->afe_curraddr[5] << 8) | afep->afe_curraddr[4];
7131959748cSgd78059 
7141959748cSgd78059 	PUTCSR(afep, CSR_PAR0, pa0);
7151959748cSgd78059 	PUTCSR(afep, CSR_PAR1, pa1);
7161959748cSgd78059 	if (rxen) {
7171959748cSgd78059 		SETBIT(afep, CSR_NAR, rxen);
7181959748cSgd78059 	}
7191959748cSgd78059 
7201959748cSgd78059 	/* program multicast filter */
7211959748cSgd78059 	if (AFE_MODEL(afep) == MODEL_COMET) {
7221959748cSgd78059 		if (afep->afe_mctab[0] || afep->afe_mctab[1]) {
7231959748cSgd78059 			SETBIT(afep, CSR_NAR, NAR_RX_MULTI);
7241959748cSgd78059 		} else {
7251959748cSgd78059 			CLRBIT(afep, CSR_NAR, NAR_RX_MULTI);
7261959748cSgd78059 		}
7271959748cSgd78059 	} else {
7281959748cSgd78059 		CLRBIT(afep, CSR_NAR, NAR_RX_MULTI);
7291959748cSgd78059 		PUTCSR(afep, CSR_MAR0, afep->afe_mctab[0]);
7301959748cSgd78059 		PUTCSR(afep, CSR_MAR1, afep->afe_mctab[1]);
7311959748cSgd78059 	}
7321959748cSgd78059 
7331959748cSgd78059 	/* restart receiver */
7341959748cSgd78059 	if (rxen) {
7351959748cSgd78059 		afe_startmac(afep);
7361959748cSgd78059 	}
7371959748cSgd78059 }
7381959748cSgd78059 
7391959748cSgd78059 int
740bdb9230aSGarrett D'Amore afe_watchdog(afe_t *afep)
741bdb9230aSGarrett D'Amore {
742bdb9230aSGarrett D'Amore 	if ((afep->afe_txstall_time != 0) &&
743bdb9230aSGarrett D'Amore 	    (gethrtime() > afep->afe_txstall_time) &&
744bdb9230aSGarrett D'Amore 	    (afep->afe_txavail != AFE_TXRING)) {
745bdb9230aSGarrett D'Amore 		afep->afe_txstall_time = 0;
746bdb9230aSGarrett D'Amore 		afe_error(afep->afe_dip, "TX stall detected!");
747bdb9230aSGarrett D'Amore 		return (DDI_FAILURE);
748bdb9230aSGarrett D'Amore 	} else {
749bdb9230aSGarrett D'Amore 		return (DDI_SUCCESS);
750bdb9230aSGarrett D'Amore 	}
751bdb9230aSGarrett D'Amore }
752bdb9230aSGarrett D'Amore 
753bdb9230aSGarrett D'Amore int
7541959748cSgd78059 afe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
7551959748cSgd78059 {
7561959748cSgd78059 	afe_t		*afep = arg;
7571959748cSgd78059 	int		index;
7581959748cSgd78059 	uint32_t	crc;
7591959748cSgd78059 	uint32_t	bit;
7601959748cSgd78059 	uint32_t	newval, oldval;
7611959748cSgd78059 
7621959748cSgd78059 	CRC32(crc, macaddr, ETHERADDRL, -1U, crc32_table);
7631959748cSgd78059 	crc %= AFE_MCHASH;
7641959748cSgd78059 
7651959748cSgd78059 	/* bit within a 32-bit word */
7661959748cSgd78059 	index = crc / 32;
7671959748cSgd78059 	bit = (1 << (crc % 32));
7681959748cSgd78059 
7691959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
7701959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
7711959748cSgd78059 	newval = oldval = afep->afe_mctab[index];
7721959748cSgd78059 
7731959748cSgd78059 	if (add) {
7741959748cSgd78059 		afep->afe_mccount[crc]++;
7751959748cSgd78059 		if (afep->afe_mccount[crc] == 1)
7761959748cSgd78059 			newval |= bit;
7771959748cSgd78059 	} else {
7781959748cSgd78059 		afep->afe_mccount[crc]--;
7791959748cSgd78059 		if (afep->afe_mccount[crc] == 0)
7801959748cSgd78059 			newval &= ~bit;
7811959748cSgd78059 	}
7821959748cSgd78059 	if (newval != oldval) {
7831959748cSgd78059 		afep->afe_mctab[index] = newval;
7841959748cSgd78059 		afe_setrxfilt(afep);
7851959748cSgd78059 	}
7861959748cSgd78059 
7871959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
7881959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
7891959748cSgd78059 
7901959748cSgd78059 	return (0);
7911959748cSgd78059 }
7921959748cSgd78059 
7931959748cSgd78059 int
7941959748cSgd78059 afe_m_promisc(void *arg, boolean_t on)
7951959748cSgd78059 {
7961959748cSgd78059 	afe_t		*afep = arg;
7971959748cSgd78059 
7981959748cSgd78059 	/* exclusive access to the card while we reprogram it */
7991959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
8001959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
8011959748cSgd78059 	/* save current promiscuous mode state for replay in resume */
8021959748cSgd78059 	afep->afe_promisc = on;
8031959748cSgd78059 
8041959748cSgd78059 	afe_setrxfilt(afep);
8051959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
8061959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
8071959748cSgd78059 
8081959748cSgd78059 	return (0);
8091959748cSgd78059 }
8101959748cSgd78059 
8111959748cSgd78059 int
8121959748cSgd78059 afe_m_unicst(void *arg, const uint8_t *macaddr)
8131959748cSgd78059 {
8141959748cSgd78059 	afe_t		*afep = arg;
8151959748cSgd78059 
8161959748cSgd78059 	/* exclusive access to the card while we reprogram it */
8171959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
8181959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
8191959748cSgd78059 
8201959748cSgd78059 	bcopy(macaddr, afep->afe_curraddr, ETHERADDRL);
8211959748cSgd78059 	afe_setrxfilt(afep);
8221959748cSgd78059 
8231959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
8241959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
8251959748cSgd78059 
8261959748cSgd78059 	return (0);
8271959748cSgd78059 }
8281959748cSgd78059 
8291959748cSgd78059 mblk_t *
8301959748cSgd78059 afe_m_tx(void *arg, mblk_t *mp)
8311959748cSgd78059 {
8321959748cSgd78059 	afe_t	*afep = arg;
8331959748cSgd78059 	mblk_t	*nmp;
8341959748cSgd78059 
8351959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
8361959748cSgd78059 
8371959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
8381959748cSgd78059 		while ((nmp = mp) != NULL) {
8391959748cSgd78059 			afep->afe_carrier_errors++;
8401959748cSgd78059 			mp = mp->b_next;
8411959748cSgd78059 			freemsg(nmp);
8421959748cSgd78059 		}
8431959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
8441959748cSgd78059 		return (NULL);
8451959748cSgd78059 	}
8461959748cSgd78059 
8471959748cSgd78059 	while (mp != NULL) {
8481959748cSgd78059 		nmp = mp->b_next;
8491959748cSgd78059 		mp->b_next = NULL;
8501959748cSgd78059 
8511959748cSgd78059 		if (!afe_send(afep, mp)) {
8521959748cSgd78059 			mp->b_next = nmp;
8531959748cSgd78059 			break;
8541959748cSgd78059 		}
8551959748cSgd78059 		mp = nmp;
8561959748cSgd78059 	}
8571959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
8581959748cSgd78059 
8591959748cSgd78059 	return (mp);
8601959748cSgd78059 }
8611959748cSgd78059 
862bdb9230aSGarrett D'Amore void
863bdb9230aSGarrett D'Amore afe_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
864bdb9230aSGarrett D'Amore {
865bdb9230aSGarrett D'Amore 	afe_t	*afep = arg;
866bdb9230aSGarrett D'Amore 
867bdb9230aSGarrett D'Amore 	if (mii_m_loop_ioctl(afep->afe_mii, wq, mp))
868bdb9230aSGarrett D'Amore 		return;
869bdb9230aSGarrett D'Amore 
870bdb9230aSGarrett D'Amore 	miocnak(wq, mp, 0, EINVAL);
871bdb9230aSGarrett D'Amore }
872bdb9230aSGarrett D'Amore 
8731959748cSgd78059 /*
8741959748cSgd78059  * Hardware management.
8751959748cSgd78059  */
8761959748cSgd78059 static boolean_t
8771959748cSgd78059 afe_initialize(afe_t *afep)
8781959748cSgd78059 {
8791959748cSgd78059 	int		i;
8801959748cSgd78059 	unsigned	val;
8811959748cSgd78059 	uint32_t	par, nar;
8821959748cSgd78059 
8831959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
8841959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
8851959748cSgd78059 
8861959748cSgd78059 	SETBIT(afep, CSR_PAR, PAR_RESET);
8871959748cSgd78059 	for (i = 1; i < 10; i++) {
8881959748cSgd78059 		drv_usecwait(5);
8891959748cSgd78059 		val = GETCSR(afep, CSR_PAR);
8901959748cSgd78059 		if (!(val & PAR_RESET)) {
8911959748cSgd78059 			break;
8921959748cSgd78059 		}
8931959748cSgd78059 	}
8941959748cSgd78059 	if (i == 10) {
8951959748cSgd78059 		afe_error(afep->afe_dip, "timed out waiting for reset!");
8961959748cSgd78059 		return (B_FALSE);
8971959748cSgd78059 	}
8981959748cSgd78059 
8991959748cSgd78059 	/*
9001959748cSgd78059 	 * Updated Centaur data sheets show that the Comet and Centaur are
9011959748cSgd78059 	 * alike here (contrary to earlier versions of the data sheet).
9021959748cSgd78059 	 */
9031959748cSgd78059 	/* XXX:? chip problems */
9041959748cSgd78059 	/* par = PAR_MRLE | PAR_MRME | PAR_MWIE; */
9051959748cSgd78059 	par = 0;
9061959748cSgd78059 	switch (afep->afe_cachesize) {
9071959748cSgd78059 	case 8:
9081959748cSgd78059 		par |= PAR_CALIGN_8 | PAR_BURST_8;
9091959748cSgd78059 		break;
9101959748cSgd78059 	case 16:
9111959748cSgd78059 		par |= PAR_CALIGN_16 | PAR_BURST_16;
9121959748cSgd78059 		break;
9131959748cSgd78059 	case 32:
9141959748cSgd78059 		par |= PAR_CALIGN_32 | PAR_BURST_32;
9151959748cSgd78059 		break;
9161959748cSgd78059 	default:
9171959748cSgd78059 		par |= PAR_BURST_32;
9181959748cSgd78059 		par &= ~(PAR_MWIE | PAR_MRLE | PAR_MRME);
9191959748cSgd78059 		break;
9201959748cSgd78059 
9211959748cSgd78059 	}
9221959748cSgd78059 
9231959748cSgd78059 	PUTCSR(afep, CSR_PAR, par);
9241959748cSgd78059 
9251959748cSgd78059 	/* enable transmit underrun auto-recovery */
9261959748cSgd78059 	SETBIT(afep, CSR_CR, CR_TXURAUTOR);
9271959748cSgd78059 
9281959748cSgd78059 	afe_resetrings(afep);
9291959748cSgd78059 
9301959748cSgd78059 	/* clear the lost packet counter (cleared on read) */
9311959748cSgd78059 	(void) GETCSR(afep, CSR_LPC);
9321959748cSgd78059 
9331959748cSgd78059 	nar = GETCSR(afep, CSR_NAR);
9341959748cSgd78059 	nar &= ~NAR_TR;		/* clear tx threshold */
9351959748cSgd78059 	nar |= NAR_SF;		/* store-and-forward */
9361959748cSgd78059 	nar |= NAR_HBD;		/* disable SQE test */
9371959748cSgd78059 	PUTCSR(afep, CSR_NAR, nar);
9381959748cSgd78059 
9391959748cSgd78059 	afe_setrxfilt(afep);
9401959748cSgd78059 
9411959748cSgd78059 	return (B_TRUE);
9421959748cSgd78059 }
9431959748cSgd78059 
9441959748cSgd78059 /*
9451959748cSgd78059  * Serial EEPROM access - inspired by the FreeBSD implementation.
9461959748cSgd78059  */
9471959748cSgd78059 
9481959748cSgd78059 uint8_t
9491959748cSgd78059 afe_sromwidth(afe_t *afep)
9501959748cSgd78059 {
9511959748cSgd78059 	int		i;
9521959748cSgd78059 	uint32_t	eeread;
9531959748cSgd78059 	uint8_t		addrlen = 8;
9541959748cSgd78059 
9551959748cSgd78059 	eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
9561959748cSgd78059 
9571959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
9581959748cSgd78059 	drv_usecwait(1);
9591959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
9601959748cSgd78059 
9611959748cSgd78059 	/* command bits first */
9621959748cSgd78059 	for (i = 4; i != 0; i >>= 1) {
9631959748cSgd78059 		unsigned val = (SROM_READCMD & i) ? SPR_SROM_DIN : 0;
9641959748cSgd78059 
9651959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val);
9661959748cSgd78059 		drv_usecwait(1);
9671959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
9681959748cSgd78059 		drv_usecwait(1);
9691959748cSgd78059 	}
9701959748cSgd78059 
9711959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
9721959748cSgd78059 
9731959748cSgd78059 	for (addrlen = 1; addrlen <= 12; addrlen++) {
9741959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK);
9751959748cSgd78059 		drv_usecwait(1);
9761959748cSgd78059 		if (!(GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT)) {
9771959748cSgd78059 			PUTCSR(afep, CSR_SPR, eeread);
9781959748cSgd78059 			drv_usecwait(1);
9791959748cSgd78059 			break;
9801959748cSgd78059 		}
9811959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread);
9821959748cSgd78059 		drv_usecwait(1);
9831959748cSgd78059 	}
9841959748cSgd78059 
9851959748cSgd78059 	/* turn off accesses to the EEPROM */
9861959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
9871959748cSgd78059 
9881959748cSgd78059 	return ((addrlen < 4 || addrlen > 12) ? 6 : addrlen);
9891959748cSgd78059 }
9901959748cSgd78059 
9911959748cSgd78059 /*
9921959748cSgd78059  * The words in EEPROM are stored in little endian order.  We
9931959748cSgd78059  * shift bits out in big endian order, though.  This requires
9941959748cSgd78059  * a byte swap on some platforms.
9951959748cSgd78059  */
9961959748cSgd78059 uint16_t
9971959748cSgd78059 afe_readsromword(afe_t *afep, unsigned romaddr)
9981959748cSgd78059 {
9991959748cSgd78059 	int		i;
10001959748cSgd78059 	uint16_t	word = 0;
10011959748cSgd78059 	uint16_t	retval;
10021959748cSgd78059 	int		eeread;
10031959748cSgd78059 	uint8_t		addrlen;
10041959748cSgd78059 	int		readcmd;
10051959748cSgd78059 	uchar_t		*ptr;
10061959748cSgd78059 
10071959748cSgd78059 	eeread = SPR_SROM_READ | SPR_SROM_SEL | SPR_SROM_CHIP;
10081959748cSgd78059 	addrlen = afep->afe_sromwidth;
10091959748cSgd78059 	readcmd = (SROM_READCMD << addrlen) | romaddr;
10101959748cSgd78059 
10111959748cSgd78059 	if (romaddr >= (1 << addrlen)) {
10121959748cSgd78059 		/* too big to fit! */
10131959748cSgd78059 		return (0);
10141959748cSgd78059 	}
10151959748cSgd78059 
10161959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread & ~SPR_SROM_CHIP);
10171959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
10181959748cSgd78059 
10191959748cSgd78059 	/* command and address bits */
10201959748cSgd78059 	for (i = 4 + addrlen; i >= 0; i--) {
10211959748cSgd78059 		short val = (readcmd & (1 << i)) ? SPR_SROM_DIN : 0;
10221959748cSgd78059 
10231959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val);
10241959748cSgd78059 		drv_usecwait(1);
10251959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | val | SPR_SROM_CLOCK);
10261959748cSgd78059 		drv_usecwait(1);
10271959748cSgd78059 	}
10281959748cSgd78059 
10291959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread);
10301959748cSgd78059 
10311959748cSgd78059 	for (i = 0; i < 16; i++) {
10321959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread | SPR_SROM_CLOCK);
10331959748cSgd78059 		drv_usecwait(1);
10341959748cSgd78059 		word <<= 1;
10351959748cSgd78059 		if (GETCSR(afep, CSR_SPR) & SPR_SROM_DOUT) {
10361959748cSgd78059 			word |= 1;
10371959748cSgd78059 		}
10381959748cSgd78059 		PUTCSR(afep, CSR_SPR, eeread);
10391959748cSgd78059 		drv_usecwait(1);
10401959748cSgd78059 	}
10411959748cSgd78059 
10421959748cSgd78059 	/* turn off accesses to the EEPROM */
10431959748cSgd78059 	PUTCSR(afep, CSR_SPR, eeread &~ SPR_SROM_CHIP);
10441959748cSgd78059 
10451959748cSgd78059 	/*
10461959748cSgd78059 	 * Fix up the endianness thing.  Note that the values
10471959748cSgd78059 	 * are stored in little endian format on the SROM.
10481959748cSgd78059 	 */
10491959748cSgd78059 	ptr = (uchar_t *)&word;
10501959748cSgd78059 	retval = (ptr[1] << 8) | ptr[0];
10511959748cSgd78059 	return (retval);
10521959748cSgd78059 }
10531959748cSgd78059 
10541959748cSgd78059 void
10551959748cSgd78059 afe_readsrom(afe_t *afep, unsigned romaddr, unsigned len, char *dest)
10561959748cSgd78059 {
10571959748cSgd78059 	int	i;
10581959748cSgd78059 	uint16_t	word;
10591959748cSgd78059 	uint16_t	*ptr = (uint16_t *)((void *)dest);
10601959748cSgd78059 	for (i = 0; i < len; i++) {
10611959748cSgd78059 		word = afe_readsromword(afep, romaddr + i);
10621959748cSgd78059 		*ptr = word;
10631959748cSgd78059 		ptr++;
10641959748cSgd78059 	}
10651959748cSgd78059 }
10661959748cSgd78059 
10671959748cSgd78059 void
10681959748cSgd78059 afe_getfactaddr(afe_t *afep, uchar_t *eaddr)
10691959748cSgd78059 {
10701959748cSgd78059 	afe_readsrom(afep, SROM_ENADDR, ETHERADDRL / 2, (char *)eaddr);
10711959748cSgd78059 }
10721959748cSgd78059 
1073bdb9230aSGarrett D'Amore 
1074bdb9230aSGarrett D'Amore 
10751959748cSgd78059 /*
10761959748cSgd78059  * MII management.
10771959748cSgd78059  */
10781959748cSgd78059 void
1079bdb9230aSGarrett D'Amore afe_mii_reset(void *arg)
10801959748cSgd78059 {
1081bdb9230aSGarrett D'Amore 	afe_t		*afep = arg;
10821959748cSgd78059 	int		fiber;
1083bdb9230aSGarrett D'Amore 	uint16_t	mcr;
1084bdb9230aSGarrett D'Amore 	uint16_t	pilr;
1085bdb9230aSGarrett D'Amore 	uint8_t		phyaddr;
10861959748cSgd78059 
10871959748cSgd78059 	/*
1088bdb9230aSGarrett D'Amore 	 * Its entirely possible that this belongs as a PHY specific
1089bdb9230aSGarrett D'Amore 	 * override.
10901959748cSgd78059 	 */
1091bdb9230aSGarrett D'Amore 	if ((mii_get_id(afep->afe_mii) & 0xfffffff0) != 0x225410) {
1092bdb9230aSGarrett D'Amore 		/* if its not an AN983B, we don't care */
10931959748cSgd78059 		return;
10941959748cSgd78059 	}
10951959748cSgd78059 
1096bdb9230aSGarrett D'Amore 	phyaddr = mii_get_addr(afep->afe_mii);
10971959748cSgd78059 
10981959748cSgd78059 	fiber = 0;
10991959748cSgd78059 
11001959748cSgd78059 	switch (afep->afe_forcefiber) {
11011959748cSgd78059 	case 0:
11021959748cSgd78059 		/* UTP Port */
11031959748cSgd78059 		fiber = 0;
11041959748cSgd78059 		break;
11051959748cSgd78059 	case 1:
11061959748cSgd78059 		/* Fiber Port */
11071959748cSgd78059 		fiber = 1;
11081959748cSgd78059 		break;
1109bdb9230aSGarrett D'Amore 	}
11101959748cSgd78059 
1111bdb9230aSGarrett D'Amore 	mcr = afe_mii_read(afep, phyaddr, PHY_MCR);
1112bdb9230aSGarrett D'Amore 	switch (fiber) {
1113bdb9230aSGarrett D'Amore 	case 0:
11141959748cSgd78059 		mcr &= ~MCR_FIBER;
1115bdb9230aSGarrett D'Amore 		break;
1116bdb9230aSGarrett D'Amore 
1117bdb9230aSGarrett D'Amore 	case 1:
1118bdb9230aSGarrett D'Amore 		mcr |= MCR_FIBER;
11191959748cSgd78059 		break;
11201959748cSgd78059 	}
1121bdb9230aSGarrett D'Amore 	afe_mii_write(afep, phyaddr, PHY_MCR, mcr);
11221959748cSgd78059 	drv_usecwait(500);
11231959748cSgd78059 
11241959748cSgd78059 	/*
11251959748cSgd78059 	 * work around for errata 983B_0416 -- duplex light flashes
11261959748cSgd78059 	 * in 10 HDX.  we just disable SQE testing on the device.
11271959748cSgd78059 	 */
1128bdb9230aSGarrett D'Amore 	pilr = afe_mii_read(afep, phyaddr, PHY_PILR);
11291959748cSgd78059 	pilr |= PILR_NOSQE;
1130bdb9230aSGarrett D'Amore 	afe_mii_write(afep, phyaddr, PHY_PILR, pilr);
11311959748cSgd78059 }
11321959748cSgd78059 
11331959748cSgd78059 void
1134bdb9230aSGarrett D'Amore afe_mii_notify(void *arg, link_state_t link)
11351959748cSgd78059 {
1136bdb9230aSGarrett D'Amore 	afe_t	*afep = arg;
11371959748cSgd78059 
1138bdb9230aSGarrett D'Amore 	if (AFE_MODEL(afep) == MODEL_CENTAUR) {
1139bdb9230aSGarrett D'Amore 		if (mii_get_flowctrl(afep->afe_mii) == LINK_FLOWCTRL_BI) {
1140bdb9230aSGarrett D'Amore 			SETBIT(afep, CSR_CR, CR_PAUSE);
11411959748cSgd78059 		} else {
1142bdb9230aSGarrett D'Amore 			CLRBIT(afep, CSR_CR, CR_PAUSE);
11431959748cSgd78059 		}
11441959748cSgd78059 	}
1145bdb9230aSGarrett D'Amore 	mac_link_update(afep->afe_mh, link);
11461959748cSgd78059 }
11471959748cSgd78059 
11481959748cSgd78059 void
11491959748cSgd78059 afe_miitristate(afe_t *afep)
11501959748cSgd78059 {
115196fb08b9Sgd78059 	uint32_t val = SPR_SROM_WRITE | SPR_MII_CTRL;
115296fb08b9Sgd78059 
11531959748cSgd78059 	PUTCSR(afep, CSR_SPR, val);
11541959748cSgd78059 	drv_usecwait(1);
11551959748cSgd78059 	PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK);
11561959748cSgd78059 	drv_usecwait(1);
11571959748cSgd78059 }
11581959748cSgd78059 
11591959748cSgd78059 void
116096fb08b9Sgd78059 afe_miiwritebit(afe_t *afep, uint8_t bit)
11611959748cSgd78059 {
116296fb08b9Sgd78059 	uint32_t val = bit ? SPR_MII_DOUT : 0;
116396fb08b9Sgd78059 
11641959748cSgd78059 	PUTCSR(afep, CSR_SPR, val);
11651959748cSgd78059 	drv_usecwait(1);
11661959748cSgd78059 	PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK);
11671959748cSgd78059 	drv_usecwait(1);
11681959748cSgd78059 }
11691959748cSgd78059 
117096fb08b9Sgd78059 uint8_t
11711959748cSgd78059 afe_miireadbit(afe_t *afep)
11721959748cSgd78059 {
117396fb08b9Sgd78059 	uint32_t	val = SPR_MII_CTRL | SPR_SROM_READ;
117496fb08b9Sgd78059 	uint8_t		bit;
117596fb08b9Sgd78059 
11761959748cSgd78059 	PUTCSR(afep, CSR_SPR, val);
11771959748cSgd78059 	drv_usecwait(1);
11781959748cSgd78059 	bit = (GETCSR(afep, CSR_SPR) & SPR_MII_DIN) ? 1 : 0;
11791959748cSgd78059 	PUTCSR(afep, CSR_SPR, val | SPR_MII_CLOCK);
11801959748cSgd78059 	drv_usecwait(1);
11811959748cSgd78059 	return (bit);
11821959748cSgd78059 }
11831959748cSgd78059 
118496fb08b9Sgd78059 uint16_t
1185bdb9230aSGarrett D'Amore afe_mii_read(void *arg, uint8_t phy, uint8_t reg)
11861959748cSgd78059 {
1187bdb9230aSGarrett D'Amore 	afe_t *afep = arg;
11881959748cSgd78059 	/*
11891959748cSgd78059 	 * ADMtek bugs ignore address decode bits -- they only
11901959748cSgd78059 	 * support PHY at 1.
11911959748cSgd78059 	 */
11921959748cSgd78059 	if (phy != 1) {
11931959748cSgd78059 		return (0xffff);
11941959748cSgd78059 	}
11951959748cSgd78059 	switch (AFE_MODEL(afep)) {
11961959748cSgd78059 	case MODEL_COMET:
11971959748cSgd78059 		return (afe_miireadcomet(afep, phy, reg));
11981959748cSgd78059 	case MODEL_CENTAUR:
11991959748cSgd78059 		return (afe_miireadgeneral(afep, phy, reg));
12001959748cSgd78059 	}
12011959748cSgd78059 	return (0xffff);
12021959748cSgd78059 }
12031959748cSgd78059 
120496fb08b9Sgd78059 uint16_t
1205bdb9230aSGarrett D'Amore afe_miireadgeneral(afe_t *afep, uint8_t phy, uint8_t reg)
12061959748cSgd78059 {
120796fb08b9Sgd78059 	uint16_t	value = 0;
12081959748cSgd78059 	int		i;
12091959748cSgd78059 
12101959748cSgd78059 	/* send the 32 bit preamble */
12111959748cSgd78059 	for (i = 0; i < 32; i++) {
12121959748cSgd78059 		afe_miiwritebit(afep, 1);
12131959748cSgd78059 	}
12141959748cSgd78059 
12151959748cSgd78059 	/* send the start code - 01b */
12161959748cSgd78059 	afe_miiwritebit(afep, 0);
12171959748cSgd78059 	afe_miiwritebit(afep, 1);
12181959748cSgd78059 
12191959748cSgd78059 	/* send the opcode for read, - 10b */
12201959748cSgd78059 	afe_miiwritebit(afep, 1);
12211959748cSgd78059 	afe_miiwritebit(afep, 0);
12221959748cSgd78059 
12231959748cSgd78059 	/* next we send the 5 bit phy address */
12241959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
12251959748cSgd78059 		afe_miiwritebit(afep, (phy & i) ? 1 : 0);
12261959748cSgd78059 	}
12271959748cSgd78059 
12281959748cSgd78059 	/* the 5 bit register address goes next */
12291959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
12301959748cSgd78059 		afe_miiwritebit(afep, (reg & i) ? 1 : 0);
12311959748cSgd78059 	}
12321959748cSgd78059 
12331959748cSgd78059 	/* turnaround - tristate followed by logic 0 */
12341959748cSgd78059 	afe_miitristate(afep);
12351959748cSgd78059 	afe_miiwritebit(afep, 0);
12361959748cSgd78059 
12371959748cSgd78059 	/* read the 16 bit register value */
12381959748cSgd78059 	for (i = 0x8000; i > 0; i >>= 1) {
12391959748cSgd78059 		value <<= 1;
12401959748cSgd78059 		value |= afe_miireadbit(afep);
12411959748cSgd78059 	}
12421959748cSgd78059 	afe_miitristate(afep);
12431959748cSgd78059 	return (value);
12441959748cSgd78059 }
12451959748cSgd78059 
124696fb08b9Sgd78059 uint16_t
1247bdb9230aSGarrett D'Amore afe_miireadcomet(afe_t *afep, uint8_t phy, uint8_t reg)
12481959748cSgd78059 {
12491959748cSgd78059 	if (phy != 1) {
12501959748cSgd78059 		return (0xffff);
12511959748cSgd78059 	}
12521959748cSgd78059 	switch (reg) {
12531959748cSgd78059 	case MII_CONTROL:
12541959748cSgd78059 		reg = CSR_BMCR;
12551959748cSgd78059 		break;
12561959748cSgd78059 	case MII_STATUS:
12571959748cSgd78059 		reg = CSR_BMSR;
12581959748cSgd78059 		break;
12591959748cSgd78059 	case MII_PHYIDH:
12601959748cSgd78059 		reg = CSR_PHYIDR1;
12611959748cSgd78059 		break;
12621959748cSgd78059 	case MII_PHYIDL:
12631959748cSgd78059 		reg = CSR_PHYIDR2;
12641959748cSgd78059 		break;
12651959748cSgd78059 	case MII_AN_ADVERT:
12661959748cSgd78059 		reg = CSR_ANAR;
12671959748cSgd78059 		break;
12681959748cSgd78059 	case MII_AN_LPABLE:
12691959748cSgd78059 		reg = CSR_ANLPAR;
12701959748cSgd78059 		break;
12711959748cSgd78059 	case MII_AN_EXPANSION:
12721959748cSgd78059 		reg = CSR_ANER;
12731959748cSgd78059 		break;
12741959748cSgd78059 	default:
12751959748cSgd78059 		return (0);
12761959748cSgd78059 	}
12771959748cSgd78059 	return (GETCSR16(afep, reg) & 0xFFFF);
12781959748cSgd78059 }
12791959748cSgd78059 
12801959748cSgd78059 void
1281bdb9230aSGarrett D'Amore afe_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
12821959748cSgd78059 {
1283bdb9230aSGarrett D'Amore 	afe_t	*afep = arg;
1284bdb9230aSGarrett D'Amore 
12851959748cSgd78059 	/*
12861959748cSgd78059 	 * ADMtek bugs ignore address decode bits -- they only
12871959748cSgd78059 	 * support PHY at 1.
12881959748cSgd78059 	 */
12891959748cSgd78059 	if (phy != 1) {
12901959748cSgd78059 		return;
12911959748cSgd78059 	}
12921959748cSgd78059 	switch (AFE_MODEL(afep)) {
12931959748cSgd78059 	case MODEL_COMET:
12941959748cSgd78059 		afe_miiwritecomet(afep, phy, reg, val);
12951959748cSgd78059 		break;
12961959748cSgd78059 	case MODEL_CENTAUR:
12971959748cSgd78059 		afe_miiwritegeneral(afep, phy, reg, val);
12981959748cSgd78059 		break;
12991959748cSgd78059 	}
13001959748cSgd78059 }
13011959748cSgd78059 
13021959748cSgd78059 void
1303bdb9230aSGarrett D'Amore afe_miiwritegeneral(afe_t *afep, uint8_t phy, uint8_t reg, uint16_t val)
13041959748cSgd78059 {
13051959748cSgd78059 	int i;
13061959748cSgd78059 
13071959748cSgd78059 	/* send the 32 bit preamble */
13081959748cSgd78059 	for (i = 0; i < 32; i++) {
13091959748cSgd78059 		afe_miiwritebit(afep, 1);
13101959748cSgd78059 	}
13111959748cSgd78059 
13121959748cSgd78059 	/* send the start code - 01b */
13131959748cSgd78059 	afe_miiwritebit(afep, 0);
13141959748cSgd78059 	afe_miiwritebit(afep, 1);
13151959748cSgd78059 
13161959748cSgd78059 	/* send the opcode for write, - 01b */
13171959748cSgd78059 	afe_miiwritebit(afep, 0);
13181959748cSgd78059 	afe_miiwritebit(afep, 1);
13191959748cSgd78059 
13201959748cSgd78059 	/* next we send the 5 bit phy address */
13211959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
13221959748cSgd78059 		afe_miiwritebit(afep, (phy & i) ? 1 : 0);
13231959748cSgd78059 	}
13241959748cSgd78059 
13251959748cSgd78059 	/* the 5 bit register address goes next */
13261959748cSgd78059 	for (i = 0x10; i > 0; i >>= 1) {
13271959748cSgd78059 		afe_miiwritebit(afep, (reg & i) ? 1 : 0);
13281959748cSgd78059 	}
13291959748cSgd78059 
1330bdb9230aSGarrett D'Amore 	/* turnaround - 1 bit followed by logic 0 */
1331bdb9230aSGarrett D'Amore 	afe_miiwritebit(afep, 1);
13321959748cSgd78059 	afe_miiwritebit(afep, 0);
13331959748cSgd78059 
13341959748cSgd78059 	/* now write out our data (16 bits) */
13351959748cSgd78059 	for (i = 0x8000; i > 0; i >>= 1) {
13361959748cSgd78059 		afe_miiwritebit(afep, (val & i) ? 1 : 0);
13371959748cSgd78059 	}
13381959748cSgd78059 
13391959748cSgd78059 	/* idle mode */
13401959748cSgd78059 	afe_miitristate(afep);
13411959748cSgd78059 }
13421959748cSgd78059 
13431959748cSgd78059 void
1344bdb9230aSGarrett D'Amore afe_miiwritecomet(afe_t *afep, uint8_t phy, uint8_t reg, uint16_t val)
13451959748cSgd78059 {
13461959748cSgd78059 	if (phy != 1) {
13471959748cSgd78059 		return;
13481959748cSgd78059 	}
13491959748cSgd78059 	switch (reg) {
13501959748cSgd78059 	case MII_CONTROL:
13511959748cSgd78059 		reg = CSR_BMCR;
13521959748cSgd78059 		break;
13531959748cSgd78059 	case MII_STATUS:
13541959748cSgd78059 		reg = CSR_BMSR;
13551959748cSgd78059 		break;
13561959748cSgd78059 	case MII_PHYIDH:
13571959748cSgd78059 		reg = CSR_PHYIDR1;
13581959748cSgd78059 		break;
13591959748cSgd78059 	case MII_PHYIDL:
13601959748cSgd78059 		reg = CSR_PHYIDR2;
13611959748cSgd78059 		break;
13621959748cSgd78059 	case MII_AN_ADVERT:
13631959748cSgd78059 		reg = CSR_ANAR;
13641959748cSgd78059 		break;
13651959748cSgd78059 	case MII_AN_LPABLE:
13661959748cSgd78059 		reg = CSR_ANLPAR;
13671959748cSgd78059 		break;
13681959748cSgd78059 	case MII_AN_EXPANSION:
13691959748cSgd78059 		reg = CSR_ANER;
13701959748cSgd78059 		break;
13711959748cSgd78059 	default:
13721959748cSgd78059 		return;
13731959748cSgd78059 	}
13741959748cSgd78059 	PUTCSR16(afep, reg, val);
13751959748cSgd78059 }
13761959748cSgd78059 
13771959748cSgd78059 int
13781959748cSgd78059 afe_m_start(void *arg)
13791959748cSgd78059 {
13801959748cSgd78059 	afe_t	*afep = arg;
13811959748cSgd78059 
13821959748cSgd78059 	/* grab exclusive access to the card */
13831959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
13841959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
13851959748cSgd78059 
13861959748cSgd78059 	afe_startall(afep);
13871959748cSgd78059 	afep->afe_flags |= AFE_RUNNING;
13881959748cSgd78059 
13891959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
13901959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
1391bdb9230aSGarrett D'Amore 
1392bdb9230aSGarrett D'Amore 	mii_start(afep->afe_mii);
1393bdb9230aSGarrett D'Amore 
13941959748cSgd78059 	return (0);
13951959748cSgd78059 }
13961959748cSgd78059 
13971959748cSgd78059 void
13981959748cSgd78059 afe_m_stop(void *arg)
13991959748cSgd78059 {
14001959748cSgd78059 	afe_t	*afep = arg;
14011959748cSgd78059 
1402bdb9230aSGarrett D'Amore 	mii_stop(afep->afe_mii);
1403bdb9230aSGarrett D'Amore 
14041959748cSgd78059 	/* exclusive access to the hardware! */
14051959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
14061959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
14071959748cSgd78059 
14081959748cSgd78059 	afe_stopall(afep);
14091959748cSgd78059 	afep->afe_flags &= ~AFE_RUNNING;
14101959748cSgd78059 
14111959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
14121959748cSgd78059 	mutex_exit(&afep->afe_intrlock);
14131959748cSgd78059 }
14141959748cSgd78059 
14151959748cSgd78059 void
14161959748cSgd78059 afe_startmac(afe_t *afep)
14171959748cSgd78059 {
14181959748cSgd78059 	/* verify exclusive access to the card */
14191959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
14201959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
14211959748cSgd78059 
14221959748cSgd78059 	/* start the card */
14231959748cSgd78059 	SETBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
14241959748cSgd78059 
14251959748cSgd78059 	if (afep->afe_txavail != AFE_TXRING)
14261959748cSgd78059 		PUTCSR(afep, CSR_TDR, 0);
14271959748cSgd78059 
14281959748cSgd78059 	/* tell the mac that we are ready to go! */
14291959748cSgd78059 	if (afep->afe_flags & AFE_RUNNING)
14301959748cSgd78059 		mac_tx_update(afep->afe_mh);
1431bdb9230aSGarrett D'Amore 
1432bdb9230aSGarrett D'Amore 	/* start watchdog timer */
1433bdb9230aSGarrett D'Amore 	PUTCSR(afep, CSR_TIMER, TIMER_LOOP |
1434bdb9230aSGarrett D'Amore 	    (AFE_WDOGTIMER * 1000 / TIMER_USEC));
14351959748cSgd78059 }
14361959748cSgd78059 
14371959748cSgd78059 void
14381959748cSgd78059 afe_stopmac(afe_t *afep)
14391959748cSgd78059 {
14401959748cSgd78059 	int		i;
14411959748cSgd78059 
14421959748cSgd78059 	/* exclusive access to the hardware! */
14431959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
14441959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
14451959748cSgd78059 
14461959748cSgd78059 	CLRBIT(afep, CSR_NAR, NAR_TX_ENABLE | NAR_RX_ENABLE);
14471959748cSgd78059 
14481959748cSgd78059 	/*
14491959748cSgd78059 	 * A 1518 byte frame at 10Mbps takes about 1.2 msec to drain.
14501959748cSgd78059 	 * We just add up to the nearest msec (2), which should be
14511959748cSgd78059 	 * plenty to complete.
14521959748cSgd78059 	 *
14531959748cSgd78059 	 * Note that some chips never seem to indicate the transition to
14541959748cSgd78059 	 * the stopped state properly.  Experience shows that we can safely
14551959748cSgd78059 	 * proceed anyway, after waiting the requisite timeout.
14561959748cSgd78059 	 */
14571959748cSgd78059 	for (i = 2000; i != 0; i -= 10) {
14581959748cSgd78059 		if ((GETCSR(afep, CSR_SR) & (SR_TX_STATE | SR_RX_STATE)) == 0)
14591959748cSgd78059 			break;
14601959748cSgd78059 		drv_usecwait(10);
14611959748cSgd78059 	}
14621959748cSgd78059 
14631959748cSgd78059 	/* prevent an interrupt */
14641959748cSgd78059 	PUTCSR(afep, CSR_SR2, INT_RXSTOPPED | INT_TXSTOPPED);
1465bdb9230aSGarrett D'Amore 
1466bdb9230aSGarrett D'Amore 	/* stop the watchdog timer */
1467bdb9230aSGarrett D'Amore 	PUTCSR(afep, CSR_TIMER, 0);
14681959748cSgd78059 }
14691959748cSgd78059 
14701959748cSgd78059 void
14711959748cSgd78059 afe_resetrings(afe_t *afep)
14721959748cSgd78059 {
14731959748cSgd78059 	int	i;
14741959748cSgd78059 
14751959748cSgd78059 	/* now we need to reset the pointers... */
14761959748cSgd78059 	PUTCSR(afep, CSR_RDB, 0);
14771959748cSgd78059 	PUTCSR(afep, CSR_TDB, 0);
14781959748cSgd78059 
14791959748cSgd78059 	/* reset the descriptor ring pointers */
14801959748cSgd78059 	afep->afe_rxhead = 0;
14811959748cSgd78059 	afep->afe_txreclaim = 0;
14821959748cSgd78059 	afep->afe_txsend = 0;
14831959748cSgd78059 	afep->afe_txavail = AFE_TXRING;
14841959748cSgd78059 
14851959748cSgd78059 	/* set up transmit descriptor ring */
14861959748cSgd78059 	for (i = 0; i < AFE_TXRING; i++) {
14871959748cSgd78059 		afe_desc_t	*tmdp = &afep->afe_txdescp[i];
14881959748cSgd78059 		unsigned	control = 0;
14891959748cSgd78059 		if (i == (AFE_TXRING - 1)) {
14901959748cSgd78059 			control |= TXCTL_ENDRING;
14911959748cSgd78059 		}
14921959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_status, 0);
14931959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_control, control);
14941959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_buffer1, 0);
14951959748cSgd78059 		PUTTXDESC(afep, tmdp->desc_buffer2, 0);
14961959748cSgd78059 		SYNCTXDESC(afep, i, DDI_DMA_SYNC_FORDEV);
14971959748cSgd78059 	}
14981959748cSgd78059 	PUTCSR(afep, CSR_TDB, afep->afe_txdesc_paddr);
14991959748cSgd78059 
15001959748cSgd78059 	/* make the receive buffers available */
15011959748cSgd78059 	for (i = 0; i < AFE_RXRING; i++) {
15021959748cSgd78059 		afe_rxbuf_t	*rxb = afep->afe_rxbufs[i];
15031959748cSgd78059 		afe_desc_t	*rmdp = &afep->afe_rxdescp[i];
15041959748cSgd78059 		unsigned	control;
15051959748cSgd78059 
15061959748cSgd78059 		control = AFE_BUFSZ & RXCTL_BUFLEN1;
15071959748cSgd78059 		if (i == (AFE_RXRING - 1)) {
15081959748cSgd78059 			control |= RXCTL_ENDRING;
15091959748cSgd78059 		}
15101959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_buffer1, rxb->rxb_paddr);
15111959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_buffer2, 0);
15121959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_control, control);
15131959748cSgd78059 		PUTRXDESC(afep, rmdp->desc_status, RXSTAT_OWN);
15141959748cSgd78059 		SYNCRXDESC(afep, i, DDI_DMA_SYNC_FORDEV);
15151959748cSgd78059 	}
15161959748cSgd78059 	PUTCSR(afep, CSR_RDB, afep->afe_rxdesc_paddr);
15171959748cSgd78059 }
15181959748cSgd78059 
15191959748cSgd78059 void
15201959748cSgd78059 afe_stopall(afe_t *afep)
15211959748cSgd78059 {
15221959748cSgd78059 	afe_disableinterrupts(afep);
15231959748cSgd78059 	afe_stopmac(afep);
15241959748cSgd78059 }
15251959748cSgd78059 
15261959748cSgd78059 void
15271959748cSgd78059 afe_startall(afe_t *afep)
15281959748cSgd78059 {
15291959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_intrlock));
15301959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
15311959748cSgd78059 
15321959748cSgd78059 	/* make sure interrupts are disabled to begin */
15331959748cSgd78059 	afe_disableinterrupts(afep);
15341959748cSgd78059 
15351959748cSgd78059 	/* initialize the chip */
15361959748cSgd78059 	(void) afe_initialize(afep);
15371959748cSgd78059 
15381959748cSgd78059 	/* now we can enable interrupts */
15391959748cSgd78059 	afe_enableinterrupts(afep);
15401959748cSgd78059 
15411959748cSgd78059 	/* start up the mac */
15421959748cSgd78059 	afe_startmac(afep);
15431959748cSgd78059 }
15441959748cSgd78059 
15451959748cSgd78059 void
15461959748cSgd78059 afe_resetall(afe_t *afep)
15471959748cSgd78059 {
15481959748cSgd78059 	afe_stopall(afep);
15491959748cSgd78059 	afe_startall(afep);
15501959748cSgd78059 }
15511959748cSgd78059 
15521959748cSgd78059 afe_txbuf_t *
15531959748cSgd78059 afe_alloctxbuf(afe_t *afep)
15541959748cSgd78059 {
15551959748cSgd78059 	ddi_dma_cookie_t	dmac;
15561959748cSgd78059 	unsigned		ncookies;
15571959748cSgd78059 	afe_txbuf_t		*txb;
15581959748cSgd78059 	size_t			len;
15591959748cSgd78059 
15601959748cSgd78059 	txb = kmem_zalloc(sizeof (*txb), KM_SLEEP);
15611959748cSgd78059 
15621959748cSgd78059 	if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_txattr,
15631959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &txb->txb_dmah) != DDI_SUCCESS) {
15641959748cSgd78059 		return (NULL);
15651959748cSgd78059 	}
15661959748cSgd78059 
15671959748cSgd78059 	if (ddi_dma_mem_alloc(txb->txb_dmah, AFE_BUFSZ, &afe_bufattr,
15681959748cSgd78059 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &txb->txb_buf, &len,
15691959748cSgd78059 	    &txb->txb_acch) != DDI_SUCCESS) {
15701959748cSgd78059 		return (NULL);
15711959748cSgd78059 	}
15721959748cSgd78059 	if (ddi_dma_addr_bind_handle(txb->txb_dmah, NULL, txb->txb_buf,
15731959748cSgd78059 	    len, DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
15741959748cSgd78059 	    &dmac, &ncookies) != DDI_DMA_MAPPED) {
15751959748cSgd78059 		return (NULL);
15761959748cSgd78059 	}
15771959748cSgd78059 	txb->txb_paddr = dmac.dmac_address;
15781959748cSgd78059 
15791959748cSgd78059 	return (txb);
15801959748cSgd78059 }
15811959748cSgd78059 
15821959748cSgd78059 void
15831959748cSgd78059 afe_destroytxbuf(afe_txbuf_t *txb)
15841959748cSgd78059 {
15851959748cSgd78059 	if (txb != NULL) {
15861959748cSgd78059 		if (txb->txb_paddr)
15871959748cSgd78059 			(void) ddi_dma_unbind_handle(txb->txb_dmah);
15881959748cSgd78059 		if (txb->txb_acch)
15891959748cSgd78059 			ddi_dma_mem_free(&txb->txb_acch);
15901959748cSgd78059 		if (txb->txb_dmah)
15911959748cSgd78059 			ddi_dma_free_handle(&txb->txb_dmah);
15921959748cSgd78059 		kmem_free(txb, sizeof (*txb));
15931959748cSgd78059 	}
15941959748cSgd78059 }
15951959748cSgd78059 
15961959748cSgd78059 afe_rxbuf_t *
15971959748cSgd78059 afe_allocrxbuf(afe_t *afep)
15981959748cSgd78059 {
15991959748cSgd78059 	afe_rxbuf_t		*rxb;
16001959748cSgd78059 	size_t			len;
16011959748cSgd78059 	unsigned		ccnt;
16021959748cSgd78059 	ddi_dma_cookie_t	dmac;
16031959748cSgd78059 
16041959748cSgd78059 	rxb = kmem_zalloc(sizeof (*rxb), KM_SLEEP);
16051959748cSgd78059 
16061959748cSgd78059 	if (ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
16071959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &rxb->rxb_dmah) != DDI_SUCCESS) {
16081959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
16091959748cSgd78059 		return (NULL);
16101959748cSgd78059 	}
16111959748cSgd78059 	if (ddi_dma_mem_alloc(rxb->rxb_dmah, AFE_BUFSZ, &afe_bufattr,
16121959748cSgd78059 	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &rxb->rxb_buf, &len,
16131959748cSgd78059 	    &rxb->rxb_acch) != DDI_SUCCESS) {
16141959748cSgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
16151959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
16161959748cSgd78059 		return (NULL);
16171959748cSgd78059 	}
16181959748cSgd78059 	if (ddi_dma_addr_bind_handle(rxb->rxb_dmah, NULL, rxb->rxb_buf, len,
16191959748cSgd78059 	    DDI_DMA_READ | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dmac,
16201959748cSgd78059 	    &ccnt) != DDI_DMA_MAPPED) {
16211959748cSgd78059 		ddi_dma_mem_free(&rxb->rxb_acch);
16221959748cSgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
16231959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
16241959748cSgd78059 		return (NULL);
16251959748cSgd78059 	}
16261959748cSgd78059 	rxb->rxb_paddr = dmac.dmac_address;
16271959748cSgd78059 
16281959748cSgd78059 	return (rxb);
16291959748cSgd78059 }
16301959748cSgd78059 
16311959748cSgd78059 void
16321959748cSgd78059 afe_destroyrxbuf(afe_rxbuf_t *rxb)
16331959748cSgd78059 {
16341959748cSgd78059 	if (rxb) {
16351959748cSgd78059 		(void) ddi_dma_unbind_handle(rxb->rxb_dmah);
16361959748cSgd78059 		ddi_dma_mem_free(&rxb->rxb_acch);
16371959748cSgd78059 		ddi_dma_free_handle(&rxb->rxb_dmah);
16381959748cSgd78059 		kmem_free(rxb, sizeof (*rxb));
16391959748cSgd78059 	}
16401959748cSgd78059 }
16411959748cSgd78059 
16421959748cSgd78059 /*
16431959748cSgd78059  * Allocate receive resources.
16441959748cSgd78059  */
16451959748cSgd78059 int
16461959748cSgd78059 afe_allocrxring(afe_t *afep)
16471959748cSgd78059 {
16481959748cSgd78059 	int			rval;
16491959748cSgd78059 	int			i;
16501959748cSgd78059 	size_t			size;
16511959748cSgd78059 	size_t			len;
16521959748cSgd78059 	ddi_dma_cookie_t	dmac;
16531959748cSgd78059 	unsigned		ncookies;
16541959748cSgd78059 	caddr_t			kaddr;
16551959748cSgd78059 
16561959748cSgd78059 	size = AFE_RXRING * sizeof (afe_desc_t);
16571959748cSgd78059 
16581959748cSgd78059 	rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
16591959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &afep->afe_rxdesc_dmah);
16601959748cSgd78059 	if (rval != DDI_SUCCESS) {
16611959748cSgd78059 		afe_error(afep->afe_dip,
16621959748cSgd78059 		    "unable to allocate DMA handle for rx descriptors");
16631959748cSgd78059 		return (DDI_FAILURE);
16641959748cSgd78059 	}
16651959748cSgd78059 
16661959748cSgd78059 	rval = ddi_dma_mem_alloc(afep->afe_rxdesc_dmah, size, &afe_devattr,
16671959748cSgd78059 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
16681959748cSgd78059 	    &afep->afe_rxdesc_acch);
16691959748cSgd78059 	if (rval != DDI_SUCCESS) {
16701959748cSgd78059 		afe_error(afep->afe_dip,
16711959748cSgd78059 		    "unable to allocate DMA memory for rx descriptors");
16721959748cSgd78059 		return (DDI_FAILURE);
16731959748cSgd78059 	}
16741959748cSgd78059 
16751959748cSgd78059 	rval = ddi_dma_addr_bind_handle(afep->afe_rxdesc_dmah, NULL, kaddr,
16761959748cSgd78059 	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
16771959748cSgd78059 	    &dmac, &ncookies);
16781959748cSgd78059 	if (rval != DDI_DMA_MAPPED) {
16791959748cSgd78059 		afe_error(afep->afe_dip,
16801959748cSgd78059 		    "unable to bind DMA for rx descriptors");
16811959748cSgd78059 		return (DDI_FAILURE);
16821959748cSgd78059 	}
16831959748cSgd78059 
16841959748cSgd78059 	/* because of afe_dma_attr */
16851959748cSgd78059 	ASSERT(ncookies == 1);
16861959748cSgd78059 
16871959748cSgd78059 	/* we take the 32-bit physical address out of the cookie */
16881959748cSgd78059 	afep->afe_rxdesc_paddr = dmac.dmac_address;
16891959748cSgd78059 	afep->afe_rxdescp = (void *)kaddr;
16901959748cSgd78059 
16911959748cSgd78059 	/* allocate buffer pointers (not the buffers themselves, yet) */
16921959748cSgd78059 	afep->afe_rxbufs = kmem_zalloc(AFE_RXRING * sizeof (afe_rxbuf_t *),
16931959748cSgd78059 	    KM_SLEEP);
16941959748cSgd78059 
16951959748cSgd78059 	/* now allocate rx buffers */
16961959748cSgd78059 	for (i = 0; i < AFE_RXRING; i++) {
16971959748cSgd78059 		afe_rxbuf_t *rxb = afe_allocrxbuf(afep);
16981959748cSgd78059 		if (rxb == NULL)
16991959748cSgd78059 			return (DDI_FAILURE);
17001959748cSgd78059 		afep->afe_rxbufs[i] = rxb;
17011959748cSgd78059 	}
17021959748cSgd78059 
17031959748cSgd78059 	return (DDI_SUCCESS);
17041959748cSgd78059 }
17051959748cSgd78059 
17061959748cSgd78059 /*
17071959748cSgd78059  * Allocate transmit resources.
17081959748cSgd78059  */
17091959748cSgd78059 int
17101959748cSgd78059 afe_alloctxring(afe_t *afep)
17111959748cSgd78059 {
17121959748cSgd78059 	int			rval;
17131959748cSgd78059 	int			i;
17141959748cSgd78059 	size_t			size;
17151959748cSgd78059 	size_t			len;
17161959748cSgd78059 	ddi_dma_cookie_t	dmac;
17171959748cSgd78059 	unsigned		ncookies;
17181959748cSgd78059 	caddr_t			kaddr;
17191959748cSgd78059 
17201959748cSgd78059 	size = AFE_TXRING * sizeof (afe_desc_t);
17211959748cSgd78059 
17221959748cSgd78059 	rval = ddi_dma_alloc_handle(afep->afe_dip, &afe_dma_attr,
17231959748cSgd78059 	    DDI_DMA_SLEEP, NULL, &afep->afe_txdesc_dmah);
17241959748cSgd78059 	if (rval != DDI_SUCCESS) {
17251959748cSgd78059 		afe_error(afep->afe_dip,
17261959748cSgd78059 		    "unable to allocate DMA handle for tx descriptors");
17271959748cSgd78059 		return (DDI_FAILURE);
17281959748cSgd78059 	}
17291959748cSgd78059 
17301959748cSgd78059 	rval = ddi_dma_mem_alloc(afep->afe_txdesc_dmah, size, &afe_devattr,
17311959748cSgd78059 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &kaddr, &len,
17321959748cSgd78059 	    &afep->afe_txdesc_acch);
17331959748cSgd78059 	if (rval != DDI_SUCCESS) {
17341959748cSgd78059 		afe_error(afep->afe_dip,
17351959748cSgd78059 		    "unable to allocate DMA memory for tx descriptors");
17361959748cSgd78059 		return (DDI_FAILURE);
17371959748cSgd78059 	}
17381959748cSgd78059 
17391959748cSgd78059 	rval = ddi_dma_addr_bind_handle(afep->afe_txdesc_dmah, NULL, kaddr,
17401959748cSgd78059 	    size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
17411959748cSgd78059 	    &dmac, &ncookies);
17421959748cSgd78059 	if (rval != DDI_DMA_MAPPED) {
17431959748cSgd78059 		afe_error(afep->afe_dip,
17441959748cSgd78059 		    "unable to bind DMA for tx descriptors");
17451959748cSgd78059 		return (DDI_FAILURE);
17461959748cSgd78059 	}
17471959748cSgd78059 
17481959748cSgd78059 	/* because of afe_dma_attr */
17491959748cSgd78059 	ASSERT(ncookies == 1);
17501959748cSgd78059 
17511959748cSgd78059 	/* we take the 32-bit physical address out of the cookie */
17521959748cSgd78059 	afep->afe_txdesc_paddr = dmac.dmac_address;
17531959748cSgd78059 	afep->afe_txdescp = (void *)kaddr;
17541959748cSgd78059 
17551959748cSgd78059 	/* allocate buffer pointers (not the buffers themselves, yet) */
17561959748cSgd78059 	afep->afe_txbufs = kmem_zalloc(AFE_TXRING * sizeof (afe_txbuf_t *),
17571959748cSgd78059 	    KM_SLEEP);
17581959748cSgd78059 
17591959748cSgd78059 	/* now allocate tx buffers */
17601959748cSgd78059 	for (i = 0; i < AFE_TXRING; i++) {
17611959748cSgd78059 		afe_txbuf_t *txb = afe_alloctxbuf(afep);
17621959748cSgd78059 		if (txb == NULL)
17631959748cSgd78059 			return (DDI_FAILURE);
17641959748cSgd78059 		afep->afe_txbufs[i] = txb;
17651959748cSgd78059 	}
17661959748cSgd78059 
17671959748cSgd78059 	return (DDI_SUCCESS);
17681959748cSgd78059 }
17691959748cSgd78059 
17701959748cSgd78059 void
17711959748cSgd78059 afe_freerxring(afe_t *afep)
17721959748cSgd78059 {
17731959748cSgd78059 	int		i;
17741959748cSgd78059 
17751959748cSgd78059 	for (i = 0; i < AFE_RXRING; i++) {
17761959748cSgd78059 		afe_destroyrxbuf(afep->afe_rxbufs[i]);
17771959748cSgd78059 	}
17781959748cSgd78059 
17791959748cSgd78059 	if (afep->afe_rxbufs) {
17801959748cSgd78059 		kmem_free(afep->afe_rxbufs,
17811959748cSgd78059 		    AFE_RXRING * sizeof (afe_rxbuf_t *));
17821959748cSgd78059 	}
17831959748cSgd78059 
17841959748cSgd78059 	if (afep->afe_rxdesc_paddr)
17851959748cSgd78059 		(void) ddi_dma_unbind_handle(afep->afe_rxdesc_dmah);
17861959748cSgd78059 	if (afep->afe_rxdesc_acch)
17871959748cSgd78059 		ddi_dma_mem_free(&afep->afe_rxdesc_acch);
17881959748cSgd78059 	if (afep->afe_rxdesc_dmah)
17891959748cSgd78059 		ddi_dma_free_handle(&afep->afe_rxdesc_dmah);
17901959748cSgd78059 }
17911959748cSgd78059 
17921959748cSgd78059 void
17931959748cSgd78059 afe_freetxring(afe_t *afep)
17941959748cSgd78059 {
17951959748cSgd78059 	int			i;
17961959748cSgd78059 
17971959748cSgd78059 	for (i = 0; i < AFE_TXRING; i++) {
17981959748cSgd78059 		afe_destroytxbuf(afep->afe_txbufs[i]);
17991959748cSgd78059 	}
18001959748cSgd78059 
18011959748cSgd78059 	if (afep->afe_txbufs) {
18021959748cSgd78059 		kmem_free(afep->afe_txbufs,
18031959748cSgd78059 		    AFE_TXRING * sizeof (afe_txbuf_t *));
18041959748cSgd78059 	}
18051959748cSgd78059 	if (afep->afe_txdesc_paddr)
18061959748cSgd78059 		(void) ddi_dma_unbind_handle(afep->afe_txdesc_dmah);
18071959748cSgd78059 	if (afep->afe_txdesc_acch)
18081959748cSgd78059 		ddi_dma_mem_free(&afep->afe_txdesc_acch);
18091959748cSgd78059 	if (afep->afe_txdesc_dmah)
18101959748cSgd78059 		ddi_dma_free_handle(&afep->afe_txdesc_dmah);
18111959748cSgd78059 }
18121959748cSgd78059 
18131959748cSgd78059 /*
18141959748cSgd78059  * Interrupt service routine.
18151959748cSgd78059  */
18161959748cSgd78059 unsigned
18171959748cSgd78059 afe_intr(caddr_t arg)
18181959748cSgd78059 {
18191959748cSgd78059 	afe_t		*afep = (void *)arg;
18201959748cSgd78059 	uint32_t	status;
18211959748cSgd78059 	mblk_t		*mp = NULL;
1822bdb9230aSGarrett D'Amore 	boolean_t	doreset = B_FALSE;
18231959748cSgd78059 
18241959748cSgd78059 	mutex_enter(&afep->afe_intrlock);
18251959748cSgd78059 
18261959748cSgd78059 	if (afep->afe_flags & AFE_SUSPENDED) {
18271959748cSgd78059 		/* we cannot receive interrupts! */
18281959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
18291959748cSgd78059 		return (DDI_INTR_UNCLAIMED);
18301959748cSgd78059 	}
18311959748cSgd78059 
18321959748cSgd78059 	/* check interrupt status bits, did we interrupt? */
18331959748cSgd78059 	status = GETCSR(afep, CSR_SR2) & INT_ALL;
18341959748cSgd78059 
18351959748cSgd78059 	if (status == 0) {
18361959748cSgd78059 		KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
18371959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
18381959748cSgd78059 		return (DDI_INTR_UNCLAIMED);
18391959748cSgd78059 	}
18401959748cSgd78059 	/* ack the interrupt */
18411959748cSgd78059 	PUTCSR(afep, CSR_SR2, status);
18421959748cSgd78059 	KIOIP->intrs[KSTAT_INTR_HARD]++;
18431959748cSgd78059 
18441959748cSgd78059 	if (!(afep->afe_flags & AFE_RUNNING)) {
18451959748cSgd78059 		/* not running, don't touch anything */
18461959748cSgd78059 		mutex_exit(&afep->afe_intrlock);
18471959748cSgd78059 		return (DDI_INTR_CLAIMED);
18481959748cSgd78059 	}
18491959748cSgd78059 
18501959748cSgd78059 	if (status & (INT_RXOK|INT_RXNOBUF)) {
18511959748cSgd78059 		/* receive packets */
18521959748cSgd78059 		mp = afe_receive(afep);
18531959748cSgd78059 		if (status & INT_RXNOBUF)
18541959748cSgd78059 			PUTCSR(afep, CSR_RDR, 0);	/* wake up chip */
18551959748cSgd78059 	}
18561959748cSgd78059 
18571959748cSgd78059 	if (status & INT_TXOK) {
18581959748cSgd78059 		/* transmit completed */
18591959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
18601959748cSgd78059 		afe_reclaim(afep);
18611959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
18621959748cSgd78059 	}
18631959748cSgd78059 
1864bdb9230aSGarrett D'Amore 	if ((status & INT_TIMER) && (afe_watchdog(afep) != DDI_SUCCESS)) {
1865bdb9230aSGarrett D'Amore 		doreset = B_TRUE;
18661959748cSgd78059 	}
18671959748cSgd78059 
18681959748cSgd78059 	if (status & (INT_RXSTOPPED|INT_TXSTOPPED|
18691959748cSgd78059 	    INT_RXJABBER|INT_TXJABBER|INT_TXUNDERFLOW)) {
18701959748cSgd78059 
18711959748cSgd78059 		if (status & (INT_RXJABBER | INT_TXJABBER)) {
18721959748cSgd78059 			afep->afe_jabber++;
18731959748cSgd78059 		}
1874bdb9230aSGarrett D'Amore 		doreset = B_TRUE;
18751959748cSgd78059 	}
18761959748cSgd78059 
18771959748cSgd78059 	if (status & INT_BUSERR) {
18781959748cSgd78059 		switch (GETCSR(afep, CSR_SR) & SR_BERR_TYPE) {
18791959748cSgd78059 		case SR_BERR_PARITY:
18801959748cSgd78059 			afe_error(afep->afe_dip, "PCI parity error");
18811959748cSgd78059 			break;
18821959748cSgd78059 		case SR_BERR_TARGET_ABORT:
18831959748cSgd78059 			afe_error(afep->afe_dip, "PCI target abort");
18841959748cSgd78059 			break;
18851959748cSgd78059 		case SR_BERR_MASTER_ABORT:
18861959748cSgd78059 			afe_error(afep->afe_dip, "PCI master abort");
18871959748cSgd78059 			break;
18881959748cSgd78059 		default:
18891959748cSgd78059 			afe_error(afep->afe_dip, "Unknown PCI error");
18901959748cSgd78059 			break;
18911959748cSgd78059 		}
18921959748cSgd78059 
18931959748cSgd78059 		/* reset the chip in an attempt to fix things */
1894bdb9230aSGarrett D'Amore 		doreset = B_TRUE;
1895bdb9230aSGarrett D'Amore 	}
1896bdb9230aSGarrett D'Amore 
1897bdb9230aSGarrett D'Amore 
1898bdb9230aSGarrett D'Amore 	if (doreset) {
18991959748cSgd78059 		mutex_enter(&afep->afe_xmtlock);
19001959748cSgd78059 		afe_resetall(afep);
19011959748cSgd78059 		mutex_exit(&afep->afe_xmtlock);
1902bdb9230aSGarrett D'Amore 		mutex_exit(&afep->afe_intrlock);
1903bdb9230aSGarrett D'Amore 
1904bdb9230aSGarrett D'Amore 		mii_reset(afep->afe_mii);
1905bdb9230aSGarrett D'Amore 	} else {
1906bdb9230aSGarrett D'Amore 		mutex_exit(&afep->afe_intrlock);
19071959748cSgd78059 	}
19081959748cSgd78059 
1909bdb9230aSGarrett D'Amore 	if (status & INT_LINKCHG) {
1910bdb9230aSGarrett D'Amore 		mii_check(afep->afe_mii);
1911bdb9230aSGarrett D'Amore 	}
19121959748cSgd78059 
19131959748cSgd78059 	/*
19141959748cSgd78059 	 * Send up packets.  We do this outside of the intrlock.
19151959748cSgd78059 	 */
19161959748cSgd78059 	if (mp) {
19171959748cSgd78059 		mac_rx(afep->afe_mh, NULL, mp);
19181959748cSgd78059 	}
19191959748cSgd78059 
19201959748cSgd78059 	return (DDI_INTR_CLAIMED);
19211959748cSgd78059 }
19221959748cSgd78059 
19231959748cSgd78059 void
19241959748cSgd78059 afe_enableinterrupts(afe_t *afep)
19251959748cSgd78059 {
19261959748cSgd78059 	unsigned mask = INT_WANTED;
19271959748cSgd78059 
19281959748cSgd78059 	if (afep->afe_wantw)
19291959748cSgd78059 		mask |= INT_TXOK;
19301959748cSgd78059 
19311959748cSgd78059 	PUTCSR(afep, CSR_IER2, mask);
19321959748cSgd78059 
19331959748cSgd78059 	if (AFE_MODEL(afep) == MODEL_COMET) {
19341959748cSgd78059 		/*
19351959748cSgd78059 		 * On the Comet, this is the internal transceiver
19361959748cSgd78059 		 * interrupt.  We program the Comet's built-in PHY to
19371959748cSgd78059 		 * enable certain interrupts.
19381959748cSgd78059 		 */
19391959748cSgd78059 		PUTCSR16(afep, CSR_XIE, XIE_LDE | XIE_ANCE);
19401959748cSgd78059 	}
19411959748cSgd78059 }
19421959748cSgd78059 
19431959748cSgd78059 void
19441959748cSgd78059 afe_disableinterrupts(afe_t *afep)
19451959748cSgd78059 {
19461959748cSgd78059 	/* disable further interrupts */
19471959748cSgd78059 	PUTCSR(afep, CSR_IER2, INT_NONE);
19481959748cSgd78059 
19491959748cSgd78059 	/* clear any pending interrupts */
19501959748cSgd78059 	PUTCSR(afep, CSR_SR2, INT_ALL);
19511959748cSgd78059 }
19521959748cSgd78059 
19531959748cSgd78059 boolean_t
19541959748cSgd78059 afe_send(afe_t *afep, mblk_t *mp)
19551959748cSgd78059 {
19561959748cSgd78059 	size_t			len;
19571959748cSgd78059 	afe_txbuf_t		*txb;
19581959748cSgd78059 	afe_desc_t		*tmd;
19591959748cSgd78059 	uint32_t		control;
19601959748cSgd78059 	int			txsend;
19611959748cSgd78059 
19621959748cSgd78059 	ASSERT(mutex_owned(&afep->afe_xmtlock));
19631959748cSgd78059 	ASSERT(mp != NULL);
19641959748cSgd78059 
19651959748cSgd78059 	len = msgsize(mp);
19661959748cSgd78059 	if (len > ETHERVLANMTU) {
19671959748cSgd78059 		afep->afe_macxmt_errors++;
19681959748cSgd78059 		freemsg(mp);
19691959748cSgd78059 		return (B_TRUE);
19701959748cSgd78059 	}
19711959748cSgd78059 
19721959748cSgd78059 	if (afep->afe_txavail < AFE_TXRECLAIM)
19731959748cSgd78059 		afe_reclaim(afep);
19741959748cSgd78059 
19751959748cSgd78059 	if (afep->afe_txavail == 0) {
19761959748cSgd78059 		/* no more tmds */
19771959748cSgd78059 		afep->afe_wantw = B_TRUE;
19781959748cSgd78059 		/* enable TX interrupt */
19791959748cSgd78059 		afe_enableinterrupts(afep);
19801959748cSgd78059 		return (B_FALSE);
19811959748cSgd78059 	}
19821959748cSgd78059 
19831959748cSgd78059 	txsend = afep->afe_txsend;
19841959748cSgd78059 
19851959748cSgd78059 	/*
19861959748cSgd78059 	 * For simplicity, we just do a copy into a preallocated
19871959748cSgd78059 	 * DMA buffer.
19881959748cSgd78059 	 */
19891959748cSgd78059 
19901959748cSgd78059 	txb = afep->afe_txbufs[txsend];
19911959748cSgd78059 	mcopymsg(mp, txb->txb_buf);	/* frees mp! */
19921959748cSgd78059 
19931959748cSgd78059 	/*
19941959748cSgd78059 	 * Statistics.
19951959748cSgd78059 	 */
19961959748cSgd78059 	afep->afe_opackets++;
19971959748cSgd78059 	afep->afe_obytes += len;
19981959748cSgd78059 	if (txb->txb_buf[0] & 0x1) {
19991959748cSgd78059 		if (bcmp(txb->txb_buf, afe_broadcast, ETHERADDRL) != 0)
20001959748cSgd78059 			afep->afe_multixmt++;
20011959748cSgd78059 		else
20021959748cSgd78059 			afep->afe_brdcstxmt++;
20031959748cSgd78059 	}
20041959748cSgd78059 
20051959748cSgd78059 	/* note len is already known to be a small unsigned */
20061959748cSgd78059 	control = len | TXCTL_FIRST | TXCTL_LAST | TXCTL_INTCMPLTE;
20071959748cSgd78059 
20081959748cSgd78059 	if (txsend == (AFE_TXRING - 1))
20091959748cSgd78059 		control |= TXCTL_ENDRING;
20101959748cSgd78059 
20111959748cSgd78059 	tmd = &afep->afe_txdescp[txsend];
20121959748cSgd78059 
20131959748cSgd78059 	SYNCTXBUF(txb, len, DDI_DMA_SYNC_FORDEV);
20141959748cSgd78059 	PUTTXDESC(afep, tmd->desc_control, control);
20151959748cSgd78059 	PUTTXDESC(afep, tmd->desc_buffer1, txb->txb_paddr);
20161959748cSgd78059 	PUTTXDESC(afep, tmd->desc_buffer2, 0);
20171959748cSgd78059 	PUTTXDESC(afep, tmd->desc_status, TXSTAT_OWN);
20181959748cSgd78059 	/* sync the descriptor out to the device */
20191959748cSgd78059 	SYNCTXDESC(afep, txsend, DDI_DMA_SYNC_FORDEV);
20201959748cSgd78059 
20211959748cSgd78059 	/*
20221959748cSgd78059 	 * Note the new values of txavail and txsend.
20231959748cSgd78059 	 */
20241959748cSgd78059 	afep->afe_txavail--;
20251959748cSgd78059 	afep->afe_txsend = (txsend + 1) % AFE_TXRING;
20261959748cSgd78059 
20271959748cSgd78059 	/*
20281959748cSgd78059 	 * It should never, ever take more than 5 seconds to drain
20291959748cSgd78059 	 * the ring.  If it happens, then we are stuck!
20301959748cSgd78059 	 */
20311959748cSgd78059 	afep->afe_txstall_time = gethrtime() + (5 * 1000000000ULL);
20321959748cSgd78059 
20331959748cSgd78059 	/*
20341959748cSgd78059 	 * wake up the chip ... inside the lock to protect against DR suspend,
20351959748cSgd78059 	 * etc.
20361959748cSgd78059 	 */
20371959748cSgd78059 	PUTCSR(afep, CSR_TDR, 0);
20381959748cSgd78059 
20391959748cSgd78059 	return (B_TRUE);
20401959748cSgd78059 }
20411959748cSgd78059 
20421959748cSgd78059 /*
20431959748cSgd78059  * Reclaim buffers that have completed transmission.
20441959748cSgd78059  */
20451959748cSgd78059 void
20461959748cSgd78059 afe_reclaim(afe_t *afep)
20471959748cSgd78059 {
20481959748cSgd78059 	afe_desc_t	*tmdp;
20491959748cSgd78059 
20501959748cSgd78059 	while (afep->afe_txavail != AFE_TXRING) {
20511959748cSgd78059 		uint32_t	status;
20521959748cSgd78059 		uint32_t	control;
20531959748cSgd78059 		int		index = afep->afe_txreclaim;
20541959748cSgd78059 
20551959748cSgd78059 		tmdp = &afep->afe_txdescp[index];
20561959748cSgd78059 
20571959748cSgd78059 		/* sync it before we read it */
20581959748cSgd78059 		SYNCTXDESC(afep, index, DDI_DMA_SYNC_FORKERNEL);
20591959748cSgd78059 
20601959748cSgd78059 		control = GETTXDESC(afep, tmdp->desc_control);
20611959748cSgd78059 		status = GETTXDESC(afep, tmdp->desc_status);
20621959748cSgd78059 
20631959748cSgd78059 		if (status & TXSTAT_OWN) {
20641959748cSgd78059 			/* chip is still working on it, we're done */
20651959748cSgd78059 			break;
20661959748cSgd78059 		}
20671959748cSgd78059 
20681959748cSgd78059 		afep->afe_txavail++;
20691959748cSgd78059 		afep->afe_txreclaim = (index + 1) % AFE_TXRING;
20701959748cSgd78059 
20711959748cSgd78059 		/* in the most common successful case, all bits are clear */
20721959748cSgd78059 		if (status == 0)
20731959748cSgd78059 			continue;
20741959748cSgd78059 
20751959748cSgd78059 		if ((control & TXCTL_LAST) == 0)
20761959748cSgd78059 			continue;
20771959748cSgd78059 
20781959748cSgd78059 		if (status & TXSTAT_TXERR) {
20791959748cSgd78059 			afep->afe_errxmt++;
20801959748cSgd78059 
20811959748cSgd78059 			if (status & TXSTAT_JABBER) {
20821959748cSgd78059 				/* transmit jabber timeout */
20831959748cSgd78059 				afep->afe_macxmt_errors++;
20841959748cSgd78059 			}
20851959748cSgd78059 			if (status &
20861959748cSgd78059 			    (TXSTAT_CARRLOST | TXSTAT_NOCARR)) {
20871959748cSgd78059 				afep->afe_carrier_errors++;
20881959748cSgd78059 			}
20891959748cSgd78059 			if (status & TXSTAT_UFLOW) {
20901959748cSgd78059 				afep->afe_underflow++;
20911959748cSgd78059 			}
20921959748cSgd78059 			if (status & TXSTAT_LATECOL) {
20931959748cSgd78059 				afep->afe_tx_late_collisions++;
20941959748cSgd78059 			}
20951959748cSgd78059 			if (status & TXSTAT_EXCOLL) {
20961959748cSgd78059 				afep->afe_ex_collisions++;
20971959748cSgd78059 				afep->afe_collisions += 16;
20981959748cSgd78059 			}
20991959748cSgd78059 		}
21001959748cSgd78059 
21011959748cSgd78059 		if (status & TXSTAT_DEFER) {
21021959748cSgd78059 			afep->afe_defer_xmts++;
21031959748cSgd78059 		}
21041959748cSgd78059 
21051959748cSgd78059 		/* collision counting */
21061959748cSgd78059 		if (TXCOLLCNT(status) == 1) {
21071959748cSgd78059 			afep->afe_collisions++;
21081959748cSgd78059 			afep->afe_first_collisions++;
21091959748cSgd78059 		} else if (TXCOLLCNT(status)) {
21101959748cSgd78059 			afep->afe_collisions += TXCOLLCNT(status);
21111959748cSgd78059 			afep->afe_multi_collisions += TXCOLLCNT(status);
21121959748cSgd78059 		}
21131959748cSgd78059 	}
21141959748cSgd78059 
21151959748cSgd78059 	if (afep->afe_txavail >= AFE_TXRESCHED) {
21161959748cSgd78059 		if (afep->afe_wantw) {
21171959748cSgd78059 			/*
21181959748cSgd78059 			 * we were able to reclaim some packets, so
21191959748cSgd78059 			 * disable tx interrupts
21201959748cSgd78059 			 */
21211959748cSgd78059 			afep->afe_wantw = B_FALSE;
21221959748cSgd78059 			afe_enableinterrupts(afep);
21231959748cSgd78059 			mac_tx_update(afep->afe_mh);
21241959748cSgd78059 		}
21251959748cSgd78059 	}
21261959748cSgd78059 }
21271959748cSgd78059 
21281959748cSgd78059 mblk_t *
21291959748cSgd78059 afe_receive(afe_t *afep)
21301959748cSgd78059 {
21311959748cSgd78059 	unsigned		len;
21321959748cSgd78059 	afe_rxbuf_t		*rxb;
21331959748cSgd78059 	afe_desc_t		*rmd;
21341959748cSgd78059 	uint32_t		status;
21351959748cSgd78059 	mblk_t			*mpchain, **mpp, *mp;
21361959748cSgd78059 	int			head, cnt;
21371959748cSgd78059 
21381959748cSgd78059 	mpchain = NULL;
21391959748cSgd78059 	mpp = &mpchain;
21401959748cSgd78059 	head = afep->afe_rxhead;
21411959748cSgd78059 
21421959748cSgd78059 	/* limit the number of packets we process to a half ring size */
21431959748cSgd78059 	for (cnt = 0; cnt < AFE_RXRING / 2; cnt++) {
21441959748cSgd78059 
21451959748cSgd78059 		rmd = &afep->afe_rxdescp[head];
21461959748cSgd78059 		rxb = afep->afe_rxbufs[head];
21471959748cSgd78059 
21481959748cSgd78059 		SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORKERNEL);
21491959748cSgd78059 		status = GETRXDESC(afep, rmd->desc_status);
21501959748cSgd78059 		if (status & RXSTAT_OWN) {
21511959748cSgd78059 			/* chip is still chewing on it */
21521959748cSgd78059 			break;
21531959748cSgd78059 		}
21541959748cSgd78059 
21551959748cSgd78059 		/* discard the ethernet frame checksum */
21561959748cSgd78059 		len = RXLENGTH(status) - ETHERFCSL;
21571959748cSgd78059 
21581959748cSgd78059 		if ((status & (RXSTAT_ERRS | RXSTAT_FIRST | RXSTAT_LAST)) !=
21591959748cSgd78059 		    (RXSTAT_FIRST | RXSTAT_LAST)) {
21601959748cSgd78059 
21611959748cSgd78059 			afep->afe_errrcv++;
21621959748cSgd78059 
21631959748cSgd78059 			/*
21641959748cSgd78059 			 * Abnormal status bits detected, analyze further.
21651959748cSgd78059 			 */
21661959748cSgd78059 			if ((status & (RXSTAT_LAST|RXSTAT_FIRST)) !=
21671959748cSgd78059 			    (RXSTAT_LAST|RXSTAT_FIRST)) {
2168bdb9230aSGarrett D'Amore 
21691959748cSgd78059 				if (status & RXSTAT_FIRST) {
21701959748cSgd78059 					afep->afe_toolong_errors++;
21711959748cSgd78059 				}
21721959748cSgd78059 			} else if (status & RXSTAT_DESCERR) {
21731959748cSgd78059 				afep->afe_macrcv_errors++;
21741959748cSgd78059 
21751959748cSgd78059 			} else if (status & RXSTAT_RUNT) {
21761959748cSgd78059 				afep->afe_runt++;
21771959748cSgd78059 
21781959748cSgd78059 			} else if (status & RXSTAT_COLLSEEN) {
21791959748cSgd78059 				/* this should really be rx_late_collisions */
21801959748cSgd78059 				afep->afe_macrcv_errors++;
21811959748cSgd78059 
21821959748cSgd78059 			} else if (status & RXSTAT_DRIBBLE) {
21831959748cSgd78059 				afep->afe_align_errors++;
21841959748cSgd78059 
21851959748cSgd78059 			} else if (status & RXSTAT_CRCERR) {
21861959748cSgd78059 				afep->afe_fcs_errors++;
21871959748cSgd78059 
21881959748cSgd78059 			} else if (status & RXSTAT_OFLOW) {
21891959748cSgd78059 				afep->afe_overflow++;
21901959748cSgd78059 			}
21911959748cSgd78059 		}
21921959748cSgd78059 
21931959748cSgd78059 		else if (len > ETHERVLANMTU) {
21941959748cSgd78059 			afep->afe_errrcv++;
21951959748cSgd78059 			afep->afe_toolong_errors++;
21961959748cSgd78059 		}
21971959748cSgd78059 
21981959748cSgd78059 		/*
21991959748cSgd78059 		 * At this point, the chip thinks the packet is OK.
22001959748cSgd78059 		 */
22011959748cSgd78059 		else {
22021959748cSgd78059 			mp = allocb(len + AFE_HEADROOM, 0);
22031959748cSgd78059 			if (mp == NULL) {
22041959748cSgd78059 				afep->afe_errrcv++;
22051959748cSgd78059 				afep->afe_norcvbuf++;
22061959748cSgd78059 				goto skip;
22071959748cSgd78059 			}
22081959748cSgd78059 
22091959748cSgd78059 			/* sync the buffer before we look at it */
22101959748cSgd78059 			SYNCRXBUF(rxb, len, DDI_DMA_SYNC_FORKERNEL);
22111959748cSgd78059 			mp->b_rptr += AFE_HEADROOM;
22121959748cSgd78059 			mp->b_wptr = mp->b_rptr + len;
22131959748cSgd78059 			bcopy((char *)rxb->rxb_buf, mp->b_rptr, len);
22141959748cSgd78059 
22151959748cSgd78059 			afep->afe_ipackets++;
22161959748cSgd78059 			afep->afe_rbytes += len;
22171959748cSgd78059 			if (status & RXSTAT_GROUP) {
22181959748cSgd78059 				if (bcmp(mp->b_rptr, afe_broadcast,
22191959748cSgd78059 				    ETHERADDRL) == 0)
22201959748cSgd78059 					afep->afe_brdcstrcv++;
22211959748cSgd78059 				else
22221959748cSgd78059 					afep->afe_multircv++;
22231959748cSgd78059 			}
22241959748cSgd78059 			*mpp = mp;
22251959748cSgd78059 			mpp = &mp->b_next;
22261959748cSgd78059 		}
22271959748cSgd78059 
22281959748cSgd78059 skip:
22291959748cSgd78059 		/* return ring entry to the hardware */
22301959748cSgd78059 		PUTRXDESC(afep, rmd->desc_status, RXSTAT_OWN);
22311959748cSgd78059 		SYNCRXDESC(afep, head, DDI_DMA_SYNC_FORDEV);
22321959748cSgd78059 
22331959748cSgd78059 		/* advance to next RMD */
22341959748cSgd78059 		head = (head + 1) % AFE_RXRING;
22351959748cSgd78059 	}
22361959748cSgd78059 
22371959748cSgd78059 	afep->afe_rxhead = head;
22381959748cSgd78059 
22391959748cSgd78059 	return (mpchain);
22401959748cSgd78059 }
22411959748cSgd78059 
22421959748cSgd78059 int
22431959748cSgd78059 afe_m_stat(void *arg, uint_t stat, uint64_t *val)
22441959748cSgd78059 {
22451959748cSgd78059 	afe_t	*afep = arg;
22461959748cSgd78059 
22471959748cSgd78059 	mutex_enter(&afep->afe_xmtlock);
22481959748cSgd78059 	if ((afep->afe_flags & (AFE_RUNNING|AFE_SUSPENDED)) == AFE_RUNNING)
22491959748cSgd78059 		afe_reclaim(afep);
22501959748cSgd78059 	mutex_exit(&afep->afe_xmtlock);
22511959748cSgd78059 
2252bdb9230aSGarrett D'Amore 	if (mii_m_getstat(afep->afe_mii, stat, val) == 0) {
2253bdb9230aSGarrett D'Amore 		return (0);
2254bdb9230aSGarrett D'Amore 	}
22551959748cSgd78059 	switch (stat) {
22561959748cSgd78059 	case MAC_STAT_MULTIRCV:
22571959748cSgd78059 		*val = afep->afe_multircv;
22581959748cSgd78059 		break;
22591959748cSgd78059 
22601959748cSgd78059 	case MAC_STAT_BRDCSTRCV:
22611959748cSgd78059 		*val = afep->afe_brdcstrcv;
22621959748cSgd78059 		break;
22631959748cSgd78059 
22641959748cSgd78059 	case MAC_STAT_MULTIXMT:
22651959748cSgd78059 		*val = afep->afe_multixmt;
22661959748cSgd78059 		break;
22671959748cSgd78059 
22681959748cSgd78059 	case MAC_STAT_BRDCSTXMT:
22691959748cSgd78059 		*val = afep->afe_brdcstxmt;
22701959748cSgd78059 		break;
22711959748cSgd78059 
22721959748cSgd78059 	case MAC_STAT_IPACKETS:
22731959748cSgd78059 		*val = afep->afe_ipackets;
22741959748cSgd78059 		break;
22751959748cSgd78059 
22761959748cSgd78059 	case MAC_STAT_RBYTES:
22771959748cSgd78059 		*val = afep->afe_rbytes;
22781959748cSgd78059 		break;
22791959748cSgd78059 
22801959748cSgd78059 	case MAC_STAT_OPACKETS:
22811959748cSgd78059 		*val = afep->afe_opackets;
22821959748cSgd78059 		break;
22831959748cSgd78059 
22841959748cSgd78059 	case MAC_STAT_OBYTES:
22851959748cSgd78059 		*val = afep->afe_obytes;
22861959748cSgd78059 		break;
22871959748cSgd78059 
22881959748cSgd78059 	case MAC_STAT_NORCVBUF:
22891959748cSgd78059 		*val = afep->afe_norcvbuf;
22901959748cSgd78059 		break;
22911959748cSgd78059 
22921959748cSgd78059 	case MAC_STAT_NOXMTBUF:
22931959748cSgd78059 		*val = 0;
22941959748cSgd78059 		break;
22951959748cSgd78059 
22961959748cSgd78059 	case MAC_STAT_COLLISIONS:
22971959748cSgd78059 		*val = afep->afe_collisions;
22981959748cSgd78059 		break;
22991959748cSgd78059 
23001959748cSgd78059 	case MAC_STAT_IERRORS:
23011959748cSgd78059 		*val = afep->afe_errrcv;
23021959748cSgd78059 		break;
23031959748cSgd78059 
23041959748cSgd78059 	case MAC_STAT_OERRORS:
23051959748cSgd78059 		*val = afep->afe_errxmt;
23061959748cSgd78059 		break;
23071959748cSgd78059 
23081959748cSgd78059 	case ETHER_STAT_ALIGN_ERRORS:
23091959748cSgd78059 		*val = afep->afe_align_errors;
23101959748cSgd78059 		break;
23111959748cSgd78059 
23121959748cSgd78059 	case ETHER_STAT_FCS_ERRORS:
23131959748cSgd78059 		*val = afep->afe_fcs_errors;
23141959748cSgd78059 		break;
23151959748cSgd78059 
23161959748cSgd78059 	case ETHER_STAT_SQE_ERRORS:
23171959748cSgd78059 		*val = afep->afe_sqe_errors;
23181959748cSgd78059 		break;
23191959748cSgd78059 
23201959748cSgd78059 	case ETHER_STAT_DEFER_XMTS:
23211959748cSgd78059 		*val = afep->afe_defer_xmts;
23221959748cSgd78059 		break;
23231959748cSgd78059 
23241959748cSgd78059 	case ETHER_STAT_FIRST_COLLISIONS:
23251959748cSgd78059 		*val = afep->afe_first_collisions;
23261959748cSgd78059 		break;
23271959748cSgd78059 
23281959748cSgd78059 	case ETHER_STAT_MULTI_COLLISIONS:
23291959748cSgd78059 		*val = afep->afe_multi_collisions;
23301959748cSgd78059 		break;
23311959748cSgd78059 
23321959748cSgd78059 	case ETHER_STAT_TX_LATE_COLLISIONS:
23331959748cSgd78059 		*val = afep->afe_tx_late_collisions;
23341959748cSgd78059 		break;
23351959748cSgd78059 
23361959748cSgd78059 	case ETHER_STAT_EX_COLLISIONS:
23371959748cSgd78059 		*val = afep->afe_ex_collisions;
23381959748cSgd78059 		break;
23391959748cSgd78059 
23401959748cSgd78059 	case ETHER_STAT_MACXMT_ERRORS:
23411959748cSgd78059 		*val = afep->afe_macxmt_errors;
23421959748cSgd78059 		break;
23431959748cSgd78059 
23441959748cSgd78059 	case ETHER_STAT_CARRIER_ERRORS:
23451959748cSgd78059 		*val = afep->afe_carrier_errors;
23461959748cSgd78059 		break;
23471959748cSgd78059 
23481959748cSgd78059 	case ETHER_STAT_TOOLONG_ERRORS:
23491959748cSgd78059 		*val = afep->afe_toolong_errors;
23501959748cSgd78059 		break;
23511959748cSgd78059 
23521959748cSgd78059 	case ETHER_STAT_MACRCV_ERRORS:
23531959748cSgd78059 		*val = afep->afe_macrcv_errors;
23541959748cSgd78059 		break;
23551959748cSgd78059 
23561959748cSgd78059 	case MAC_STAT_OVERFLOWS:
23571959748cSgd78059 		*val = afep->afe_overflow;
23581959748cSgd78059 		break;
23591959748cSgd78059 
23601959748cSgd78059 	case MAC_STAT_UNDERFLOWS:
23611959748cSgd78059 		*val = afep->afe_underflow;
23621959748cSgd78059 		break;
23631959748cSgd78059 
23641959748cSgd78059 	case ETHER_STAT_TOOSHORT_ERRORS:
23651959748cSgd78059 		*val = afep->afe_runt;
23661959748cSgd78059 		break;
23671959748cSgd78059 
23681959748cSgd78059 	case ETHER_STAT_JABBER_ERRORS:
23691959748cSgd78059 		*val = afep->afe_jabber;
23701959748cSgd78059 		break;
23711959748cSgd78059 
23721959748cSgd78059 	default:
23731959748cSgd78059 		return (ENOTSUP);
23741959748cSgd78059 	}
23751959748cSgd78059 	return (0);
23761959748cSgd78059 }
23771959748cSgd78059 
237896fb08b9Sgd78059 int
2379*0dc2366fSVenugopal Iyer afe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
2380*0dc2366fSVenugopal Iyer     void *val)
23811959748cSgd78059 {
238296fb08b9Sgd78059 	afe_t		*afep = arg;
23831959748cSgd78059 
2384*0dc2366fSVenugopal Iyer 	return (mii_m_getprop(afep->afe_mii, name, num, sz, val));
23851959748cSgd78059 }
23861959748cSgd78059 
23871959748cSgd78059 int
238896fb08b9Sgd78059 afe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
238996fb08b9Sgd78059     const void *val)
23901959748cSgd78059 {
239196fb08b9Sgd78059 	afe_t		*afep = arg;
23921959748cSgd78059 
2393bdb9230aSGarrett D'Amore 	return (mii_m_setprop(afep->afe_mii, name, num, sz, val));
23941959748cSgd78059 }
23951959748cSgd78059 
2396*0dc2366fSVenugopal Iyer static void
2397*0dc2366fSVenugopal Iyer afe_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
2398*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t prh)
2399*0dc2366fSVenugopal Iyer {
2400*0dc2366fSVenugopal Iyer 	afe_t		*afep = arg;
2401*0dc2366fSVenugopal Iyer 
2402*0dc2366fSVenugopal Iyer 	mii_m_propinfo(afep->afe_mii, name, num, prh);
2403*0dc2366fSVenugopal Iyer }
2404*0dc2366fSVenugopal Iyer 
24051959748cSgd78059 /*
24061959748cSgd78059  * Debugging and error reporting.
24071959748cSgd78059  */
24081959748cSgd78059 void
24091959748cSgd78059 afe_error(dev_info_t *dip, char *fmt, ...)
24101959748cSgd78059 {
24111959748cSgd78059 	va_list	ap;
24121959748cSgd78059 	char	buf[256];
24131959748cSgd78059 
24141959748cSgd78059 	va_start(ap, fmt);
24151959748cSgd78059 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
24161959748cSgd78059 	va_end(ap);
24171959748cSgd78059 
24181959748cSgd78059 	if (dip) {
24191959748cSgd78059 		cmn_err(CE_WARN, "%s%d: %s",
24201959748cSgd78059 		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
24211959748cSgd78059 	} else {
24221959748cSgd78059 		cmn_err(CE_WARN, "afe: %s", buf);
24231959748cSgd78059 	}
24241959748cSgd78059 }
2425