xref: /titanic_52/usr/src/uts/common/io/nge/nge_main.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
16f3e57acSmx205022 /*
247693af9Smx205022  * CDDL HEADER START
347693af9Smx205022  *
447693af9Smx205022  * The contents of this file are subject to the terms of the
547693af9Smx205022  * Common Development and Distribution License (the "License").
647693af9Smx205022  * You may not use this file except in compliance with the License.
747693af9Smx205022  *
847693af9Smx205022  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
947693af9Smx205022  * or http://www.opensolaris.org/os/licensing.
1047693af9Smx205022  * See the License for the specific language governing permissions
1147693af9Smx205022  * and limitations under the License.
1247693af9Smx205022  *
1347693af9Smx205022  * When distributing Covered Code, include this CDDL HEADER in each
1447693af9Smx205022  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1547693af9Smx205022  * If applicable, add the following below this CDDL HEADER, with the
1647693af9Smx205022  * fields enclosed by brackets "[]" replaced with your own identifying
1747693af9Smx205022  * information: Portions Copyright [yyyy] [name of copyright owner]
1847693af9Smx205022  *
1947693af9Smx205022  * CDDL HEADER END
206f3e57acSmx205022  */
216f3e57acSmx205022 
226f3e57acSmx205022 /*
23*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2447693af9Smx205022  * Use is subject to license terms.
256f3e57acSmx205022  */
266f3e57acSmx205022 
276f3e57acSmx205022 
286f3e57acSmx205022 #include "nge.h"
296f3e57acSmx205022 
306f3e57acSmx205022 /*
316f3e57acSmx205022  * Describes the chip's DMA engine
326f3e57acSmx205022  */
336f3e57acSmx205022 
346f3e57acSmx205022 static ddi_dma_attr_t hot_dma_attr = {
356f3e57acSmx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
366f3e57acSmx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
376f3e57acSmx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
386f3e57acSmx205022 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
396f3e57acSmx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
406f3e57acSmx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
416f3e57acSmx205022 	0x00000001,			/* dma_attr_minxfer	*/
426f3e57acSmx205022 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
436f3e57acSmx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
446f3e57acSmx205022 	1,				/* dma_attr_sgllen 	*/
456f3e57acSmx205022 	0x00000001,			/* dma_attr_granular 	*/
466f3e57acSmx205022 	0
476f3e57acSmx205022 };
486f3e57acSmx205022 
496f3e57acSmx205022 static ddi_dma_attr_t hot_tx_dma_attr = {
506f3e57acSmx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
516f3e57acSmx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
526f3e57acSmx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
536f3e57acSmx205022 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
546f3e57acSmx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
556f3e57acSmx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
566f3e57acSmx205022 	0x00000001,			/* dma_attr_minxfer	*/
576f3e57acSmx205022 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
586f3e57acSmx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
596f3e57acSmx205022 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
606f3e57acSmx205022 	1,				/* dma_attr_granular 	*/
616f3e57acSmx205022 	0
626f3e57acSmx205022 };
636f3e57acSmx205022 
646f3e57acSmx205022 static ddi_dma_attr_t sum_dma_attr = {
656f3e57acSmx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
666f3e57acSmx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
676f3e57acSmx205022 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
686f3e57acSmx205022 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
696f3e57acSmx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
706f3e57acSmx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
716f3e57acSmx205022 	0x00000001,			/* dma_attr_minxfer	*/
726f3e57acSmx205022 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
736f3e57acSmx205022 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
746f3e57acSmx205022 	1,				/* dma_attr_sgllen 	*/
756f3e57acSmx205022 	0x00000001,			/* dma_attr_granular 	*/
766f3e57acSmx205022 	0
776f3e57acSmx205022 };
786f3e57acSmx205022 
796f3e57acSmx205022 static ddi_dma_attr_t sum_tx_dma_attr = {
806f3e57acSmx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
816f3e57acSmx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
826f3e57acSmx205022 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
836f3e57acSmx205022 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
846f3e57acSmx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
856f3e57acSmx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
866f3e57acSmx205022 	0x00000001,			/* dma_attr_minxfer	*/
876f3e57acSmx205022 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
886f3e57acSmx205022 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
896f3e57acSmx205022 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
906f3e57acSmx205022 	1,				/* dma_attr_granular 	*/
916f3e57acSmx205022 	0
926f3e57acSmx205022 };
936f3e57acSmx205022 
946f3e57acSmx205022 /*
956f3e57acSmx205022  * DMA access attributes for data.
966f3e57acSmx205022  */
976f3e57acSmx205022 ddi_device_acc_attr_t nge_data_accattr = {
986f3e57acSmx205022 	DDI_DEVICE_ATTR_V0,
996f3e57acSmx205022 	DDI_STRUCTURE_LE_ACC,
1006f3e57acSmx205022 	DDI_STRICTORDER_ACC,
1016f3e57acSmx205022 	DDI_DEFAULT_ACC
1026f3e57acSmx205022 };
1036f3e57acSmx205022 
1046f3e57acSmx205022 /*
1056f3e57acSmx205022  * DMA access attributes for descriptors.
1066f3e57acSmx205022  */
1076f3e57acSmx205022 static ddi_device_acc_attr_t nge_desc_accattr = {
1086f3e57acSmx205022 	DDI_DEVICE_ATTR_V0,
1096f3e57acSmx205022 	DDI_STRUCTURE_LE_ACC,
1106f3e57acSmx205022 	DDI_STRICTORDER_ACC,
1116f3e57acSmx205022 	DDI_DEFAULT_ACC
1126f3e57acSmx205022 };
1136f3e57acSmx205022 
1146f3e57acSmx205022 /*
1156f3e57acSmx205022  * PIO access attributes for registers
1166f3e57acSmx205022  */
1176f3e57acSmx205022 static ddi_device_acc_attr_t nge_reg_accattr = {
1186f3e57acSmx205022 	DDI_DEVICE_ATTR_V0,
1196f3e57acSmx205022 	DDI_STRUCTURE_LE_ACC,
1206f3e57acSmx205022 	DDI_STRICTORDER_ACC,
1216f3e57acSmx205022 	DDI_DEFAULT_ACC
1226f3e57acSmx205022 };
1236f3e57acSmx205022 
1246f3e57acSmx205022 /*
1256f3e57acSmx205022  * NIC DESC MODE 2
1266f3e57acSmx205022  */
1276f3e57acSmx205022 
1286f3e57acSmx205022 static const nge_desc_attr_t nge_sum_desc = {
1296f3e57acSmx205022 
1306f3e57acSmx205022 	sizeof (sum_rx_bd),
1316f3e57acSmx205022 	sizeof (sum_tx_bd),
1326f3e57acSmx205022 	&sum_dma_attr,
1336f3e57acSmx205022 	&sum_tx_dma_attr,
1346f3e57acSmx205022 	nge_sum_rxd_fill,
1356f3e57acSmx205022 	nge_sum_rxd_check,
1366f3e57acSmx205022 	nge_sum_txd_fill,
1376f3e57acSmx205022 	nge_sum_txd_check,
1386f3e57acSmx205022 };
1396f3e57acSmx205022 
1406f3e57acSmx205022 /*
1416f3e57acSmx205022  * NIC DESC MODE 3
1426f3e57acSmx205022  */
1436f3e57acSmx205022 
1446f3e57acSmx205022 static const nge_desc_attr_t nge_hot_desc = {
1456f3e57acSmx205022 
1466f3e57acSmx205022 	sizeof (hot_rx_bd),
1476f3e57acSmx205022 	sizeof (hot_tx_bd),
1486f3e57acSmx205022 	&hot_dma_attr,
1496f3e57acSmx205022 	&hot_tx_dma_attr,
1506f3e57acSmx205022 	nge_hot_rxd_fill,
1516f3e57acSmx205022 	nge_hot_rxd_check,
1526f3e57acSmx205022 	nge_hot_txd_fill,
1536f3e57acSmx205022 	nge_hot_txd_check,
1546f3e57acSmx205022 };
1556f3e57acSmx205022 
1564045d941Ssowmini static char nge_ident[] = "nVidia 1Gb Ethernet";
1576f3e57acSmx205022 static char clsize_propname[] = "cache-line-size";
1586f3e57acSmx205022 static char latency_propname[] = "latency-timer";
1596f3e57acSmx205022 static char debug_propname[]	= "nge-debug-flags";
16002d51d0dSjj146644 static char intr_moderation[] = "intr-moderation";
1616f3e57acSmx205022 static char rx_data_hw[] = "rx-data-hw";
1626f3e57acSmx205022 static char rx_prd_lw[] = "rx-prd-lw";
1636f3e57acSmx205022 static char rx_prd_hw[] = "rx-prd-hw";
1646f3e57acSmx205022 static char sw_intr_intv[] = "sw-intr-intvl";
1656f3e57acSmx205022 static char nge_desc_mode[] = "desc-mode";
1666f3e57acSmx205022 static char default_mtu[] = "default_mtu";
1676f3e57acSmx205022 static char low_memory_mode[] = "minimal-memory-usage";
1686f3e57acSmx205022 extern kmutex_t nge_log_mutex[1];
1696f3e57acSmx205022 
1706f3e57acSmx205022 static int		nge_m_start(void *);
1716f3e57acSmx205022 static void		nge_m_stop(void *);
1726f3e57acSmx205022 static int		nge_m_promisc(void *, boolean_t);
1736f3e57acSmx205022 static int		nge_m_multicst(void *, boolean_t, const uint8_t *);
1746f3e57acSmx205022 static int		nge_m_unicst(void *, const uint8_t *);
1756f3e57acSmx205022 static void		nge_m_ioctl(void *, queue_t *, mblk_t *);
1766f3e57acSmx205022 static boolean_t	nge_m_getcapab(void *, mac_capab_t, void *);
1775a3d0718Smx205022 static int		nge_m_setprop(void *, const char *, mac_prop_id_t,
1785a3d0718Smx205022 	uint_t, const void *);
1795a3d0718Smx205022 static int		nge_m_getprop(void *, const char *, mac_prop_id_t,
180*0dc2366fSVenugopal Iyer 	uint_t, void *);
181*0dc2366fSVenugopal Iyer static void		nge_m_propinfo(void *, const char *, mac_prop_id_t,
182*0dc2366fSVenugopal Iyer 	mac_prop_info_handle_t);
1835a3d0718Smx205022 static int		nge_set_priv_prop(nge_t *, const char *, uint_t,
1845a3d0718Smx205022 	const void *);
1855a3d0718Smx205022 static int		nge_get_priv_prop(nge_t *, const char *, uint_t,
186*0dc2366fSVenugopal Iyer 	void *);
1876f3e57acSmx205022 
1885a3d0718Smx205022 #define		NGE_M_CALLBACK_FLAGS\
189*0dc2366fSVenugopal Iyer 		(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | \
190*0dc2366fSVenugopal Iyer 		MC_PROPINFO)
1916f3e57acSmx205022 
1926f3e57acSmx205022 static mac_callbacks_t nge_m_callbacks = {
1936f3e57acSmx205022 	NGE_M_CALLBACK_FLAGS,
1946f3e57acSmx205022 	nge_m_stat,
1956f3e57acSmx205022 	nge_m_start,
1966f3e57acSmx205022 	nge_m_stop,
1976f3e57acSmx205022 	nge_m_promisc,
1986f3e57acSmx205022 	nge_m_multicst,
1996f3e57acSmx205022 	nge_m_unicst,
2006f3e57acSmx205022 	nge_m_tx,
201*0dc2366fSVenugopal Iyer 	NULL,
2026f3e57acSmx205022 	nge_m_ioctl,
2035a3d0718Smx205022 	nge_m_getcapab,
2045a3d0718Smx205022 	NULL,
2055a3d0718Smx205022 	NULL,
2065a3d0718Smx205022 	nge_m_setprop,
207*0dc2366fSVenugopal Iyer 	nge_m_getprop,
208*0dc2366fSVenugopal Iyer 	nge_m_propinfo
2096f3e57acSmx205022 };
2106f3e57acSmx205022 
211*0dc2366fSVenugopal Iyer char *nge_priv_props[] = {
212*0dc2366fSVenugopal Iyer 	"_tx_bcopy_threshold",
213*0dc2366fSVenugopal Iyer 	"_rx_bcopy_threshold",
214*0dc2366fSVenugopal Iyer 	"_recv_max_packet",
215*0dc2366fSVenugopal Iyer 	"_poll_quiet_time",
216*0dc2366fSVenugopal Iyer 	"_poll_busy_time",
217*0dc2366fSVenugopal Iyer 	"_rx_intr_hwater",
218*0dc2366fSVenugopal Iyer 	"_rx_intr_lwater",
219*0dc2366fSVenugopal Iyer 	NULL
2204045d941Ssowmini };
2214045d941Ssowmini 
2226f3e57acSmx205022 static int nge_add_intrs(nge_t *, int);
2236f3e57acSmx205022 static void nge_rem_intrs(nge_t *);
2246f3e57acSmx205022 static int nge_register_intrs_and_init_locks(nge_t *);
2256f3e57acSmx205022 
2266f3e57acSmx205022 /*
2276f3e57acSmx205022  * NGE MSI tunable:
2286f3e57acSmx205022  */
2296f3e57acSmx205022 boolean_t nge_enable_msi = B_FALSE;
2306f3e57acSmx205022 
2316f3e57acSmx205022 static enum ioc_reply
2326f3e57acSmx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
2336f3e57acSmx205022 {
2346f3e57acSmx205022 	/*
2356f3e57acSmx205022 	 * If the mode isn't being changed, there's nothing to do ...
2366f3e57acSmx205022 	 */
2376f3e57acSmx205022 	if (mode == ngep->param_loop_mode)
2386f3e57acSmx205022 		return (IOC_ACK);
2396f3e57acSmx205022 
2406f3e57acSmx205022 	/*
2416f3e57acSmx205022 	 * Validate the requested mode and prepare a suitable message
2426f3e57acSmx205022 	 * to explain the link down/up cycle that the change will
2436f3e57acSmx205022 	 * probably induce ...
2446f3e57acSmx205022 	 */
2456f3e57acSmx205022 	switch (mode) {
2466f3e57acSmx205022 	default:
2476f3e57acSmx205022 		return (IOC_INVAL);
2486f3e57acSmx205022 
2496f3e57acSmx205022 	case NGE_LOOP_NONE:
2506f3e57acSmx205022 	case NGE_LOOP_EXTERNAL_100:
2516f3e57acSmx205022 	case NGE_LOOP_EXTERNAL_10:
2526f3e57acSmx205022 	case NGE_LOOP_INTERNAL_PHY:
2536f3e57acSmx205022 		break;
2546f3e57acSmx205022 	}
2556f3e57acSmx205022 
2566f3e57acSmx205022 	/*
2576f3e57acSmx205022 	 * All OK; tell the caller to reprogram
2586f3e57acSmx205022 	 * the PHY and/or MAC for the new mode ...
2596f3e57acSmx205022 	 */
2606f3e57acSmx205022 	ngep->param_loop_mode = mode;
2616f3e57acSmx205022 	return (IOC_RESTART_ACK);
2626f3e57acSmx205022 }
2636f3e57acSmx205022 
2646f3e57acSmx205022 #undef	NGE_DBG
2656f3e57acSmx205022 #define	NGE_DBG		NGE_DBG_INIT
2666f3e57acSmx205022 
2676f3e57acSmx205022 /*
2686f3e57acSmx205022  * Utility routine to carve a slice off a chunk of allocated memory,
2696f3e57acSmx205022  * updating the chunk descriptor accordingly.  The size of the slice
2706f3e57acSmx205022  * is given by the product of the <qty> and <size> parameters.
2716f3e57acSmx205022  */
2726f3e57acSmx205022 void
2736f3e57acSmx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
2746f3e57acSmx205022     uint32_t qty, uint32_t size)
2756f3e57acSmx205022 {
2766f3e57acSmx205022 	size_t totsize;
2776f3e57acSmx205022 
2786f3e57acSmx205022 	totsize = qty*size;
2796f3e57acSmx205022 	ASSERT(size > 0);
2806f3e57acSmx205022 	ASSERT(totsize <= chunk->alength);
2816f3e57acSmx205022 
2826f3e57acSmx205022 	*slice = *chunk;
2836f3e57acSmx205022 	slice->nslots = qty;
2846f3e57acSmx205022 	slice->size = size;
2856f3e57acSmx205022 	slice->alength = totsize;
2866f3e57acSmx205022 
2876f3e57acSmx205022 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
2886f3e57acSmx205022 	chunk->alength -= totsize;
2896f3e57acSmx205022 	chunk->offset += totsize;
2906f3e57acSmx205022 	chunk->cookie.dmac_laddress += totsize;
2916f3e57acSmx205022 	chunk->cookie.dmac_size -= totsize;
2926f3e57acSmx205022 }
2936f3e57acSmx205022 
2946f3e57acSmx205022 /*
2956f3e57acSmx205022  * Allocate an area of memory and a DMA handle for accessing it
2966f3e57acSmx205022  */
2976f3e57acSmx205022 int
2986f3e57acSmx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
2996f3e57acSmx205022     uint_t dma_flags, dma_area_t *dma_p)
3006f3e57acSmx205022 {
3016f3e57acSmx205022 	int err;
3026f3e57acSmx205022 	caddr_t va;
3036f3e57acSmx205022 
3046f3e57acSmx205022 	NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
3056f3e57acSmx205022 	    (void *)ngep, memsize, attr_p, dma_flags, dma_p));
3066f3e57acSmx205022 	/*
3076f3e57acSmx205022 	 * Allocate handle
3086f3e57acSmx205022 	 */
3096f3e57acSmx205022 	err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
3106f3e57acSmx205022 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
3116f3e57acSmx205022 	if (err != DDI_SUCCESS)
3126f3e57acSmx205022 		goto fail;
3136f3e57acSmx205022 
3146f3e57acSmx205022 	/*
3156f3e57acSmx205022 	 * Allocate memory
3166f3e57acSmx205022 	 */
3176f3e57acSmx205022 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
3186f3e57acSmx205022 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
3196f3e57acSmx205022 	    DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
3206f3e57acSmx205022 	if (err != DDI_SUCCESS)
3216f3e57acSmx205022 		goto fail;
3226f3e57acSmx205022 
3236f3e57acSmx205022 	/*
3246f3e57acSmx205022 	 * Bind the two together
3256f3e57acSmx205022 	 */
3266f3e57acSmx205022 	dma_p->mem_va = va;
3276f3e57acSmx205022 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
3286f3e57acSmx205022 	    va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
3296f3e57acSmx205022 	    &dma_p->cookie, &dma_p->ncookies);
3306f3e57acSmx205022 
3316f3e57acSmx205022 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
3326f3e57acSmx205022 		goto fail;
3336f3e57acSmx205022 
3346f3e57acSmx205022 	dma_p->nslots = ~0U;
3356f3e57acSmx205022 	dma_p->size = ~0U;
3366f3e57acSmx205022 	dma_p->offset = 0;
3376f3e57acSmx205022 
3386f3e57acSmx205022 	return (DDI_SUCCESS);
3396f3e57acSmx205022 
3406f3e57acSmx205022 fail:
3416f3e57acSmx205022 	nge_free_dma_mem(dma_p);
3426f3e57acSmx205022 	NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
3436f3e57acSmx205022 
3446f3e57acSmx205022 	return (DDI_FAILURE);
3456f3e57acSmx205022 }
3466f3e57acSmx205022 
3476f3e57acSmx205022 /*
3486f3e57acSmx205022  * Free one allocated area of DMAable memory
3496f3e57acSmx205022  */
3506f3e57acSmx205022 void
3516f3e57acSmx205022 nge_free_dma_mem(dma_area_t *dma_p)
3526f3e57acSmx205022 {
3536f3e57acSmx205022 	if (dma_p->dma_hdl != NULL) {
3546f3e57acSmx205022 		if (dma_p->ncookies) {
3556f3e57acSmx205022 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
3566f3e57acSmx205022 			dma_p->ncookies = 0;
3576f3e57acSmx205022 		}
3586f3e57acSmx205022 	}
3596f3e57acSmx205022 	if (dma_p->acc_hdl != NULL) {
3606f3e57acSmx205022 		ddi_dma_mem_free(&dma_p->acc_hdl);
3616f3e57acSmx205022 		dma_p->acc_hdl = NULL;
3626f3e57acSmx205022 	}
3636f3e57acSmx205022 	if (dma_p->dma_hdl != NULL) {
3646f3e57acSmx205022 		ddi_dma_free_handle(&dma_p->dma_hdl);
3656f3e57acSmx205022 		dma_p->dma_hdl = NULL;
3666f3e57acSmx205022 	}
3676f3e57acSmx205022 }
3686f3e57acSmx205022 
3696f3e57acSmx205022 #define	ALLOC_TX_BUF	0x1
3706f3e57acSmx205022 #define	ALLOC_TX_DESC	0x2
3716f3e57acSmx205022 #define	ALLOC_RX_DESC	0x4
3726f3e57acSmx205022 
3736f3e57acSmx205022 int
3746f3e57acSmx205022 nge_alloc_bufs(nge_t *ngep)
3756f3e57acSmx205022 {
3766f3e57acSmx205022 	int err;
3776f3e57acSmx205022 	int split;
3786f3e57acSmx205022 	int progress;
3796f3e57acSmx205022 	size_t txbuffsize;
3806f3e57acSmx205022 	size_t rxdescsize;
3816f3e57acSmx205022 	size_t txdescsize;
3826f3e57acSmx205022 
3836f3e57acSmx205022 	txbuffsize = ngep->tx_desc * ngep->buf_size;
3846f3e57acSmx205022 	rxdescsize = ngep->rx_desc;
3856f3e57acSmx205022 	txdescsize = ngep->tx_desc;
3866f3e57acSmx205022 	rxdescsize *= ngep->desc_attr.rxd_size;
3876f3e57acSmx205022 	txdescsize *= ngep->desc_attr.txd_size;
3886f3e57acSmx205022 	progress = 0;
3896f3e57acSmx205022 
3906f3e57acSmx205022 	NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
3916f3e57acSmx205022 	/*
3926f3e57acSmx205022 	 * Allocate memory & handles for TX buffers
3936f3e57acSmx205022 	 */
3946f3e57acSmx205022 	ASSERT((txbuffsize % ngep->nge_split) == 0);
3956f3e57acSmx205022 	for (split = 0; split < ngep->nge_split; ++split) {
3966f3e57acSmx205022 		err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
3976f3e57acSmx205022 		    &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
3986f3e57acSmx205022 		    &ngep->send->buf[split]);
3996f3e57acSmx205022 		if (err != DDI_SUCCESS)
4006f3e57acSmx205022 			goto fail;
4016f3e57acSmx205022 	}
4026f3e57acSmx205022 
4036f3e57acSmx205022 	progress |= ALLOC_TX_BUF;
4046f3e57acSmx205022 
4056f3e57acSmx205022 	/*
4066f3e57acSmx205022 	 * Allocate memory & handles for receive return rings and
4076f3e57acSmx205022 	 * buffer (producer) descriptor rings
4086f3e57acSmx205022 	 */
4096f3e57acSmx205022 	err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
4106f3e57acSmx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
4116f3e57acSmx205022 	if (err != DDI_SUCCESS)
4126f3e57acSmx205022 		goto fail;
4136f3e57acSmx205022 	progress |= ALLOC_RX_DESC;
4146f3e57acSmx205022 
4156f3e57acSmx205022 	/*
4166f3e57acSmx205022 	 * Allocate memory & handles for TX descriptor rings,
4176f3e57acSmx205022 	 */
4186f3e57acSmx205022 	err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
4196f3e57acSmx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
4206f3e57acSmx205022 	if (err != DDI_SUCCESS)
4216f3e57acSmx205022 		goto fail;
4226f3e57acSmx205022 	return (DDI_SUCCESS);
4236f3e57acSmx205022 
4246f3e57acSmx205022 fail:
4256f3e57acSmx205022 	if (progress & ALLOC_RX_DESC)
4266f3e57acSmx205022 		nge_free_dma_mem(&ngep->recv->desc);
4276f3e57acSmx205022 	if (progress & ALLOC_TX_BUF) {
4286f3e57acSmx205022 		for (split = 0; split < ngep->nge_split; ++split)
4296f3e57acSmx205022 			nge_free_dma_mem(&ngep->send->buf[split]);
4306f3e57acSmx205022 	}
4316f3e57acSmx205022 
4326f3e57acSmx205022 	return (DDI_FAILURE);
4336f3e57acSmx205022 }
4346f3e57acSmx205022 
4356f3e57acSmx205022 /*
4366f3e57acSmx205022  * This routine frees the transmit and receive buffers and descriptors.
4376f3e57acSmx205022  * Make sure the chip is stopped before calling it!
4386f3e57acSmx205022  */
4396f3e57acSmx205022 void
4406f3e57acSmx205022 nge_free_bufs(nge_t *ngep)
4416f3e57acSmx205022 {
4426f3e57acSmx205022 	int split;
4436f3e57acSmx205022 
4446f3e57acSmx205022 	NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
4456f3e57acSmx205022 
4466f3e57acSmx205022 	nge_free_dma_mem(&ngep->recv->desc);
4476f3e57acSmx205022 	nge_free_dma_mem(&ngep->send->desc);
4486f3e57acSmx205022 
4496f3e57acSmx205022 	for (split = 0; split < ngep->nge_split; ++split)
4506f3e57acSmx205022 		nge_free_dma_mem(&ngep->send->buf[split]);
4516f3e57acSmx205022 }
4526f3e57acSmx205022 
4536f3e57acSmx205022 /*
4546f3e57acSmx205022  * Clean up initialisation done above before the memory is freed
4556f3e57acSmx205022  */
4566f3e57acSmx205022 static void
4576f3e57acSmx205022 nge_fini_send_ring(nge_t *ngep)
4586f3e57acSmx205022 {
4596f3e57acSmx205022 	uint32_t slot;
4606f3e57acSmx205022 	size_t dmah_num;
4616f3e57acSmx205022 	send_ring_t *srp;
4626f3e57acSmx205022 	sw_tx_sbd_t *ssbdp;
4636f3e57acSmx205022 
4646f3e57acSmx205022 	srp = ngep->send;
4656f3e57acSmx205022 	ssbdp = srp->sw_sbds;
4666f3e57acSmx205022 
4676f3e57acSmx205022 	NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
4686f3e57acSmx205022 
4696f3e57acSmx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
4706f3e57acSmx205022 
4716f3e57acSmx205022 	for (slot = 0; slot < dmah_num; ++slot) {
4726f3e57acSmx205022 		if (srp->dmahndl[slot].hndl) {
4736f3e57acSmx205022 			(void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
4746f3e57acSmx205022 			ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
4756f3e57acSmx205022 			srp->dmahndl[slot].hndl = NULL;
4766f3e57acSmx205022 			srp->dmahndl[slot].next = NULL;
4776f3e57acSmx205022 		}
4786f3e57acSmx205022 	}
4796f3e57acSmx205022 
4806f3e57acSmx205022 	srp->dmah_free.head = NULL;
4816f3e57acSmx205022 	srp->dmah_free.tail = NULL;
4826f3e57acSmx205022 
4836f3e57acSmx205022 	kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
4846f3e57acSmx205022 
4856f3e57acSmx205022 }
4866f3e57acSmx205022 
4876f3e57acSmx205022 /*
4886f3e57acSmx205022  * Initialise the specified Send Ring, using the information in the
4896f3e57acSmx205022  * <dma_area> descriptors that it contains to set up all the other
4906f3e57acSmx205022  * fields. This routine should be called only once for each ring.
4916f3e57acSmx205022  */
4926f3e57acSmx205022 static int
4936f3e57acSmx205022 nge_init_send_ring(nge_t *ngep)
4946f3e57acSmx205022 {
4956f3e57acSmx205022 	size_t dmah_num;
4966f3e57acSmx205022 	uint32_t nslots;
4976f3e57acSmx205022 	uint32_t err;
4986f3e57acSmx205022 	uint32_t slot;
4996f3e57acSmx205022 	uint32_t split;
5006f3e57acSmx205022 	send_ring_t *srp;
5016f3e57acSmx205022 	sw_tx_sbd_t *ssbdp;
5026f3e57acSmx205022 	dma_area_t desc;
5036f3e57acSmx205022 	dma_area_t pbuf;
5046f3e57acSmx205022 
5056f3e57acSmx205022 	srp = ngep->send;
5066f3e57acSmx205022 	srp->desc.nslots = ngep->tx_desc;
5076f3e57acSmx205022 	nslots = srp->desc.nslots;
5086f3e57acSmx205022 
5096f3e57acSmx205022 	NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
5106f3e57acSmx205022 	/*
5116f3e57acSmx205022 	 * Other one-off initialisation of per-ring data
5126f3e57acSmx205022 	 */
5136f3e57acSmx205022 	srp->ngep = ngep;
5146f3e57acSmx205022 
5156f3e57acSmx205022 	/*
5166f3e57acSmx205022 	 * Allocate the array of s/w Send Buffer Descriptors
5176f3e57acSmx205022 	 */
5186f3e57acSmx205022 	ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
5196f3e57acSmx205022 	srp->sw_sbds = ssbdp;
5206f3e57acSmx205022 
5216f3e57acSmx205022 	/*
5226f3e57acSmx205022 	 * Now initialise each array element once and for all
5236f3e57acSmx205022 	 */
5246f3e57acSmx205022 	desc = srp->desc;
5256f3e57acSmx205022 	for (split = 0; split < ngep->nge_split; ++split) {
5266f3e57acSmx205022 		pbuf = srp->buf[split];
5276f3e57acSmx205022 		for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
5286f3e57acSmx205022 			nge_slice_chunk(&ssbdp->desc, &desc, 1,
5296f3e57acSmx205022 			    ngep->desc_attr.txd_size);
5306f3e57acSmx205022 			nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
5316f3e57acSmx205022 			    ngep->buf_size);
5326f3e57acSmx205022 		}
5336f3e57acSmx205022 		ASSERT(pbuf.alength == 0);
5346f3e57acSmx205022 	}
5356f3e57acSmx205022 	ASSERT(desc.alength == 0);
5366f3e57acSmx205022 
5376f3e57acSmx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5386f3e57acSmx205022 
5396f3e57acSmx205022 	/* preallocate dma handles for tx buffer */
5406f3e57acSmx205022 	for (slot = 0; slot < dmah_num; ++slot) {
5416f3e57acSmx205022 
5426f3e57acSmx205022 		err = ddi_dma_alloc_handle(ngep->devinfo,
5436f3e57acSmx205022 		    ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
5446f3e57acSmx205022 		    NULL, &srp->dmahndl[slot].hndl);
5456f3e57acSmx205022 
5466f3e57acSmx205022 		if (err != DDI_SUCCESS) {
5476f3e57acSmx205022 			nge_fini_send_ring(ngep);
5486f3e57acSmx205022 			nge_error(ngep,
5496f3e57acSmx205022 			    "nge_init_send_ring: alloc dma handle fails");
5506f3e57acSmx205022 			return (DDI_FAILURE);
5516f3e57acSmx205022 		}
5526f3e57acSmx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5536f3e57acSmx205022 	}
5546f3e57acSmx205022 
5556f3e57acSmx205022 	srp->dmah_free.head = srp->dmahndl;
5566f3e57acSmx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5576f3e57acSmx205022 	srp->dmah_free.tail->next = NULL;
5586f3e57acSmx205022 
5596f3e57acSmx205022 	return (DDI_SUCCESS);
5606f3e57acSmx205022 }
5616f3e57acSmx205022 
5626f3e57acSmx205022 /*
5636f3e57acSmx205022  * Intialize the tx recycle pointer and tx sending pointer of tx ring
5646f3e57acSmx205022  * and set the type of tx's data descriptor by default.
5656f3e57acSmx205022  */
5666f3e57acSmx205022 static void
5676f3e57acSmx205022 nge_reinit_send_ring(nge_t *ngep)
5686f3e57acSmx205022 {
5696f3e57acSmx205022 	size_t dmah_num;
5706f3e57acSmx205022 	uint32_t slot;
5716f3e57acSmx205022 	send_ring_t *srp;
5726f3e57acSmx205022 	sw_tx_sbd_t *ssbdp;
5736f3e57acSmx205022 
5746f3e57acSmx205022 	srp = ngep->send;
5756f3e57acSmx205022 
5766f3e57acSmx205022 	/*
5776f3e57acSmx205022 	 * Reinitialise control variables ...
5786f3e57acSmx205022 	 */
5796f3e57acSmx205022 
5806f3e57acSmx205022 	srp->tx_hwmark = NGE_DESC_MIN;
5816f3e57acSmx205022 	srp->tx_lwmark = NGE_DESC_MIN;
5826f3e57acSmx205022 
5836f3e57acSmx205022 	srp->tx_next = 0;
5846f3e57acSmx205022 	srp->tx_free = srp->desc.nslots;
5856f3e57acSmx205022 	srp->tc_next = 0;
5866f3e57acSmx205022 
5876f3e57acSmx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5886f3e57acSmx205022 
5896f3e57acSmx205022 	for (slot = 0; slot - dmah_num != 0; ++slot)
5906f3e57acSmx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5916f3e57acSmx205022 
5926f3e57acSmx205022 	srp->dmah_free.head = srp->dmahndl;
5936f3e57acSmx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5946f3e57acSmx205022 	srp->dmah_free.tail->next = NULL;
5956f3e57acSmx205022 
5966f3e57acSmx205022 	/*
5976f3e57acSmx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
5986f3e57acSmx205022 	 */
5996f3e57acSmx205022 	for (slot = 0; slot < srp->desc.nslots; ++slot) {
6006f3e57acSmx205022 		ssbdp = &srp->sw_sbds[slot];
6016f3e57acSmx205022 		ssbdp->flags = HOST_OWN;
6026f3e57acSmx205022 	}
6036f3e57acSmx205022 
6046f3e57acSmx205022 	DMA_ZERO(srp->desc);
6056f3e57acSmx205022 	DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
6066f3e57acSmx205022 }
6076f3e57acSmx205022 
6086f3e57acSmx205022 /*
6096f3e57acSmx205022  * Initialize the slot number of rx's ring
6106f3e57acSmx205022  */
6116f3e57acSmx205022 static void
6126f3e57acSmx205022 nge_init_recv_ring(nge_t *ngep)
6136f3e57acSmx205022 {
6146f3e57acSmx205022 	recv_ring_t *rrp;
6156f3e57acSmx205022 
6166f3e57acSmx205022 	rrp = ngep->recv;
6176f3e57acSmx205022 	rrp->desc.nslots = ngep->rx_desc;
6186f3e57acSmx205022 	rrp->ngep = ngep;
6196f3e57acSmx205022 }
6206f3e57acSmx205022 
6216f3e57acSmx205022 /*
6226f3e57acSmx205022  * Intialize the rx recycle pointer and rx sending pointer of rx ring
6236f3e57acSmx205022  */
6246f3e57acSmx205022 static void
6256f3e57acSmx205022 nge_reinit_recv_ring(nge_t *ngep)
6266f3e57acSmx205022 {
6276f3e57acSmx205022 	recv_ring_t *rrp;
6286f3e57acSmx205022 
6296f3e57acSmx205022 	rrp = ngep->recv;
6306f3e57acSmx205022 
6316f3e57acSmx205022 	/*
6326f3e57acSmx205022 	 * Reinitialise control variables ...
6336f3e57acSmx205022 	 */
6346f3e57acSmx205022 	rrp->prod_index = 0;
6356f3e57acSmx205022 	/*
6366f3e57acSmx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
6376f3e57acSmx205022 	 */
6386f3e57acSmx205022 	DMA_ZERO(rrp->desc);
6396f3e57acSmx205022 	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
6406f3e57acSmx205022 }
6416f3e57acSmx205022 
6426f3e57acSmx205022 /*
6436f3e57acSmx205022  * Clean up initialisation done above before the memory is freed
6446f3e57acSmx205022  */
6456f3e57acSmx205022 static void
6466f3e57acSmx205022 nge_fini_buff_ring(nge_t *ngep)
6476f3e57acSmx205022 {
6486f3e57acSmx205022 	uint32_t i;
6496f3e57acSmx205022 	buff_ring_t *brp;
6506f3e57acSmx205022 	dma_area_t *bufp;
6516f3e57acSmx205022 	sw_rx_sbd_t *bsbdp;
6526f3e57acSmx205022 
6536f3e57acSmx205022 	brp = ngep->buff;
6546f3e57acSmx205022 	bsbdp = brp->sw_rbds;
6556f3e57acSmx205022 
6566f3e57acSmx205022 	NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
6576f3e57acSmx205022 
6586f3e57acSmx205022 	mutex_enter(brp->recycle_lock);
6596f3e57acSmx205022 	brp->buf_sign++;
6606f3e57acSmx205022 	mutex_exit(brp->recycle_lock);
6616f3e57acSmx205022 	for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
6626f3e57acSmx205022 		if (bsbdp->bufp) {
6636f3e57acSmx205022 			if (bsbdp->bufp->mp)
6646f3e57acSmx205022 				freemsg(bsbdp->bufp->mp);
6656f3e57acSmx205022 			nge_free_dma_mem(bsbdp->bufp);
6666f3e57acSmx205022 			kmem_free(bsbdp->bufp, sizeof (dma_area_t));
6676f3e57acSmx205022 			bsbdp->bufp = NULL;
6686f3e57acSmx205022 		}
6696f3e57acSmx205022 	}
6706f3e57acSmx205022 	while (brp->free_list != NULL) {
6716f3e57acSmx205022 		bufp = brp->free_list;
6726f3e57acSmx205022 		brp->free_list = bufp->next;
6736f3e57acSmx205022 		bufp->next = NULL;
6746f3e57acSmx205022 		if (bufp->mp)
6756f3e57acSmx205022 			freemsg(bufp->mp);
6766f3e57acSmx205022 		nge_free_dma_mem(bufp);
6776f3e57acSmx205022 		kmem_free(bufp, sizeof (dma_area_t));
6786f3e57acSmx205022 	}
6796f3e57acSmx205022 	while (brp->recycle_list != NULL) {
6806f3e57acSmx205022 		bufp = brp->recycle_list;
6816f3e57acSmx205022 		brp->recycle_list = bufp->next;
6826f3e57acSmx205022 		bufp->next = NULL;
6836f3e57acSmx205022 		if (bufp->mp)
6846f3e57acSmx205022 			freemsg(bufp->mp);
6856f3e57acSmx205022 		nge_free_dma_mem(bufp);
6866f3e57acSmx205022 		kmem_free(bufp, sizeof (dma_area_t));
6876f3e57acSmx205022 	}
6886f3e57acSmx205022 
6896f3e57acSmx205022 
6906f3e57acSmx205022 	kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
6916f3e57acSmx205022 	brp->sw_rbds = NULL;
6926f3e57acSmx205022 }
6936f3e57acSmx205022 
6946f3e57acSmx205022 /*
6956f3e57acSmx205022  * Intialize the Rx's data ring and free ring
6966f3e57acSmx205022  */
6976f3e57acSmx205022 static int
6986f3e57acSmx205022 nge_init_buff_ring(nge_t *ngep)
6996f3e57acSmx205022 {
7006f3e57acSmx205022 	uint32_t err;
7016f3e57acSmx205022 	uint32_t slot;
7026f3e57acSmx205022 	uint32_t nslots_buff;
7036f3e57acSmx205022 	uint32_t nslots_recv;
7046f3e57acSmx205022 	buff_ring_t *brp;
7056f3e57acSmx205022 	recv_ring_t *rrp;
7066f3e57acSmx205022 	dma_area_t desc;
7076f3e57acSmx205022 	dma_area_t *bufp;
7086f3e57acSmx205022 	sw_rx_sbd_t *bsbdp;
7096f3e57acSmx205022 
7106f3e57acSmx205022 	rrp = ngep->recv;
7116f3e57acSmx205022 	brp = ngep->buff;
7126f3e57acSmx205022 	brp->nslots = ngep->rx_buf;
7136f3e57acSmx205022 	brp->rx_bcopy = B_FALSE;
7146f3e57acSmx205022 	nslots_recv = rrp->desc.nslots;
7156f3e57acSmx205022 	nslots_buff = brp->nslots;
7166f3e57acSmx205022 	brp->ngep = ngep;
7176f3e57acSmx205022 
7186f3e57acSmx205022 	NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
7196f3e57acSmx205022 
7206f3e57acSmx205022 	/*
7216f3e57acSmx205022 	 * Allocate the array of s/w Recv Buffer Descriptors
7226f3e57acSmx205022 	 */
7236f3e57acSmx205022 	bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
7246f3e57acSmx205022 	brp->sw_rbds = bsbdp;
7256f3e57acSmx205022 	brp->free_list = NULL;
7266f3e57acSmx205022 	brp->recycle_list = NULL;
7276f3e57acSmx205022 	for (slot = 0; slot < nslots_buff; ++slot) {
7286f3e57acSmx205022 		bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
7296f3e57acSmx205022 		err = nge_alloc_dma_mem(ngep, (ngep->buf_size
7306f3e57acSmx205022 		    + NGE_HEADROOM),
7316f3e57acSmx205022 		    &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
7326f3e57acSmx205022 		if (err != DDI_SUCCESS) {
7336f3e57acSmx205022 			kmem_free(bufp, sizeof (dma_area_t));
7346f3e57acSmx205022 			return (DDI_FAILURE);
7356f3e57acSmx205022 		}
7366f3e57acSmx205022 
7376f3e57acSmx205022 		bufp->alength -= NGE_HEADROOM;
7386f3e57acSmx205022 		bufp->offset += NGE_HEADROOM;
7396f3e57acSmx205022 		bufp->private = (caddr_t)ngep;
7406f3e57acSmx205022 		bufp->rx_recycle.free_func = nge_recv_recycle;
7416f3e57acSmx205022 		bufp->rx_recycle.free_arg = (caddr_t)bufp;
7426f3e57acSmx205022 		bufp->signature = brp->buf_sign;
7436f3e57acSmx205022 		bufp->rx_delivered = B_FALSE;
7446f3e57acSmx205022 		bufp->mp = desballoc(DMA_VPTR(*bufp),
7456f3e57acSmx205022 		    ngep->buf_size + NGE_HEADROOM,
7466f3e57acSmx205022 		    0, &bufp->rx_recycle);
7476f3e57acSmx205022 
7486f3e57acSmx205022 		if (bufp->mp == NULL) {
7496f3e57acSmx205022 			return (DDI_FAILURE);
7506f3e57acSmx205022 		}
7516f3e57acSmx205022 		bufp->next = brp->free_list;
7526f3e57acSmx205022 		brp->free_list = bufp;
7536f3e57acSmx205022 	}
7546f3e57acSmx205022 
7556f3e57acSmx205022 	/*
7566f3e57acSmx205022 	 * Now initialise each array element once and for all
7576f3e57acSmx205022 	 */
7586f3e57acSmx205022 	desc = rrp->desc;
7596f3e57acSmx205022 	for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
7606f3e57acSmx205022 		nge_slice_chunk(&bsbdp->desc, &desc, 1,
7616f3e57acSmx205022 		    ngep->desc_attr.rxd_size);
7626f3e57acSmx205022 		bufp = brp->free_list;
7636f3e57acSmx205022 		brp->free_list = bufp->next;
7646f3e57acSmx205022 		bsbdp->bufp = bufp;
7656f3e57acSmx205022 		bsbdp->flags = CONTROLER_OWN;
7666f3e57acSmx205022 		bufp->next = NULL;
7676f3e57acSmx205022 	}
7686f3e57acSmx205022 
7696f3e57acSmx205022 	ASSERT(desc.alength == 0);
7706f3e57acSmx205022 	return (DDI_SUCCESS);
7716f3e57acSmx205022 }
7726f3e57acSmx205022 
7736f3e57acSmx205022 /*
7746f3e57acSmx205022  * Fill the host address of data in rx' descriptor
7756f3e57acSmx205022  * and initialize free pointers of rx free ring
7766f3e57acSmx205022  */
7776f3e57acSmx205022 static int
7786f3e57acSmx205022 nge_reinit_buff_ring(nge_t *ngep)
7796f3e57acSmx205022 {
7806f3e57acSmx205022 	uint32_t slot;
7816f3e57acSmx205022 	uint32_t nslots_recv;
7826f3e57acSmx205022 	buff_ring_t *brp;
7836f3e57acSmx205022 	recv_ring_t *rrp;
7846f3e57acSmx205022 	sw_rx_sbd_t *bsbdp;
7856f3e57acSmx205022 	void *hw_bd_p;
7866f3e57acSmx205022 
7876f3e57acSmx205022 	brp = ngep->buff;
7886f3e57acSmx205022 	rrp = ngep->recv;
7896f3e57acSmx205022 	bsbdp = brp->sw_rbds;
7906f3e57acSmx205022 	nslots_recv = rrp->desc.nslots;
7916f3e57acSmx205022 	for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
7926f3e57acSmx205022 		hw_bd_p = DMA_VPTR(bsbdp->desc);
7936f3e57acSmx205022 	/*
7946f3e57acSmx205022 	 * There is a scenario: When the traffic of small tcp
7956f3e57acSmx205022 	 * packet is heavy, suspending the tcp traffic will
7966f3e57acSmx205022 	 * cause the preallocated buffers for rx not to be
7976f3e57acSmx205022 	 * released in time by tcp taffic and cause rx's buffer
7986f3e57acSmx205022 	 * pointers not to be refilled in time.
7996f3e57acSmx205022 	 *
8006f3e57acSmx205022 	 * At this point, if we reinitialize the driver, the bufp
8016f3e57acSmx205022 	 * pointer for rx's traffic will be NULL.
8026f3e57acSmx205022 	 * So the result of the reinitializion fails.
8036f3e57acSmx205022 	 */
8046f3e57acSmx205022 		if (bsbdp->bufp == NULL)
8056f3e57acSmx205022 			return (DDI_FAILURE);
8066f3e57acSmx205022 
8076f3e57acSmx205022 		ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
8086f3e57acSmx205022 		    bsbdp->bufp->alength);
8096f3e57acSmx205022 	}
8106f3e57acSmx205022 	return (DDI_SUCCESS);
8116f3e57acSmx205022 }
8126f3e57acSmx205022 
8136f3e57acSmx205022 static void
8146f3e57acSmx205022 nge_init_ring_param_lock(nge_t *ngep)
8156f3e57acSmx205022 {
8166f3e57acSmx205022 	buff_ring_t *brp;
8176f3e57acSmx205022 	send_ring_t *srp;
8186f3e57acSmx205022 
8196f3e57acSmx205022 	srp = ngep->send;
8206f3e57acSmx205022 	brp = ngep->buff;
8216f3e57acSmx205022 
8226f3e57acSmx205022 	/* Init the locks for send ring */
8236f3e57acSmx205022 	mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
8246f3e57acSmx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8256f3e57acSmx205022 	mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
8266f3e57acSmx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8276f3e57acSmx205022 	mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
8286f3e57acSmx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8296f3e57acSmx205022 
8306f3e57acSmx205022 	/* Init parameters of buffer ring */
8316f3e57acSmx205022 	brp->free_list = NULL;
8326f3e57acSmx205022 	brp->recycle_list = NULL;
8336f3e57acSmx205022 	brp->rx_hold = 0;
8346f3e57acSmx205022 	brp->buf_sign = 0;
8356f3e57acSmx205022 
8366f3e57acSmx205022 	/* Init recycle list lock */
8376f3e57acSmx205022 	mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
8386f3e57acSmx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8396f3e57acSmx205022 }
8406f3e57acSmx205022 
8416f3e57acSmx205022 int
8426f3e57acSmx205022 nge_init_rings(nge_t *ngep)
8436f3e57acSmx205022 {
8446f3e57acSmx205022 	uint32_t err;
8456f3e57acSmx205022 
8466f3e57acSmx205022 	err = nge_init_send_ring(ngep);
8476f3e57acSmx205022 	if (err != DDI_SUCCESS) {
8486f3e57acSmx205022 		return (err);
8496f3e57acSmx205022 	}
8506f3e57acSmx205022 	nge_init_recv_ring(ngep);
8516f3e57acSmx205022 
8526f3e57acSmx205022 	err = nge_init_buff_ring(ngep);
8536f3e57acSmx205022 	if (err != DDI_SUCCESS) {
8546f3e57acSmx205022 		nge_fini_send_ring(ngep);
8556f3e57acSmx205022 		return (DDI_FAILURE);
8566f3e57acSmx205022 	}
8576f3e57acSmx205022 
8586f3e57acSmx205022 	return (err);
8596f3e57acSmx205022 }
8606f3e57acSmx205022 
8616f3e57acSmx205022 static int
8626f3e57acSmx205022 nge_reinit_ring(nge_t *ngep)
8636f3e57acSmx205022 {
8646f3e57acSmx205022 	int err;
8656f3e57acSmx205022 
8666f3e57acSmx205022 	nge_reinit_recv_ring(ngep);
8676f3e57acSmx205022 	nge_reinit_send_ring(ngep);
8686f3e57acSmx205022 	err = nge_reinit_buff_ring(ngep);
8696f3e57acSmx205022 	return (err);
8706f3e57acSmx205022 }
8716f3e57acSmx205022 
8726f3e57acSmx205022 
8736f3e57acSmx205022 void
8746f3e57acSmx205022 nge_fini_rings(nge_t *ngep)
8756f3e57acSmx205022 {
8766f3e57acSmx205022 	/*
8776f3e57acSmx205022 	 * For receive ring, nothing need to be finished.
8786f3e57acSmx205022 	 * So only finish buffer ring and send ring here.
8796f3e57acSmx205022 	 */
8806f3e57acSmx205022 	nge_fini_buff_ring(ngep);
8816f3e57acSmx205022 	nge_fini_send_ring(ngep);
8826f3e57acSmx205022 }
8836f3e57acSmx205022 
8846f3e57acSmx205022 /*
8856f3e57acSmx205022  * Loopback ioctl code
8866f3e57acSmx205022  */
8876f3e57acSmx205022 
8886f3e57acSmx205022 static lb_property_t loopmodes[] = {
8896f3e57acSmx205022 	{ normal,	"normal",	NGE_LOOP_NONE		},
8906f3e57acSmx205022 	{ external,	"100Mbps",	NGE_LOOP_EXTERNAL_100	},
8916f3e57acSmx205022 	{ external,	"10Mbps",	NGE_LOOP_EXTERNAL_10	},
8926f3e57acSmx205022 	{ internal,	"PHY",		NGE_LOOP_INTERNAL_PHY	},
8936f3e57acSmx205022 };
8946f3e57acSmx205022 
8956f3e57acSmx205022 enum ioc_reply
8966f3e57acSmx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
8976f3e57acSmx205022 {
8986f3e57acSmx205022 	int cmd;
8996f3e57acSmx205022 	uint32_t *lbmp;
9006f3e57acSmx205022 	lb_info_sz_t *lbsp;
9016f3e57acSmx205022 	lb_property_t *lbpp;
9026f3e57acSmx205022 
9036f3e57acSmx205022 	/*
9046f3e57acSmx205022 	 * Validate format of ioctl
9056f3e57acSmx205022 	 */
9066f3e57acSmx205022 	if (mp->b_cont == NULL)
9076f3e57acSmx205022 		return (IOC_INVAL);
9086f3e57acSmx205022 
9096f3e57acSmx205022 	cmd = iocp->ioc_cmd;
9106f3e57acSmx205022 
9116f3e57acSmx205022 	switch (cmd) {
9126f3e57acSmx205022 	default:
9136f3e57acSmx205022 		return (IOC_INVAL);
9146f3e57acSmx205022 
9156f3e57acSmx205022 	case LB_GET_INFO_SIZE:
9166f3e57acSmx205022 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
9176f3e57acSmx205022 			return (IOC_INVAL);
9186f3e57acSmx205022 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
9196f3e57acSmx205022 		*lbsp = sizeof (loopmodes);
9206f3e57acSmx205022 		return (IOC_REPLY);
9216f3e57acSmx205022 
9226f3e57acSmx205022 	case LB_GET_INFO:
9236f3e57acSmx205022 		if (iocp->ioc_count != sizeof (loopmodes))
9246f3e57acSmx205022 			return (IOC_INVAL);
9256f3e57acSmx205022 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
9266f3e57acSmx205022 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
9276f3e57acSmx205022 		return (IOC_REPLY);
9286f3e57acSmx205022 
9296f3e57acSmx205022 	case LB_GET_MODE:
9306f3e57acSmx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9316f3e57acSmx205022 			return (IOC_INVAL);
9326f3e57acSmx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9336f3e57acSmx205022 		*lbmp = ngep->param_loop_mode;
9346f3e57acSmx205022 		return (IOC_REPLY);
9356f3e57acSmx205022 
9366f3e57acSmx205022 	case LB_SET_MODE:
9376f3e57acSmx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9386f3e57acSmx205022 			return (IOC_INVAL);
9396f3e57acSmx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9406f3e57acSmx205022 		return (nge_set_loop_mode(ngep, *lbmp));
9416f3e57acSmx205022 	}
9426f3e57acSmx205022 }
9436f3e57acSmx205022 
9446f3e57acSmx205022 #undef	NGE_DBG
9456f3e57acSmx205022 #define	NGE_DBG	NGE_DBG_NEMO
9466f3e57acSmx205022 
9476f3e57acSmx205022 
9486f3e57acSmx205022 static void
9496f3e57acSmx205022 nge_check_desc_prop(nge_t *ngep)
9506f3e57acSmx205022 {
9516f3e57acSmx205022 	if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
9526f3e57acSmx205022 		ngep->desc_mode = DESC_HOT;
9536f3e57acSmx205022 
9546f3e57acSmx205022 	if (ngep->desc_mode == DESC_OFFLOAD)	{
9556f3e57acSmx205022 
9566f3e57acSmx205022 		ngep->desc_attr = nge_sum_desc;
9576f3e57acSmx205022 
9586f3e57acSmx205022 	}	else if (ngep->desc_mode == DESC_HOT)	{
9596f3e57acSmx205022 
9606f3e57acSmx205022 		ngep->desc_attr = nge_hot_desc;
9616f3e57acSmx205022 	}
9626f3e57acSmx205022 }
9636f3e57acSmx205022 
9646f3e57acSmx205022 /*
9656f3e57acSmx205022  * nge_get_props -- get the parameters to tune the driver
9666f3e57acSmx205022  */
9676f3e57acSmx205022 static void
9686f3e57acSmx205022 nge_get_props(nge_t *ngep)
9696f3e57acSmx205022 {
9706f3e57acSmx205022 	chip_info_t *infop;
9716f3e57acSmx205022 	dev_info_t *devinfo;
9726f3e57acSmx205022 	nge_dev_spec_param_t *dev_param_p;
9736f3e57acSmx205022 
9746f3e57acSmx205022 	devinfo = ngep->devinfo;
9756f3e57acSmx205022 	infop = (chip_info_t *)&ngep->chipinfo;
9766f3e57acSmx205022 	dev_param_p = &ngep->dev_spec_param;
9776f3e57acSmx205022 
9786f3e57acSmx205022 	infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9796f3e57acSmx205022 	    DDI_PROP_DONTPASS, clsize_propname, 32);
9806f3e57acSmx205022 
9816f3e57acSmx205022 	infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9826f3e57acSmx205022 	    DDI_PROP_DONTPASS, latency_propname, 64);
98302d51d0dSjj146644 	ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
98402d51d0dSjj146644 	    DDI_PROP_DONTPASS, intr_moderation, NGE_SET);
9856f3e57acSmx205022 	ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9866f3e57acSmx205022 	    DDI_PROP_DONTPASS, rx_data_hw, 0x20);
9876f3e57acSmx205022 	ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9886f3e57acSmx205022 	    DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
9896f3e57acSmx205022 	ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9906f3e57acSmx205022 	    DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
9916f3e57acSmx205022 
9926f3e57acSmx205022 	ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9936f3e57acSmx205022 	    DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
9946f3e57acSmx205022 	ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9956f3e57acSmx205022 	    DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
9966f3e57acSmx205022 	ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9976f3e57acSmx205022 	    DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
9986f3e57acSmx205022 	ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9996f3e57acSmx205022 	    DDI_PROP_DONTPASS, low_memory_mode, 0);
10006f3e57acSmx205022 
10016f3e57acSmx205022 	if (dev_param_p->jumbo) {
10026f3e57acSmx205022 		ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10036f3e57acSmx205022 		    DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
10046f3e57acSmx205022 	} else
10056f3e57acSmx205022 		ngep->default_mtu = ETHERMTU;
100686d6718fSLi-Zhen You 	if (dev_param_p->tx_pause_frame)
100786d6718fSLi-Zhen You 			ngep->param_link_tx_pause = B_TRUE;
100886d6718fSLi-Zhen You 	else
100986d6718fSLi-Zhen You 			ngep->param_link_tx_pause = B_FALSE;
101086d6718fSLi-Zhen You 
101186d6718fSLi-Zhen You 	if (dev_param_p->rx_pause_frame)
101286d6718fSLi-Zhen You 			ngep->param_link_rx_pause = B_TRUE;
101386d6718fSLi-Zhen You 	else
101486d6718fSLi-Zhen You 			ngep->param_link_rx_pause = B_FALSE;
10156f3e57acSmx205022 
10166f3e57acSmx205022 	if (ngep->default_mtu > ETHERMTU &&
10176f3e57acSmx205022 	    ngep->default_mtu <= NGE_MTU_2500) {
10186f3e57acSmx205022 		ngep->buf_size = NGE_JB2500_BUFSZ;
10196f3e57acSmx205022 		ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
10206f3e57acSmx205022 		ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
10216f3e57acSmx205022 		ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
10226f3e57acSmx205022 		ngep->nge_split = NGE_SPLIT_256;
10236f3e57acSmx205022 	} else if (ngep->default_mtu > NGE_MTU_2500 &&
10246f3e57acSmx205022 	    ngep->default_mtu <= NGE_MTU_4500) {
10256f3e57acSmx205022 		ngep->buf_size = NGE_JB4500_BUFSZ;
10266f3e57acSmx205022 		ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
10276f3e57acSmx205022 		ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
10286f3e57acSmx205022 		ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
10296f3e57acSmx205022 		ngep->nge_split = NGE_SPLIT_256;
10306f3e57acSmx205022 	} else if (ngep->default_mtu > NGE_MTU_4500 &&
10316f3e57acSmx205022 	    ngep->default_mtu <= NGE_MAX_MTU) {
10326f3e57acSmx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10336f3e57acSmx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10346f3e57acSmx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10356f3e57acSmx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10366f3e57acSmx205022 		ngep->nge_split = NGE_SPLIT_256;
10376f3e57acSmx205022 	} else if (ngep->default_mtu > NGE_MAX_MTU) {
10386f3e57acSmx205022 		ngep->default_mtu = NGE_MAX_MTU;
10396f3e57acSmx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10406f3e57acSmx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10416f3e57acSmx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10426f3e57acSmx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10436f3e57acSmx205022 		ngep->nge_split = NGE_SPLIT_256;
10446f3e57acSmx205022 	} else if (ngep->lowmem_mode != 0) {
10456f3e57acSmx205022 		ngep->default_mtu = ETHERMTU;
10466f3e57acSmx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10476f3e57acSmx205022 		ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
10486f3e57acSmx205022 		ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
10496f3e57acSmx205022 		ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
10506f3e57acSmx205022 		ngep->nge_split = NGE_SPLIT_32;
10516f3e57acSmx205022 	} else {
10526f3e57acSmx205022 		ngep->default_mtu = ETHERMTU;
10536f3e57acSmx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10546f3e57acSmx205022 		ngep->tx_desc = dev_param_p->tx_desc_num;
10556f3e57acSmx205022 		ngep->rx_desc = dev_param_p->rx_desc_num;
10566f3e57acSmx205022 		ngep->rx_buf = dev_param_p->rx_desc_num * 2;
10576f3e57acSmx205022 		ngep->nge_split = dev_param_p->nge_split;
10586f3e57acSmx205022 	}
10596f3e57acSmx205022 
10606f3e57acSmx205022 	nge_check_desc_prop(ngep);
10616f3e57acSmx205022 }
10626f3e57acSmx205022 
10636f3e57acSmx205022 
10646f3e57acSmx205022 static int
106519397407SSherry Moore nge_reset_dev(nge_t *ngep)
10666f3e57acSmx205022 {
10676f3e57acSmx205022 	int err;
10682d58516dSmx205022 	nge_mul_addr1 maddr1;
10692d58516dSmx205022 	nge_sw_statistics_t *sw_stp;
10702d58516dSmx205022 	sw_stp = &ngep->statistics.sw_statistics;
10716f3e57acSmx205022 	send_ring_t *srp = ngep->send;
10726f3e57acSmx205022 
10736f3e57acSmx205022 	ASSERT(mutex_owned(ngep->genlock));
10746f3e57acSmx205022 	mutex_enter(srp->tc_lock);
10756f3e57acSmx205022 	mutex_enter(srp->tx_lock);
10766f3e57acSmx205022 
10776f3e57acSmx205022 	nge_tx_recycle_all(ngep);
10786f3e57acSmx205022 	err = nge_reinit_ring(ngep);
10796f3e57acSmx205022 	if (err == DDI_FAILURE) {
10806f3e57acSmx205022 		mutex_exit(srp->tx_lock);
10816f3e57acSmx205022 		mutex_exit(srp->tc_lock);
10826f3e57acSmx205022 		return (err);
10836f3e57acSmx205022 	}
10846f3e57acSmx205022 	err = nge_chip_reset(ngep);
10852d58516dSmx205022 	/*
10862d58516dSmx205022 	 * Clear the Multicast mac address table
10872d58516dSmx205022 	 */
10882d58516dSmx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
10892d58516dSmx205022 	maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
10902d58516dSmx205022 	maddr1.addr_bits.addr = 0;
10912d58516dSmx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
10922d58516dSmx205022 
10936f3e57acSmx205022 	mutex_exit(srp->tx_lock);
10946f3e57acSmx205022 	mutex_exit(srp->tc_lock);
10956f3e57acSmx205022 	if (err == DDI_FAILURE)
10966f3e57acSmx205022 		return (err);
10976f3e57acSmx205022 	ngep->watchdog = 0;
10986f3e57acSmx205022 	ngep->resched_needed = B_FALSE;
10996f3e57acSmx205022 	ngep->promisc = B_FALSE;
11006f3e57acSmx205022 	ngep->param_loop_mode = NGE_LOOP_NONE;
11016f3e57acSmx205022 	ngep->factotum_flag = 0;
11026f3e57acSmx205022 	ngep->resched_needed = 0;
11036f3e57acSmx205022 	ngep->nge_mac_state = NGE_MAC_RESET;
11046f3e57acSmx205022 	ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
11056f3e57acSmx205022 	ngep->max_sdu += VTAG_SIZE;
11066f3e57acSmx205022 	ngep->rx_def = 0x16;
11072d58516dSmx205022 
11082d58516dSmx205022 	/* Clear the software statistics */
11092d58516dSmx205022 	sw_stp->recv_count = 0;
11102d58516dSmx205022 	sw_stp->xmit_count = 0;
11112d58516dSmx205022 	sw_stp->rbytes = 0;
11122d58516dSmx205022 	sw_stp->obytes = 0;
11132d58516dSmx205022 
11146f3e57acSmx205022 	return (DDI_SUCCESS);
11156f3e57acSmx205022 }
11166f3e57acSmx205022 
11176f3e57acSmx205022 static void
11186f3e57acSmx205022 nge_m_stop(void *arg)
11196f3e57acSmx205022 {
11206f3e57acSmx205022 	nge_t *ngep = arg;		/* private device info	*/
1121a01a4735SWinson Wang - Sun Microsystems - Beijing China 	int err;
11226f3e57acSmx205022 
11236f3e57acSmx205022 	NGE_TRACE(("nge_m_stop($%p)", arg));
11246f3e57acSmx205022 
11256f3e57acSmx205022 	/*
11266f3e57acSmx205022 	 * Just stop processing, then record new MAC state
11276f3e57acSmx205022 	 */
11286f3e57acSmx205022 	mutex_enter(ngep->genlock);
11292d58516dSmx205022 	/* If suspended, the adapter is already stopped, just return. */
11302d58516dSmx205022 	if (ngep->suspended) {
11312d58516dSmx205022 		ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
11322d58516dSmx205022 		mutex_exit(ngep->genlock);
11332d58516dSmx205022 		return;
11342d58516dSmx205022 	}
11356f3e57acSmx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11366f3e57acSmx205022 
1137a01a4735SWinson Wang - Sun Microsystems - Beijing China 	err = nge_chip_stop(ngep, B_FALSE);
1138a01a4735SWinson Wang - Sun Microsystems - Beijing China 	if (err == DDI_FAILURE)
1139a01a4735SWinson Wang - Sun Microsystems - Beijing China 		err = nge_chip_reset(ngep);
1140a01a4735SWinson Wang - Sun Microsystems - Beijing China 	if (err == DDI_FAILURE)
1141a01a4735SWinson Wang - Sun Microsystems - Beijing China 		nge_problem(ngep, "nge_m_stop: stop chip failed");
11426f3e57acSmx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
11436f3e57acSmx205022 
11446f3e57acSmx205022 	/* Recycle all the TX BD */
11456f3e57acSmx205022 	nge_tx_recycle_all(ngep);
11466f3e57acSmx205022 	nge_fini_rings(ngep);
11476f3e57acSmx205022 	nge_free_bufs(ngep);
11486f3e57acSmx205022 
11496f3e57acSmx205022 	NGE_DEBUG(("nge_m_stop($%p) done", arg));
11506f3e57acSmx205022 
11516f3e57acSmx205022 	rw_exit(ngep->rwlock);
11526f3e57acSmx205022 	mutex_exit(ngep->genlock);
11536f3e57acSmx205022 }
11546f3e57acSmx205022 
11556f3e57acSmx205022 static int
11566f3e57acSmx205022 nge_m_start(void *arg)
11576f3e57acSmx205022 {
11586f3e57acSmx205022 	int err;
11596f3e57acSmx205022 	nge_t *ngep = arg;
11606f3e57acSmx205022 
11616f3e57acSmx205022 	NGE_TRACE(("nge_m_start($%p)", arg));
11622d58516dSmx205022 
11636f3e57acSmx205022 	/*
11646f3e57acSmx205022 	 * Start processing and record new MAC state
11656f3e57acSmx205022 	 */
11666f3e57acSmx205022 	mutex_enter(ngep->genlock);
11672d58516dSmx205022 	/*
11682d58516dSmx205022 	 * If suspended, don't start, as the resume processing
11692d58516dSmx205022 	 * will recall this function with the suspended flag off.
11702d58516dSmx205022 	 */
11712d58516dSmx205022 	if (ngep->suspended) {
11722d58516dSmx205022 		mutex_exit(ngep->genlock);
117375675fb7Svb160487 		return (EIO);
11742d58516dSmx205022 	}
11756f3e57acSmx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11766f3e57acSmx205022 	err = nge_alloc_bufs(ngep);
11776f3e57acSmx205022 	if (err != DDI_SUCCESS) {
11786f3e57acSmx205022 		nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
11796f3e57acSmx205022 		goto finish;
11806f3e57acSmx205022 	}
11816f3e57acSmx205022 	err = nge_init_rings(ngep);
11826f3e57acSmx205022 	if (err != DDI_SUCCESS) {
11836f3e57acSmx205022 		nge_free_bufs(ngep);
118475675fb7Svb160487 		nge_problem(ngep, "nge_init_rings() failed,err=%x", err);
11856f3e57acSmx205022 		goto finish;
11866f3e57acSmx205022 	}
11876f3e57acSmx205022 	err = nge_restart(ngep);
11886f3e57acSmx205022 
11896f3e57acSmx205022 	NGE_DEBUG(("nge_m_start($%p) done", arg));
11906f3e57acSmx205022 finish:
11916f3e57acSmx205022 	rw_exit(ngep->rwlock);
11926f3e57acSmx205022 	mutex_exit(ngep->genlock);
11936f3e57acSmx205022 
119475675fb7Svb160487 	return (err == DDI_SUCCESS ? 0 : EIO);
11956f3e57acSmx205022 }
11966f3e57acSmx205022 
11976f3e57acSmx205022 static int
11986f3e57acSmx205022 nge_m_unicst(void *arg, const uint8_t *macaddr)
11996f3e57acSmx205022 {
12006f3e57acSmx205022 	nge_t *ngep = arg;
12016f3e57acSmx205022 
12026f3e57acSmx205022 	NGE_TRACE(("nge_m_unicst($%p)", arg));
12036f3e57acSmx205022 	/*
12046f3e57acSmx205022 	 * Remember the new current address in the driver state
12056f3e57acSmx205022 	 * Sync the chip's idea of the address too ...
12066f3e57acSmx205022 	 */
12076f3e57acSmx205022 	mutex_enter(ngep->genlock);
12086f3e57acSmx205022 
12096f3e57acSmx205022 	ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
12106f3e57acSmx205022 	ngep->cur_uni_addr.set = 1;
12116f3e57acSmx205022 
12126f3e57acSmx205022 	/*
12136f3e57acSmx205022 	 * If we are suspended, we want to quit now, and not update
12146f3e57acSmx205022 	 * the chip.  Doing so might put it in a bad state, but the
12156f3e57acSmx205022 	 * resume will get the unicast address installed.
12166f3e57acSmx205022 	 */
12172d58516dSmx205022 	if (ngep->suspended) {
12182d58516dSmx205022 		mutex_exit(ngep->genlock);
12196f3e57acSmx205022 		return (DDI_SUCCESS);
12202d58516dSmx205022 	}
12216f3e57acSmx205022 	nge_chip_sync(ngep);
12226f3e57acSmx205022 
12236f3e57acSmx205022 	NGE_DEBUG(("nge_m_unicst($%p) done", arg));
12246f3e57acSmx205022 	mutex_exit(ngep->genlock);
12256f3e57acSmx205022 
12266f3e57acSmx205022 	return (0);
12276f3e57acSmx205022 }
12286f3e57acSmx205022 
12296f3e57acSmx205022 static int
12306f3e57acSmx205022 nge_m_promisc(void *arg, boolean_t on)
12316f3e57acSmx205022 {
12326f3e57acSmx205022 	nge_t *ngep = arg;
12336f3e57acSmx205022 
12346f3e57acSmx205022 	NGE_TRACE(("nge_m_promisc($%p)", arg));
12356f3e57acSmx205022 
12366f3e57acSmx205022 	/*
12376f3e57acSmx205022 	 * Store specified mode and pass to chip layer to update h/w
12386f3e57acSmx205022 	 */
12396f3e57acSmx205022 	mutex_enter(ngep->genlock);
12402d58516dSmx205022 	/*
12412d58516dSmx205022 	 * If suspended, there is no need to do anything, even
12422d58516dSmx205022 	 * recording the promiscuious mode is not neccessary, as
12432d58516dSmx205022 	 * it won't be properly set on resume.  Just return failing.
12442d58516dSmx205022 	 */
12452d58516dSmx205022 	if (ngep->suspended) {
12462d58516dSmx205022 		mutex_exit(ngep->genlock);
12472d58516dSmx205022 		return (DDI_FAILURE);
12482d58516dSmx205022 	}
12496f3e57acSmx205022 	if (ngep->promisc == on) {
12506f3e57acSmx205022 		mutex_exit(ngep->genlock);
12516f3e57acSmx205022 		NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12526f3e57acSmx205022 		return (0);
12536f3e57acSmx205022 	}
12546f3e57acSmx205022 	ngep->promisc = on;
12556de4f663Smx205022 	ngep->record_promisc = ngep->promisc;
12566f3e57acSmx205022 	nge_chip_sync(ngep);
12576f3e57acSmx205022 	NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12586f3e57acSmx205022 	mutex_exit(ngep->genlock);
12596f3e57acSmx205022 
12606f3e57acSmx205022 	return (0);
12616f3e57acSmx205022 }
12626f3e57acSmx205022 
12636f3e57acSmx205022 static void nge_mulparam(nge_t *ngep)
12646f3e57acSmx205022 {
12656f3e57acSmx205022 	uint8_t number;
12666f3e57acSmx205022 	ether_addr_t pand;
12676f3e57acSmx205022 	ether_addr_t por;
12686f3e57acSmx205022 	mul_item *plist;
12696f3e57acSmx205022 
12706f3e57acSmx205022 	for (number = 0; number < ETHERADDRL; number++) {
12716f3e57acSmx205022 		pand[number] = 0x00;
12726f3e57acSmx205022 		por[number] = 0x00;
12736f3e57acSmx205022 	}
12746f3e57acSmx205022 	for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
12756f3e57acSmx205022 		for (number = 0; number < ETHERADDRL; number++) {
12766f3e57acSmx205022 			pand[number] &= plist->mul_addr[number];
12776f3e57acSmx205022 			por[number] |= plist->mul_addr[number];
12786f3e57acSmx205022 		}
12796f3e57acSmx205022 	}
12806f3e57acSmx205022 	for (number = 0; number < ETHERADDRL; number++) {
12816f3e57acSmx205022 		ngep->cur_mul_addr.addr[number]
12826f3e57acSmx205022 		    = pand[number] & por[number];
12836f3e57acSmx205022 		ngep->cur_mul_mask.addr[number]
12846f3e57acSmx205022 		    = pand [number] | (~por[number]);
12856f3e57acSmx205022 	}
12866f3e57acSmx205022 }
12876f3e57acSmx205022 static int
12886f3e57acSmx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
12896f3e57acSmx205022 {
12906f3e57acSmx205022 	boolean_t update;
12916f3e57acSmx205022 	boolean_t b_eq;
12926f3e57acSmx205022 	nge_t *ngep = arg;
12936f3e57acSmx205022 	mul_item *plist;
12946f3e57acSmx205022 	mul_item *plist_prev;
12956f3e57acSmx205022 	mul_item *pitem;
12966f3e57acSmx205022 
12976f3e57acSmx205022 	NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
12986f3e57acSmx205022 	    (add) ? "add" : "remove", ether_sprintf((void *)mca)));
12996f3e57acSmx205022 
13006f3e57acSmx205022 	update = B_FALSE;
13016f3e57acSmx205022 	plist = plist_prev = NULL;
13026f3e57acSmx205022 	mutex_enter(ngep->genlock);
13036f3e57acSmx205022 	if (add) {
13046f3e57acSmx205022 		if (ngep->pcur_mulist != NULL) {
13056f3e57acSmx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13066f3e57acSmx205022 			    plist = plist->next) {
13076f3e57acSmx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13086f3e57acSmx205022 				if (b_eq) {
13096f3e57acSmx205022 					plist->ref_cnt++;
13106f3e57acSmx205022 					break;
13116f3e57acSmx205022 				}
13126f3e57acSmx205022 				plist_prev = plist;
13136f3e57acSmx205022 			}
13146f3e57acSmx205022 		}
13156f3e57acSmx205022 
13166f3e57acSmx205022 		if (plist == NULL) {
13176f3e57acSmx205022 			pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
13186f3e57acSmx205022 			ether_copy(mca, pitem->mul_addr);
13196f3e57acSmx205022 			pitem ->ref_cnt++;
13206f3e57acSmx205022 			pitem ->next = NULL;
13216f3e57acSmx205022 			if (plist_prev == NULL)
13226f3e57acSmx205022 				ngep->pcur_mulist = pitem;
13236f3e57acSmx205022 			else
13246f3e57acSmx205022 				plist_prev->next = pitem;
13256f3e57acSmx205022 			update = B_TRUE;
13266f3e57acSmx205022 		}
13276f3e57acSmx205022 	} else {
13286f3e57acSmx205022 		if (ngep->pcur_mulist != NULL) {
13296f3e57acSmx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13306f3e57acSmx205022 			    plist = plist->next) {
13316f3e57acSmx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13326f3e57acSmx205022 				if (b_eq) {
13336f3e57acSmx205022 					update = B_TRUE;
13346f3e57acSmx205022 					break;
13356f3e57acSmx205022 				}
13366f3e57acSmx205022 				plist_prev = plist;
13376f3e57acSmx205022 			}
13386f3e57acSmx205022 
13396f3e57acSmx205022 			if (update) {
13406f3e57acSmx205022 				if ((plist_prev == NULL) &&
13416f3e57acSmx205022 				    (plist->next == NULL))
13426f3e57acSmx205022 					ngep->pcur_mulist = NULL;
13436f3e57acSmx205022 				else if ((plist_prev == NULL) &&
13446f3e57acSmx205022 				    (plist->next != NULL))
13456f3e57acSmx205022 					ngep->pcur_mulist = plist->next;
13466f3e57acSmx205022 				else
13476f3e57acSmx205022 					plist_prev->next = plist->next;
13486f3e57acSmx205022 				kmem_free(plist, sizeof (mul_item));
13496f3e57acSmx205022 			}
13506f3e57acSmx205022 		}
13516f3e57acSmx205022 	}
13526f3e57acSmx205022 
13532d58516dSmx205022 	if (update && !ngep->suspended) {
13546f3e57acSmx205022 		nge_mulparam(ngep);
13556f3e57acSmx205022 		nge_chip_sync(ngep);
13566f3e57acSmx205022 	}
13576f3e57acSmx205022 	NGE_DEBUG(("nge_m_multicst($%p) done", arg));
13586f3e57acSmx205022 	mutex_exit(ngep->genlock);
13596f3e57acSmx205022 
13606f3e57acSmx205022 	return (0);
13616f3e57acSmx205022 }
13626f3e57acSmx205022 
13636f3e57acSmx205022 static void
13646f3e57acSmx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
13656f3e57acSmx205022 {
13666f3e57acSmx205022 	int err;
13676f3e57acSmx205022 	int cmd;
13686f3e57acSmx205022 	nge_t *ngep = arg;
13696f3e57acSmx205022 	struct iocblk *iocp;
13706f3e57acSmx205022 	enum ioc_reply status;
13716f3e57acSmx205022 	boolean_t need_privilege;
13726f3e57acSmx205022 
13736f3e57acSmx205022 	/*
13746f3e57acSmx205022 	 * If suspended, we might actually be able to do some of
13756f3e57acSmx205022 	 * these ioctls, but it is harder to make sure they occur
13766f3e57acSmx205022 	 * without actually putting the hardware in an undesireable
13776f3e57acSmx205022 	 * state.  So just NAK it.
13786f3e57acSmx205022 	 */
13792d58516dSmx205022 	mutex_enter(ngep->genlock);
13806f3e57acSmx205022 	if (ngep->suspended) {
13816f3e57acSmx205022 		miocnak(wq, mp, 0, EINVAL);
13822d58516dSmx205022 		mutex_exit(ngep->genlock);
13836f3e57acSmx205022 		return;
13846f3e57acSmx205022 	}
13852d58516dSmx205022 	mutex_exit(ngep->genlock);
13866f3e57acSmx205022 
13876f3e57acSmx205022 	/*
13886f3e57acSmx205022 	 * Validate the command before bothering with the mutex ...
13896f3e57acSmx205022 	 */
13906f3e57acSmx205022 	iocp = (struct iocblk *)mp->b_rptr;
13916f3e57acSmx205022 	iocp->ioc_error = 0;
13926f3e57acSmx205022 	need_privilege = B_TRUE;
13936f3e57acSmx205022 	cmd = iocp->ioc_cmd;
13946f3e57acSmx205022 
13956f3e57acSmx205022 	NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
13966f3e57acSmx205022 	switch (cmd) {
13976f3e57acSmx205022 	default:
13986f3e57acSmx205022 		NGE_LDB(NGE_DBG_BADIOC,
13996f3e57acSmx205022 		    ("nge_m_ioctl: unknown cmd 0x%x", cmd));
14006f3e57acSmx205022 
14016f3e57acSmx205022 		miocnak(wq, mp, 0, EINVAL);
14026f3e57acSmx205022 		return;
14036f3e57acSmx205022 
14046f3e57acSmx205022 	case NGE_MII_READ:
14056f3e57acSmx205022 	case NGE_MII_WRITE:
14066f3e57acSmx205022 	case NGE_SEE_READ:
14076f3e57acSmx205022 	case NGE_SEE_WRITE:
14086f3e57acSmx205022 	case NGE_DIAG:
14096f3e57acSmx205022 	case NGE_PEEK:
14106f3e57acSmx205022 	case NGE_POKE:
14116f3e57acSmx205022 	case NGE_PHY_RESET:
14126f3e57acSmx205022 	case NGE_SOFT_RESET:
14136f3e57acSmx205022 	case NGE_HARD_RESET:
14146f3e57acSmx205022 		break;
14156f3e57acSmx205022 
14166f3e57acSmx205022 	case LB_GET_INFO_SIZE:
14176f3e57acSmx205022 	case LB_GET_INFO:
14186f3e57acSmx205022 	case LB_GET_MODE:
14196f3e57acSmx205022 		need_privilege = B_FALSE;
14206f3e57acSmx205022 		break;
14216f3e57acSmx205022 	case LB_SET_MODE:
14226f3e57acSmx205022 		break;
14236f3e57acSmx205022 	}
14246f3e57acSmx205022 
14256f3e57acSmx205022 	if (need_privilege) {
14266f3e57acSmx205022 		/*
14276f3e57acSmx205022 		 * Check for specific net_config privilege.
14286f3e57acSmx205022 		 */
14296f3e57acSmx205022 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
14306f3e57acSmx205022 		if (err != 0) {
14316f3e57acSmx205022 			NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
14326f3e57acSmx205022 			    cmd, err));
14336f3e57acSmx205022 			miocnak(wq, mp, 0, err);
14346f3e57acSmx205022 			return;
14356f3e57acSmx205022 		}
14366f3e57acSmx205022 	}
14376f3e57acSmx205022 
14386f3e57acSmx205022 	mutex_enter(ngep->genlock);
14396f3e57acSmx205022 
14406f3e57acSmx205022 	switch (cmd) {
14416f3e57acSmx205022 	default:
14426f3e57acSmx205022 		_NOTE(NOTREACHED)
14436f3e57acSmx205022 		status = IOC_INVAL;
14446f3e57acSmx205022 	break;
14456f3e57acSmx205022 
14466f3e57acSmx205022 	case NGE_MII_READ:
14476f3e57acSmx205022 	case NGE_MII_WRITE:
14486f3e57acSmx205022 	case NGE_SEE_READ:
14496f3e57acSmx205022 	case NGE_SEE_WRITE:
14506f3e57acSmx205022 	case NGE_DIAG:
14516f3e57acSmx205022 	case NGE_PEEK:
14526f3e57acSmx205022 	case NGE_POKE:
14536f3e57acSmx205022 	case NGE_PHY_RESET:
14546f3e57acSmx205022 	case NGE_SOFT_RESET:
14556f3e57acSmx205022 	case NGE_HARD_RESET:
14566f3e57acSmx205022 		status = nge_chip_ioctl(ngep, mp, iocp);
14576f3e57acSmx205022 	break;
14586f3e57acSmx205022 
14596f3e57acSmx205022 	case LB_GET_INFO_SIZE:
14606f3e57acSmx205022 	case LB_GET_INFO:
14616f3e57acSmx205022 	case LB_GET_MODE:
14626f3e57acSmx205022 	case LB_SET_MODE:
14636f3e57acSmx205022 		status = nge_loop_ioctl(ngep, mp, iocp);
14646f3e57acSmx205022 	break;
14656f3e57acSmx205022 
14666f3e57acSmx205022 	}
14676f3e57acSmx205022 
14686f3e57acSmx205022 	/*
14696f3e57acSmx205022 	 * Do we need to reprogram the PHY and/or the MAC?
14706f3e57acSmx205022 	 * Do it now, while we still have the mutex.
14716f3e57acSmx205022 	 *
14726f3e57acSmx205022 	 * Note: update the PHY first, 'cos it controls the
14736f3e57acSmx205022 	 * speed/duplex parameters that the MAC code uses.
14746f3e57acSmx205022 	 */
14756f3e57acSmx205022 
14766f3e57acSmx205022 	NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
14776f3e57acSmx205022 
14786f3e57acSmx205022 	switch (status) {
14796f3e57acSmx205022 	case IOC_RESTART_REPLY:
14806f3e57acSmx205022 	case IOC_RESTART_ACK:
14816f3e57acSmx205022 		(*ngep->physops->phys_update)(ngep);
14826f3e57acSmx205022 		nge_chip_sync(ngep);
14836f3e57acSmx205022 		break;
14846f3e57acSmx205022 
14856f3e57acSmx205022 	default:
14866f3e57acSmx205022 	break;
14876f3e57acSmx205022 	}
14886f3e57acSmx205022 
14896f3e57acSmx205022 	mutex_exit(ngep->genlock);
14906f3e57acSmx205022 
14916f3e57acSmx205022 	/*
14926f3e57acSmx205022 	 * Finally, decide how to reply
14936f3e57acSmx205022 	 */
14946f3e57acSmx205022 	switch (status) {
14956f3e57acSmx205022 
14966f3e57acSmx205022 	default:
14976f3e57acSmx205022 	case IOC_INVAL:
14986f3e57acSmx205022 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
14996f3e57acSmx205022 		    EINVAL : iocp->ioc_error);
15006f3e57acSmx205022 		break;
15016f3e57acSmx205022 
15026f3e57acSmx205022 	case IOC_DONE:
15036f3e57acSmx205022 		break;
15046f3e57acSmx205022 
15056f3e57acSmx205022 	case IOC_RESTART_ACK:
15066f3e57acSmx205022 	case IOC_ACK:
15076f3e57acSmx205022 		miocack(wq, mp, 0, 0);
15086f3e57acSmx205022 		break;
15096f3e57acSmx205022 
15106f3e57acSmx205022 	case IOC_RESTART_REPLY:
15116f3e57acSmx205022 	case IOC_REPLY:
15126f3e57acSmx205022 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
15136f3e57acSmx205022 		    M_IOCACK : M_IOCNAK;
15146f3e57acSmx205022 		qreply(wq, mp);
15156f3e57acSmx205022 		break;
15166f3e57acSmx205022 	}
15176f3e57acSmx205022 }
15186f3e57acSmx205022 
15195a3d0718Smx205022 static boolean_t
15205a3d0718Smx205022 nge_param_locked(mac_prop_id_t pr_num)
15215a3d0718Smx205022 {
15225a3d0718Smx205022 	/*
15235a3d0718Smx205022 	 * All adv_* parameters are locked (read-only) while
15245a3d0718Smx205022 	 * the device is in any sort of loopback mode ...
15255a3d0718Smx205022 	 */
15265a3d0718Smx205022 	switch (pr_num) {
15273fd94f8cSam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15283fd94f8cSam223141 		case MAC_PROP_EN_1000FDX_CAP:
15293fd94f8cSam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15303fd94f8cSam223141 		case MAC_PROP_EN_1000HDX_CAP:
15313fd94f8cSam223141 		case MAC_PROP_ADV_100FDX_CAP:
15323fd94f8cSam223141 		case MAC_PROP_EN_100FDX_CAP:
15333fd94f8cSam223141 		case MAC_PROP_ADV_100HDX_CAP:
15343fd94f8cSam223141 		case MAC_PROP_EN_100HDX_CAP:
15353fd94f8cSam223141 		case MAC_PROP_ADV_10FDX_CAP:
15363fd94f8cSam223141 		case MAC_PROP_EN_10FDX_CAP:
15373fd94f8cSam223141 		case MAC_PROP_ADV_10HDX_CAP:
15383fd94f8cSam223141 		case MAC_PROP_EN_10HDX_CAP:
15393fd94f8cSam223141 		case MAC_PROP_AUTONEG:
15403fd94f8cSam223141 		case MAC_PROP_FLOWCTRL:
15415a3d0718Smx205022 			return (B_TRUE);
15425a3d0718Smx205022 	}
15435a3d0718Smx205022 	return (B_FALSE);
15445a3d0718Smx205022 }
15455a3d0718Smx205022 
15465a3d0718Smx205022 /*
15475a3d0718Smx205022  * callback functions for set/get of properties
15485a3d0718Smx205022  */
15495a3d0718Smx205022 static int
15505a3d0718Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
15515a3d0718Smx205022     uint_t pr_valsize, const void *pr_val)
15525a3d0718Smx205022 {
15535a3d0718Smx205022 	nge_t *ngep = barg;
15545a3d0718Smx205022 	int err = 0;
15554045d941Ssowmini 	uint32_t cur_mtu, new_mtu;
15565a3d0718Smx205022 	link_flowctrl_t fl;
15575a3d0718Smx205022 
15585a3d0718Smx205022 	mutex_enter(ngep->genlock);
15595a3d0718Smx205022 	if (ngep->param_loop_mode != NGE_LOOP_NONE &&
15605a3d0718Smx205022 	    nge_param_locked(pr_num)) {
15615a3d0718Smx205022 		/*
15625a3d0718Smx205022 		 * All adv_* parameters are locked (read-only)
15635a3d0718Smx205022 		 * while the device is in any sort of loopback mode.
15645a3d0718Smx205022 		 */
15655a3d0718Smx205022 		mutex_exit(ngep->genlock);
15665a3d0718Smx205022 		return (EBUSY);
15675a3d0718Smx205022 	}
15685a3d0718Smx205022 	switch (pr_num) {
15693fd94f8cSam223141 		case MAC_PROP_EN_1000FDX_CAP:
15705a3d0718Smx205022 			ngep->param_en_1000fdx = *(uint8_t *)pr_val;
15715a3d0718Smx205022 			ngep->param_adv_1000fdx = *(uint8_t *)pr_val;
15725a3d0718Smx205022 			goto reprogram;
15733fd94f8cSam223141 		case MAC_PROP_EN_100FDX_CAP:
15745a3d0718Smx205022 			ngep->param_en_100fdx = *(uint8_t *)pr_val;
15755a3d0718Smx205022 			ngep->param_adv_100fdx = *(uint8_t *)pr_val;
15765a3d0718Smx205022 			goto reprogram;
15773fd94f8cSam223141 		case MAC_PROP_EN_100HDX_CAP:
15785a3d0718Smx205022 			ngep->param_en_100hdx = *(uint8_t *)pr_val;
15795a3d0718Smx205022 			ngep->param_adv_100hdx = *(uint8_t *)pr_val;
15805a3d0718Smx205022 			goto reprogram;
15813fd94f8cSam223141 		case MAC_PROP_EN_10FDX_CAP:
15825a3d0718Smx205022 			ngep->param_en_10fdx = *(uint8_t *)pr_val;
15835a3d0718Smx205022 			ngep->param_adv_10fdx = *(uint8_t *)pr_val;
15845a3d0718Smx205022 			goto reprogram;
15853fd94f8cSam223141 		case MAC_PROP_EN_10HDX_CAP:
15865a3d0718Smx205022 			ngep->param_en_10hdx = *(uint8_t *)pr_val;
15875a3d0718Smx205022 			ngep->param_adv_10hdx = *(uint8_t *)pr_val;
15885a3d0718Smx205022 reprogram:
15895a3d0718Smx205022 		(*ngep->physops->phys_update)(ngep);
15905a3d0718Smx205022 		nge_chip_sync(ngep);
15915a3d0718Smx205022 		break;
15925a3d0718Smx205022 
15933fd94f8cSam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15943fd94f8cSam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15953fd94f8cSam223141 		case MAC_PROP_ADV_100FDX_CAP:
15963fd94f8cSam223141 		case MAC_PROP_ADV_100HDX_CAP:
15973fd94f8cSam223141 		case MAC_PROP_ADV_10FDX_CAP:
15983fd94f8cSam223141 		case MAC_PROP_ADV_10HDX_CAP:
15993fd94f8cSam223141 		case MAC_PROP_STATUS:
16003fd94f8cSam223141 		case MAC_PROP_SPEED:
16013fd94f8cSam223141 		case MAC_PROP_DUPLEX:
16023fd94f8cSam223141 		case MAC_PROP_EN_1000HDX_CAP:
16035a3d0718Smx205022 			err = ENOTSUP; /* read-only prop. Can't set this */
16045a3d0718Smx205022 			break;
16053fd94f8cSam223141 		case MAC_PROP_AUTONEG:
16065a3d0718Smx205022 			ngep->param_adv_autoneg = *(uint8_t *)pr_val;
16075a3d0718Smx205022 			(*ngep->physops->phys_update)(ngep);
16085a3d0718Smx205022 			nge_chip_sync(ngep);
16095a3d0718Smx205022 			break;
16103fd94f8cSam223141 		case MAC_PROP_MTU:
16115a3d0718Smx205022 			cur_mtu = ngep->default_mtu;
16125a3d0718Smx205022 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
16135a3d0718Smx205022 			if (new_mtu == cur_mtu) {
16145a3d0718Smx205022 				err = 0;
16155a3d0718Smx205022 				break;
16165a3d0718Smx205022 			}
16175a3d0718Smx205022 			if (new_mtu < ETHERMTU ||
16185a3d0718Smx205022 			    new_mtu > NGE_MAX_MTU) {
16195a3d0718Smx205022 				err = EINVAL;
16205a3d0718Smx205022 				break;
16215a3d0718Smx205022 			}
16225a3d0718Smx205022 			if ((new_mtu > ETHERMTU) &&
16235a3d0718Smx205022 			    (!ngep->dev_spec_param.jumbo)) {
16245a3d0718Smx205022 				err = EINVAL;
16255a3d0718Smx205022 				break;
16265a3d0718Smx205022 			}
16275a3d0718Smx205022 			if (ngep->nge_mac_state == NGE_MAC_STARTED) {
16285a3d0718Smx205022 				err = EBUSY;
16295a3d0718Smx205022 				break;
16305a3d0718Smx205022 			}
16315a3d0718Smx205022 
16325a3d0718Smx205022 			ngep->default_mtu = new_mtu;
16335a3d0718Smx205022 			if (ngep->default_mtu > ETHERMTU &&
16345a3d0718Smx205022 			    ngep->default_mtu <= NGE_MTU_2500) {
16355a3d0718Smx205022 				ngep->buf_size = NGE_JB2500_BUFSZ;
16365a3d0718Smx205022 				ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
16375a3d0718Smx205022 				ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
16385a3d0718Smx205022 				ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
16395a3d0718Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16405a3d0718Smx205022 			} else if (ngep->default_mtu > NGE_MTU_2500 &&
16415a3d0718Smx205022 			    ngep->default_mtu <= NGE_MTU_4500) {
16425a3d0718Smx205022 				ngep->buf_size = NGE_JB4500_BUFSZ;
16435a3d0718Smx205022 				ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
16445a3d0718Smx205022 				ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
16455a3d0718Smx205022 				ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
16465a3d0718Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16475a3d0718Smx205022 			} else if (ngep->default_mtu > NGE_MTU_4500 &&
16485a3d0718Smx205022 			    ngep->default_mtu <= NGE_MAX_MTU) {
16495a3d0718Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16505a3d0718Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16515a3d0718Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16525a3d0718Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16535a3d0718Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16545a3d0718Smx205022 			} else if (ngep->default_mtu > NGE_MAX_MTU) {
16555a3d0718Smx205022 				ngep->default_mtu = NGE_MAX_MTU;
16565a3d0718Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16575a3d0718Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16585a3d0718Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16595a3d0718Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16605a3d0718Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16615a3d0718Smx205022 			} else if (ngep->lowmem_mode != 0) {
16625a3d0718Smx205022 				ngep->default_mtu = ETHERMTU;
16635a3d0718Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16645a3d0718Smx205022 				ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
16655a3d0718Smx205022 				ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
16665a3d0718Smx205022 				ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
16675a3d0718Smx205022 				ngep->nge_split = NGE_SPLIT_32;
16685a3d0718Smx205022 			} else {
16695a3d0718Smx205022 				ngep->default_mtu = ETHERMTU;
16705a3d0718Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16715a3d0718Smx205022 				ngep->tx_desc =
16725a3d0718Smx205022 				    ngep->dev_spec_param.tx_desc_num;
16735a3d0718Smx205022 				ngep->rx_desc =
16745a3d0718Smx205022 				    ngep->dev_spec_param.rx_desc_num;
16755a3d0718Smx205022 				ngep->rx_buf =
16765a3d0718Smx205022 				    ngep->dev_spec_param.rx_desc_num * 2;
16775a3d0718Smx205022 				ngep->nge_split =
16785a3d0718Smx205022 				    ngep->dev_spec_param.nge_split;
16795a3d0718Smx205022 			}
16805a3d0718Smx205022 
16815a3d0718Smx205022 			err = mac_maxsdu_update(ngep->mh, ngep->default_mtu);
16825a3d0718Smx205022 
16835a3d0718Smx205022 			break;
16843fd94f8cSam223141 		case MAC_PROP_FLOWCTRL:
16855a3d0718Smx205022 			bcopy(pr_val, &fl, sizeof (fl));
16865a3d0718Smx205022 			switch (fl) {
16875a3d0718Smx205022 			default:
16885a3d0718Smx205022 				err = ENOTSUP;
16895a3d0718Smx205022 				break;
16905a3d0718Smx205022 			case LINK_FLOWCTRL_NONE:
16915a3d0718Smx205022 				ngep->param_adv_pause = 0;
16925a3d0718Smx205022 				ngep->param_adv_asym_pause = 0;
16935a3d0718Smx205022 
16945a3d0718Smx205022 				ngep->param_link_rx_pause = B_FALSE;
16955a3d0718Smx205022 				ngep->param_link_tx_pause = B_FALSE;
16965a3d0718Smx205022 				break;
16975a3d0718Smx205022 			case LINK_FLOWCTRL_RX:
16985a3d0718Smx205022 				if (!((ngep->param_lp_pause == 0) &&
16995a3d0718Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
17005a3d0718Smx205022 					err = EINVAL;
17015a3d0718Smx205022 					break;
17025a3d0718Smx205022 				}
17035a3d0718Smx205022 				ngep->param_adv_pause = 1;
17045a3d0718Smx205022 				ngep->param_adv_asym_pause = 1;
17055a3d0718Smx205022 
17065a3d0718Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17075a3d0718Smx205022 				ngep->param_link_tx_pause = B_FALSE;
17085a3d0718Smx205022 				break;
17095a3d0718Smx205022 			case LINK_FLOWCTRL_TX:
17105a3d0718Smx205022 				if (!((ngep->param_lp_pause == 1) &&
17115a3d0718Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
17125a3d0718Smx205022 					err = EINVAL;
17135a3d0718Smx205022 					break;
17145a3d0718Smx205022 				}
17155a3d0718Smx205022 				ngep->param_adv_pause = 0;
17165a3d0718Smx205022 				ngep->param_adv_asym_pause = 1;
17175a3d0718Smx205022 
17185a3d0718Smx205022 				ngep->param_link_rx_pause = B_FALSE;
17195a3d0718Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17205a3d0718Smx205022 				break;
17215a3d0718Smx205022 			case LINK_FLOWCTRL_BI:
17225a3d0718Smx205022 				if (ngep->param_lp_pause != 1) {
17235a3d0718Smx205022 					err = EINVAL;
17245a3d0718Smx205022 					break;
17255a3d0718Smx205022 				}
17265a3d0718Smx205022 				ngep->param_adv_pause = 1;
17275a3d0718Smx205022 
17285a3d0718Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17295a3d0718Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17305a3d0718Smx205022 				break;
17315a3d0718Smx205022 			}
17325a3d0718Smx205022 
17335a3d0718Smx205022 			if (err == 0) {
17345a3d0718Smx205022 				(*ngep->physops->phys_update)(ngep);
17355a3d0718Smx205022 				nge_chip_sync(ngep);
17365a3d0718Smx205022 			}
17375a3d0718Smx205022 
17385a3d0718Smx205022 			break;
17393fd94f8cSam223141 		case MAC_PROP_PRIVATE:
17405a3d0718Smx205022 			err = nge_set_priv_prop(ngep, pr_name, pr_valsize,
17415a3d0718Smx205022 			    pr_val);
17425a3d0718Smx205022 			if (err == 0) {
17435a3d0718Smx205022 				(*ngep->physops->phys_update)(ngep);
17445a3d0718Smx205022 				nge_chip_sync(ngep);
17455a3d0718Smx205022 			}
17465a3d0718Smx205022 			break;
17475a3d0718Smx205022 		default:
17485a3d0718Smx205022 			err = ENOTSUP;
17495a3d0718Smx205022 	}
17505a3d0718Smx205022 	mutex_exit(ngep->genlock);
17515a3d0718Smx205022 	return (err);
17525a3d0718Smx205022 }
17535a3d0718Smx205022 
17545a3d0718Smx205022 static int
17555a3d0718Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1756*0dc2366fSVenugopal Iyer     uint_t pr_valsize, void *pr_val)
17575a3d0718Smx205022 {
17585a3d0718Smx205022 	nge_t *ngep = barg;
17594045d941Ssowmini 	int err = 0;
17605a3d0718Smx205022 	link_flowctrl_t fl;
17614045d941Ssowmini 	uint64_t speed;
1762afdda45fSVasumathi Sundaram - Sun Microsystems 
17635a3d0718Smx205022 	switch (pr_num) {
17643fd94f8cSam223141 		case MAC_PROP_DUPLEX:
1765*0dc2366fSVenugopal Iyer 			ASSERT(pr_valsize >= sizeof (link_duplex_t));
17664045d941Ssowmini 			bcopy(&ngep->param_link_duplex, pr_val,
17674045d941Ssowmini 			    sizeof (link_duplex_t));
17685a3d0718Smx205022 			break;
17693fd94f8cSam223141 		case MAC_PROP_SPEED:
1770*0dc2366fSVenugopal Iyer 			ASSERT(pr_valsize >= sizeof (uint64_t));
17714045d941Ssowmini 			speed = ngep->param_link_speed * 1000000ull;
17724045d941Ssowmini 			bcopy(&speed, pr_val, sizeof (speed));
17735a3d0718Smx205022 			break;
17743fd94f8cSam223141 		case MAC_PROP_AUTONEG:
17755a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_adv_autoneg;
17765a3d0718Smx205022 			break;
17773fd94f8cSam223141 		case MAC_PROP_FLOWCTRL:
1778*0dc2366fSVenugopal Iyer 			ASSERT(pr_valsize >= sizeof (link_flowctrl_t));
17795a3d0718Smx205022 			if (ngep->param_link_rx_pause &&
17805a3d0718Smx205022 			    !ngep->param_link_tx_pause)
17815a3d0718Smx205022 				fl = LINK_FLOWCTRL_RX;
17825a3d0718Smx205022 
17835a3d0718Smx205022 			if (!ngep->param_link_rx_pause &&
17845a3d0718Smx205022 			    !ngep->param_link_tx_pause)
17855a3d0718Smx205022 				fl = LINK_FLOWCTRL_NONE;
17865a3d0718Smx205022 
17875a3d0718Smx205022 			if (!ngep->param_link_rx_pause &&
17885a3d0718Smx205022 			    ngep->param_link_tx_pause)
17895a3d0718Smx205022 				fl = LINK_FLOWCTRL_TX;
17905a3d0718Smx205022 
17915a3d0718Smx205022 			if (ngep->param_link_rx_pause &&
17925a3d0718Smx205022 			    ngep->param_link_tx_pause)
17935a3d0718Smx205022 				fl = LINK_FLOWCTRL_BI;
17945a3d0718Smx205022 			bcopy(&fl, pr_val, sizeof (fl));
17955a3d0718Smx205022 			break;
17963fd94f8cSam223141 		case MAC_PROP_ADV_1000FDX_CAP:
17975a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_adv_1000fdx;
17985a3d0718Smx205022 			break;
17993fd94f8cSam223141 		case MAC_PROP_EN_1000FDX_CAP:
18005a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_en_1000fdx;
18015a3d0718Smx205022 			break;
18023fd94f8cSam223141 		case MAC_PROP_ADV_1000HDX_CAP:
18035a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_adv_1000hdx;
18045a3d0718Smx205022 			break;
18053fd94f8cSam223141 		case MAC_PROP_EN_1000HDX_CAP:
18065a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_en_1000hdx;
18075a3d0718Smx205022 			break;
18083fd94f8cSam223141 		case MAC_PROP_ADV_100FDX_CAP:
18095a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_adv_100fdx;
18105a3d0718Smx205022 			break;
18113fd94f8cSam223141 		case MAC_PROP_EN_100FDX_CAP:
18125a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_en_100fdx;
18135a3d0718Smx205022 			break;
18143fd94f8cSam223141 		case MAC_PROP_ADV_100HDX_CAP:
18155a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_adv_100hdx;
18165a3d0718Smx205022 			break;
18173fd94f8cSam223141 		case MAC_PROP_EN_100HDX_CAP:
18185a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_en_100hdx;
18195a3d0718Smx205022 			break;
18203fd94f8cSam223141 		case MAC_PROP_ADV_10FDX_CAP:
18215a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_adv_10fdx;
18225a3d0718Smx205022 			break;
18233fd94f8cSam223141 		case MAC_PROP_EN_10FDX_CAP:
18245a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_en_10fdx;
18255a3d0718Smx205022 			break;
18263fd94f8cSam223141 		case MAC_PROP_ADV_10HDX_CAP:
18275a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_adv_10hdx;
18285a3d0718Smx205022 			break;
18293fd94f8cSam223141 		case MAC_PROP_EN_10HDX_CAP:
18305a3d0718Smx205022 			*(uint8_t *)pr_val = ngep->param_en_10hdx;
18315a3d0718Smx205022 			break;
18323fd94f8cSam223141 		case MAC_PROP_ADV_100T4_CAP:
18333fd94f8cSam223141 		case MAC_PROP_EN_100T4_CAP:
18344045d941Ssowmini 			*(uint8_t *)pr_val = 0;
18354045d941Ssowmini 			break;
18363fd94f8cSam223141 		case MAC_PROP_PRIVATE:
1837*0dc2366fSVenugopal Iyer 			err = nge_get_priv_prop(ngep, pr_name,
18384045d941Ssowmini 			    pr_valsize, pr_val);
18395a3d0718Smx205022 			break;
18405a3d0718Smx205022 		default:
18415a3d0718Smx205022 			err = ENOTSUP;
18425a3d0718Smx205022 	}
18435a3d0718Smx205022 	return (err);
18445a3d0718Smx205022 }
18455a3d0718Smx205022 
1846*0dc2366fSVenugopal Iyer static void
1847*0dc2366fSVenugopal Iyer nge_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1848*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t prh)
1849*0dc2366fSVenugopal Iyer {
1850*0dc2366fSVenugopal Iyer 	nge_t *ngep = barg;
1851*0dc2366fSVenugopal Iyer 
1852*0dc2366fSVenugopal Iyer 	switch (pr_num) {
1853*0dc2366fSVenugopal Iyer 	case MAC_PROP_DUPLEX:
1854*0dc2366fSVenugopal Iyer 	case MAC_PROP_SPEED:
1855*0dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_1000FDX_CAP:
1856*0dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_1000HDX_CAP:
1857*0dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100FDX_CAP:
1858*0dc2366fSVenugopal Iyer 	case MAC_PROP_EN_1000HDX_CAP:
1859*0dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100HDX_CAP:
1860*0dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_10FDX_CAP:
1861*0dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_10HDX_CAP:
1862*0dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100T4_CAP:
1863*0dc2366fSVenugopal Iyer 	case MAC_PROP_EN_100T4_CAP:
1864*0dc2366fSVenugopal Iyer 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1865*0dc2366fSVenugopal Iyer 		break;
1866*0dc2366fSVenugopal Iyer 
1867*0dc2366fSVenugopal Iyer 	case MAC_PROP_EN_1000FDX_CAP:
1868*0dc2366fSVenugopal Iyer 	case MAC_PROP_EN_100FDX_CAP:
1869*0dc2366fSVenugopal Iyer 	case MAC_PROP_EN_100HDX_CAP:
1870*0dc2366fSVenugopal Iyer 	case MAC_PROP_EN_10FDX_CAP:
1871*0dc2366fSVenugopal Iyer 	case MAC_PROP_EN_10HDX_CAP:
1872*0dc2366fSVenugopal Iyer 		mac_prop_info_set_default_uint8(prh, 1);
1873*0dc2366fSVenugopal Iyer 		break;
1874*0dc2366fSVenugopal Iyer 
1875*0dc2366fSVenugopal Iyer 	case MAC_PROP_AUTONEG:
1876*0dc2366fSVenugopal Iyer 		mac_prop_info_set_default_uint8(prh, 1);
1877*0dc2366fSVenugopal Iyer 		break;
1878*0dc2366fSVenugopal Iyer 
1879*0dc2366fSVenugopal Iyer 	case MAC_PROP_FLOWCTRL:
1880*0dc2366fSVenugopal Iyer 		mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI);
1881*0dc2366fSVenugopal Iyer 		break;
1882*0dc2366fSVenugopal Iyer 
1883*0dc2366fSVenugopal Iyer 	case MAC_PROP_MTU:
1884*0dc2366fSVenugopal Iyer 		mac_prop_info_set_range_uint32(prh, ETHERMTU,
1885*0dc2366fSVenugopal Iyer 		    ngep->dev_spec_param.jumbo ? NGE_MAX_MTU : ETHERMTU);
1886*0dc2366fSVenugopal Iyer 		break;
1887*0dc2366fSVenugopal Iyer 
1888*0dc2366fSVenugopal Iyer 	case MAC_PROP_PRIVATE: {
1889*0dc2366fSVenugopal Iyer 		char valstr[64];
1890*0dc2366fSVenugopal Iyer 		int value;
1891*0dc2366fSVenugopal Iyer 
1892*0dc2366fSVenugopal Iyer 		bzero(valstr, sizeof (valstr));
1893*0dc2366fSVenugopal Iyer 		if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
1894*0dc2366fSVenugopal Iyer 			value = NGE_TX_COPY_SIZE;
1895*0dc2366fSVenugopal Iyer 		} else 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
1896*0dc2366fSVenugopal Iyer 			value = NGE_RX_COPY_SIZE;
1897*0dc2366fSVenugopal Iyer 		} else 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
1898*0dc2366fSVenugopal Iyer 			value = 128;
1899*0dc2366fSVenugopal Iyer 		} else 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
1900*0dc2366fSVenugopal Iyer 			value = NGE_POLL_QUIET_TIME;
1901*0dc2366fSVenugopal Iyer 		} else 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
1902*0dc2366fSVenugopal Iyer 			value = NGE_POLL_BUSY_TIME;
1903*0dc2366fSVenugopal Iyer 		} else	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
1904*0dc2366fSVenugopal Iyer 			value = 1;
1905*0dc2366fSVenugopal Iyer 		} else 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
1906*0dc2366fSVenugopal Iyer 			value = 8;
1907*0dc2366fSVenugopal Iyer 		} else {
1908*0dc2366fSVenugopal Iyer 			return;
1909*0dc2366fSVenugopal Iyer 		}
1910*0dc2366fSVenugopal Iyer 
1911*0dc2366fSVenugopal Iyer 		(void) snprintf(valstr, sizeof (valstr), "%d", value);
1912*0dc2366fSVenugopal Iyer 	}
1913*0dc2366fSVenugopal Iyer 	}
1914*0dc2366fSVenugopal Iyer 
1915*0dc2366fSVenugopal Iyer }
1916*0dc2366fSVenugopal Iyer 
19175a3d0718Smx205022 /* ARGSUSED */
19185a3d0718Smx205022 static int
19195a3d0718Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
19205a3d0718Smx205022     const void *pr_val)
19215a3d0718Smx205022 {
19225a3d0718Smx205022 	int err = 0;
19235a3d0718Smx205022 	long result;
19245a3d0718Smx205022 
19255a3d0718Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
19265a3d0718Smx205022 		if (pr_val == NULL) {
19275a3d0718Smx205022 			err = EINVAL;
19285a3d0718Smx205022 			return (err);
19295a3d0718Smx205022 		}
19305a3d0718Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19315a3d0718Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19325a3d0718Smx205022 			err = EINVAL;
19335a3d0718Smx205022 		} else {
19345a3d0718Smx205022 			ngep->param_txbcopy_threshold = (uint32_t)result;
19355a3d0718Smx205022 			goto reprogram;
19365a3d0718Smx205022 		}
19375a3d0718Smx205022 		return (err);
19385a3d0718Smx205022 	}
19395a3d0718Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
19405a3d0718Smx205022 		if (pr_val == NULL) {
19415a3d0718Smx205022 			err = EINVAL;
19425a3d0718Smx205022 			return (err);
19435a3d0718Smx205022 		}
19445a3d0718Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19455a3d0718Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19465a3d0718Smx205022 			err = EINVAL;
19475a3d0718Smx205022 		} else {
19485a3d0718Smx205022 			ngep->param_rxbcopy_threshold = (uint32_t)result;
19495a3d0718Smx205022 			goto reprogram;
19505a3d0718Smx205022 		}
19515a3d0718Smx205022 		return (err);
19525a3d0718Smx205022 	}
19535a3d0718Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
19545a3d0718Smx205022 		if (pr_val == NULL) {
19555a3d0718Smx205022 			err = EINVAL;
19565a3d0718Smx205022 			return (err);
19575a3d0718Smx205022 		}
19585a3d0718Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19595a3d0718Smx205022 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
19605a3d0718Smx205022 			err = EINVAL;
19615a3d0718Smx205022 		} else {
19625a3d0718Smx205022 			ngep->param_recv_max_packet = (uint32_t)result;
19635a3d0718Smx205022 			goto reprogram;
19645a3d0718Smx205022 		}
19655a3d0718Smx205022 		return (err);
19665a3d0718Smx205022 	}
19675a3d0718Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
19685a3d0718Smx205022 		if (pr_val == NULL) {
19695a3d0718Smx205022 			err = EINVAL;
19705a3d0718Smx205022 			return (err);
19715a3d0718Smx205022 		}
19725a3d0718Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19735a3d0718Smx205022 		if (result < 0 || result > 10000) {
19745a3d0718Smx205022 			err = EINVAL;
19755a3d0718Smx205022 		} else {
19765a3d0718Smx205022 			ngep->param_poll_quiet_time = (uint32_t)result;
19775a3d0718Smx205022 			goto reprogram;
19785a3d0718Smx205022 		}
19795a3d0718Smx205022 		return (err);
19805a3d0718Smx205022 	}
19815a3d0718Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
19825a3d0718Smx205022 		if (pr_val == NULL) {
19835a3d0718Smx205022 			err = EINVAL;
19845a3d0718Smx205022 			return (err);
19855a3d0718Smx205022 		}
19865a3d0718Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19875a3d0718Smx205022 		if (result < 0 || result > 10000) {
19885a3d0718Smx205022 			err = EINVAL;
19895a3d0718Smx205022 		} else {
19905a3d0718Smx205022 			ngep->param_poll_busy_time = (uint32_t)result;
19915a3d0718Smx205022 			goto reprogram;
19925a3d0718Smx205022 		}
19935a3d0718Smx205022 		return (err);
19945a3d0718Smx205022 	}
19955a3d0718Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
19965a3d0718Smx205022 		if (pr_val == NULL) {
19975a3d0718Smx205022 			err = EINVAL;
19985a3d0718Smx205022 			return (err);
19995a3d0718Smx205022 		}
20005a3d0718Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20014045d941Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20025a3d0718Smx205022 			err = EINVAL;
20035a3d0718Smx205022 		} else {
20045a3d0718Smx205022 			ngep->param_rx_intr_hwater = (uint32_t)result;
20055a3d0718Smx205022 			goto reprogram;
20065a3d0718Smx205022 		}
20075a3d0718Smx205022 		return (err);
20085a3d0718Smx205022 	}
20095a3d0718Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
20105a3d0718Smx205022 		if (pr_val == NULL) {
20115a3d0718Smx205022 			err = EINVAL;
20125a3d0718Smx205022 			return (err);
20135a3d0718Smx205022 		}
20145a3d0718Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20154045d941Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20165a3d0718Smx205022 			err = EINVAL;
20175a3d0718Smx205022 		} else {
20185a3d0718Smx205022 			ngep->param_rx_intr_lwater = (uint32_t)result;
20195a3d0718Smx205022 			goto reprogram;
20205a3d0718Smx205022 		}
20215a3d0718Smx205022 		return (err);
20225a3d0718Smx205022 	}
20235a3d0718Smx205022 	err = ENOTSUP;
20245a3d0718Smx205022 	return (err);
20255a3d0718Smx205022 
20265a3d0718Smx205022 reprogram:
20275a3d0718Smx205022 	if (err == 0) {
20285a3d0718Smx205022 		(*ngep->physops->phys_update)(ngep);
20295a3d0718Smx205022 		nge_chip_sync(ngep);
20305a3d0718Smx205022 	}
20315a3d0718Smx205022 
20325a3d0718Smx205022 	return (err);
20335a3d0718Smx205022 }
20345a3d0718Smx205022 
20355a3d0718Smx205022 static int
2036*0dc2366fSVenugopal Iyer nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
2037*0dc2366fSVenugopal Iyer     void *pr_val)
20385a3d0718Smx205022 {
20395a3d0718Smx205022 	int err = ENOTSUP;
20404045d941Ssowmini 	int value;
20415a3d0718Smx205022 
20425a3d0718Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
2043*0dc2366fSVenugopal Iyer 		value = ngep->param_txbcopy_threshold;
20445a3d0718Smx205022 		err = 0;
20455a3d0718Smx205022 		goto done;
20465a3d0718Smx205022 	}
20475a3d0718Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
2048*0dc2366fSVenugopal Iyer 		value = ngep->param_rxbcopy_threshold;
20495a3d0718Smx205022 		err = 0;
20505a3d0718Smx205022 		goto done;
20515a3d0718Smx205022 	}
20525a3d0718Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
2053*0dc2366fSVenugopal Iyer 		value = ngep->param_recv_max_packet;
20545a3d0718Smx205022 		err = 0;
20555a3d0718Smx205022 		goto done;
20565a3d0718Smx205022 	}
20575a3d0718Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
2058*0dc2366fSVenugopal Iyer 		value = ngep->param_poll_quiet_time;
20595a3d0718Smx205022 		err = 0;
20605a3d0718Smx205022 		goto done;
20615a3d0718Smx205022 	}
20625a3d0718Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
2063*0dc2366fSVenugopal Iyer 		value = ngep->param_poll_busy_time;
20645a3d0718Smx205022 		err = 0;
20655a3d0718Smx205022 		goto done;
20665a3d0718Smx205022 	}
20675a3d0718Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
2068*0dc2366fSVenugopal Iyer 		value = ngep->param_rx_intr_hwater;
20695a3d0718Smx205022 		err = 0;
20705a3d0718Smx205022 		goto done;
20715a3d0718Smx205022 	}
20725a3d0718Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
2073*0dc2366fSVenugopal Iyer 		value = ngep->param_rx_intr_lwater;
20745a3d0718Smx205022 		err = 0;
20755a3d0718Smx205022 		goto done;
20765a3d0718Smx205022 	}
20775a3d0718Smx205022 
20785a3d0718Smx205022 done:
20795a3d0718Smx205022 	if (err == 0) {
20804045d941Ssowmini 		(void) snprintf(pr_val, pr_valsize, "%d", value);
20815a3d0718Smx205022 	}
20825a3d0718Smx205022 	return (err);
20835a3d0718Smx205022 }
20845a3d0718Smx205022 
20856f3e57acSmx205022 /* ARGSUSED */
20866f3e57acSmx205022 static boolean_t
20876f3e57acSmx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
20886f3e57acSmx205022 {
20896f3e57acSmx205022 	nge_t	*ngep = arg;
20906f3e57acSmx205022 	nge_dev_spec_param_t *dev_param_p;
20916f3e57acSmx205022 
20926f3e57acSmx205022 	dev_param_p = &ngep->dev_spec_param;
20936f3e57acSmx205022 
20946f3e57acSmx205022 	switch (cap) {
20956f3e57acSmx205022 	case MAC_CAPAB_HCKSUM: {
20966f3e57acSmx205022 		uint32_t *hcksum_txflags = cap_data;
20976f3e57acSmx205022 
20986f3e57acSmx205022 		if (dev_param_p->tx_hw_checksum) {
20996f3e57acSmx205022 			*hcksum_txflags = dev_param_p->tx_hw_checksum;
21006f3e57acSmx205022 		} else
21016f3e57acSmx205022 			return (B_FALSE);
21026f3e57acSmx205022 		break;
21036f3e57acSmx205022 	}
21046f3e57acSmx205022 	default:
21056f3e57acSmx205022 		return (B_FALSE);
21066f3e57acSmx205022 	}
21076f3e57acSmx205022 	return (B_TRUE);
21086f3e57acSmx205022 }
21096f3e57acSmx205022 
21106f3e57acSmx205022 #undef	NGE_DBG
21116f3e57acSmx205022 #define	NGE_DBG	NGE_DBG_INIT	/* debug flag for this code	*/
21126f3e57acSmx205022 int
21136f3e57acSmx205022 nge_restart(nge_t *ngep)
21146f3e57acSmx205022 {
21156f3e57acSmx205022 	int err = 0;
211619397407SSherry Moore 	err = nge_reset_dev(ngep);
21176de4f663Smx205022 	/* write back the promisc setting */
21186de4f663Smx205022 	ngep->promisc = ngep->record_promisc;
2119c322ff79Smx205022 	nge_chip_sync(ngep);
21202d58516dSmx205022 	if (!err)
21212d58516dSmx205022 		err = nge_chip_start(ngep);
21226f3e57acSmx205022 
21236f3e57acSmx205022 	if (err) {
21246f3e57acSmx205022 		ngep->nge_mac_state = NGE_MAC_STOPPED;
21256f3e57acSmx205022 		return (DDI_FAILURE);
21266f3e57acSmx205022 	} else {
21276f3e57acSmx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
21286f3e57acSmx205022 		return (DDI_SUCCESS);
21296f3e57acSmx205022 	}
21306f3e57acSmx205022 }
21316f3e57acSmx205022 
21326f3e57acSmx205022 void
21336f3e57acSmx205022 nge_wake_factotum(nge_t *ngep)
21346f3e57acSmx205022 {
21356f3e57acSmx205022 	mutex_enter(ngep->softlock);
21366f3e57acSmx205022 	if (ngep->factotum_flag == 0) {
21376f3e57acSmx205022 		ngep->factotum_flag = 1;
21386f3e57acSmx205022 		(void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
21396f3e57acSmx205022 	}
21406f3e57acSmx205022 	mutex_exit(ngep->softlock);
21416f3e57acSmx205022 }
21426f3e57acSmx205022 
214351fc88a8SWinson Wang - Sun Microsystems - Beijing China void
214451fc88a8SWinson Wang - Sun Microsystems - Beijing China nge_interrupt_optimize(nge_t *ngep)
214551fc88a8SWinson Wang - Sun Microsystems - Beijing China {
214651fc88a8SWinson Wang - Sun Microsystems - Beijing China 	uint32_t tx_pkts;
214751fc88a8SWinson Wang - Sun Microsystems - Beijing China 	tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last;
214851fc88a8SWinson Wang - Sun Microsystems - Beijing China 	ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count;
214951fc88a8SWinson Wang - Sun Microsystems - Beijing China 	if ((tx_pkts > NGE_POLL_TUNE) &&
215051fc88a8SWinson Wang - Sun Microsystems - Beijing China 	    (tx_pkts <= NGE_POLL_MAX))
215151fc88a8SWinson Wang - Sun Microsystems - Beijing China 		ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER);
215251fc88a8SWinson Wang - Sun Microsystems - Beijing China 	else
215351fc88a8SWinson Wang - Sun Microsystems - Beijing China 		ngep->tfint_threshold = NGE_TFINT_DEFAULT;
215451fc88a8SWinson Wang - Sun Microsystems - Beijing China }
215551fc88a8SWinson Wang - Sun Microsystems - Beijing China 
21566f3e57acSmx205022 /*
21576f3e57acSmx205022  * High-level cyclic handler
21586f3e57acSmx205022  *
21596f3e57acSmx205022  * This routine schedules a (low-level) softint callback to the
21606f3e57acSmx205022  * factotum.
21616f3e57acSmx205022  */
21626f3e57acSmx205022 
21636f3e57acSmx205022 static void
21646f3e57acSmx205022 nge_chip_cyclic(void *arg)
21656f3e57acSmx205022 {
21666f3e57acSmx205022 	nge_t *ngep;
21676f3e57acSmx205022 
21686f3e57acSmx205022 	ngep = (nge_t *)arg;
21696f3e57acSmx205022 
21706f3e57acSmx205022 	switch (ngep->nge_chip_state) {
21716f3e57acSmx205022 	default:
21726f3e57acSmx205022 		return;
21736f3e57acSmx205022 
21746f3e57acSmx205022 	case NGE_CHIP_RUNNING:
217551fc88a8SWinson Wang - Sun Microsystems - Beijing China 		nge_interrupt_optimize(ngep);
21766f3e57acSmx205022 		break;
21776f3e57acSmx205022 
21786f3e57acSmx205022 	case NGE_CHIP_FAULT:
21796f3e57acSmx205022 	case NGE_CHIP_ERROR:
21806f3e57acSmx205022 		break;
21816f3e57acSmx205022 	}
21826f3e57acSmx205022 
21836f3e57acSmx205022 	nge_wake_factotum(ngep);
21846f3e57acSmx205022 }
21856f3e57acSmx205022 
2186d635b452SWinson Wang - Sun Microsystems - Beijing China /*
2187d635b452SWinson Wang - Sun Microsystems - Beijing China  * Get/Release semaphore of SMU
2188d635b452SWinson Wang - Sun Microsystems - Beijing China  * For SMU enabled chipset
2189d635b452SWinson Wang - Sun Microsystems - Beijing China  * When nge driver is attached, driver should acquire
2190d635b452SWinson Wang - Sun Microsystems - Beijing China  * semaphore before PHY init and accessing MAC registers.
2191d635b452SWinson Wang - Sun Microsystems - Beijing China  * When nge driver is unattached, driver should release
2192d635b452SWinson Wang - Sun Microsystems - Beijing China  * semaphore.
2193d635b452SWinson Wang - Sun Microsystems - Beijing China  */
2194d635b452SWinson Wang - Sun Microsystems - Beijing China 
2195d635b452SWinson Wang - Sun Microsystems - Beijing China static int
2196d635b452SWinson Wang - Sun Microsystems - Beijing China nge_smu_sema(nge_t *ngep, boolean_t acquire)
2197d635b452SWinson Wang - Sun Microsystems - Beijing China {
2198d635b452SWinson Wang - Sun Microsystems - Beijing China 	nge_tx_en tx_en;
2199d635b452SWinson Wang - Sun Microsystems - Beijing China 	uint32_t tries;
2200d635b452SWinson Wang - Sun Microsystems - Beijing China 
2201d635b452SWinson Wang - Sun Microsystems - Beijing China 	if (acquire) {
2202d635b452SWinson Wang - Sun Microsystems - Beijing China 		for (tries = 0; tries < 5; tries++) {
2203d635b452SWinson Wang - Sun Microsystems - Beijing China 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2204d635b452SWinson Wang - Sun Microsystems - Beijing China 			if (tx_en.bits.smu2mac == NGE_SMU_FREE)
2205d635b452SWinson Wang - Sun Microsystems - Beijing China 				break;
2206d635b452SWinson Wang - Sun Microsystems - Beijing China 			delay(drv_usectohz(1000000));
2207d635b452SWinson Wang - Sun Microsystems - Beijing China 		}
2208d635b452SWinson Wang - Sun Microsystems - Beijing China 		if (tx_en.bits.smu2mac != NGE_SMU_FREE)
2209d635b452SWinson Wang - Sun Microsystems - Beijing China 			return (DDI_FAILURE);
2210d635b452SWinson Wang - Sun Microsystems - Beijing China 		for (tries = 0; tries < 5; tries++) {
2211d635b452SWinson Wang - Sun Microsystems - Beijing China 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2212d635b452SWinson Wang - Sun Microsystems - Beijing China 			tx_en.bits.mac2smu = NGE_SMU_GET;
2213d635b452SWinson Wang - Sun Microsystems - Beijing China 			nge_reg_put32(ngep, NGE_TX_EN, tx_en.val);
2214d635b452SWinson Wang - Sun Microsystems - Beijing China 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2215d635b452SWinson Wang - Sun Microsystems - Beijing China 
2216d635b452SWinson Wang - Sun Microsystems - Beijing China 			if (tx_en.bits.mac2smu == NGE_SMU_GET &&
2217d635b452SWinson Wang - Sun Microsystems - Beijing China 			    tx_en.bits.smu2mac == NGE_SMU_FREE)
2218d635b452SWinson Wang - Sun Microsystems - Beijing China 				return (DDI_SUCCESS);
2219d635b452SWinson Wang - Sun Microsystems - Beijing China 			drv_usecwait(10);
2220d635b452SWinson Wang - Sun Microsystems - Beijing China 		}
2221d635b452SWinson Wang - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
2222d635b452SWinson Wang - Sun Microsystems - Beijing China 	} else
2223d635b452SWinson Wang - Sun Microsystems - Beijing China 		nge_reg_put32(ngep, NGE_TX_EN, 0x0);
2224d635b452SWinson Wang - Sun Microsystems - Beijing China 
2225d635b452SWinson Wang - Sun Microsystems - Beijing China 	return (DDI_SUCCESS);
2226d635b452SWinson Wang - Sun Microsystems - Beijing China 
2227d635b452SWinson Wang - Sun Microsystems - Beijing China }
22286f3e57acSmx205022 static void
22296f3e57acSmx205022 nge_unattach(nge_t *ngep)
22306f3e57acSmx205022 {
22316f3e57acSmx205022 	send_ring_t *srp;
22326f3e57acSmx205022 	buff_ring_t *brp;
22336f3e57acSmx205022 
22346f3e57acSmx205022 	srp = ngep->send;
22356f3e57acSmx205022 	brp = ngep->buff;
22366f3e57acSmx205022 	NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
22376f3e57acSmx205022 
22386f3e57acSmx205022 	/*
22396f3e57acSmx205022 	 * Flag that no more activity may be initiated
22406f3e57acSmx205022 	 */
22416f3e57acSmx205022 	ngep->progress &= ~PROGRESS_READY;
22426f3e57acSmx205022 	ngep->nge_mac_state = NGE_MAC_UNATTACH;
22436f3e57acSmx205022 
22446f3e57acSmx205022 	/*
22456f3e57acSmx205022 	 * Quiesce the PHY and MAC (leave it reset but still powered).
22466f3e57acSmx205022 	 * Clean up and free all NGE data structures
22476f3e57acSmx205022 	 */
22486f3e57acSmx205022 	if (ngep->periodic_id != NULL) {
22496f3e57acSmx205022 		ddi_periodic_delete(ngep->periodic_id);
22506f3e57acSmx205022 		ngep->periodic_id = NULL;
22516f3e57acSmx205022 	}
22526f3e57acSmx205022 
22536f3e57acSmx205022 	if (ngep->progress & PROGRESS_KSTATS)
22546f3e57acSmx205022 		nge_fini_kstats(ngep);
22556f3e57acSmx205022 
22566f3e57acSmx205022 	if (ngep->progress & PROGRESS_HWINT) {
22576f3e57acSmx205022 		mutex_enter(ngep->genlock);
22586f3e57acSmx205022 		nge_restore_mac_addr(ngep);
22596f3e57acSmx205022 		(void) nge_chip_stop(ngep, B_FALSE);
2260d635b452SWinson Wang - Sun Microsystems - Beijing China 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2261d635b452SWinson Wang - Sun Microsystems - Beijing China 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2262d635b452SWinson Wang - Sun Microsystems - Beijing China 			(void) nge_smu_sema(ngep, B_FALSE);
2263d635b452SWinson Wang - Sun Microsystems - Beijing China 		}
22646f3e57acSmx205022 		mutex_exit(ngep->genlock);
22656f3e57acSmx205022 	}
22666f3e57acSmx205022 
22676f3e57acSmx205022 	if (ngep->progress & PROGRESS_SWINT)
22686f3e57acSmx205022 		nge_rem_intrs(ngep);
22696f3e57acSmx205022 
22706f3e57acSmx205022 	if (ngep->progress & PROGRESS_FACTOTUM)
22716f3e57acSmx205022 		(void) ddi_intr_remove_softint(ngep->factotum_hdl);
22726f3e57acSmx205022 
22736f3e57acSmx205022 	if (ngep->progress & PROGRESS_RESCHED)
22746f3e57acSmx205022 		(void) ddi_intr_remove_softint(ngep->resched_hdl);
22756f3e57acSmx205022 
22766f3e57acSmx205022 	if (ngep->progress & PROGRESS_INTR) {
22776f3e57acSmx205022 		mutex_destroy(srp->tx_lock);
22786f3e57acSmx205022 		mutex_destroy(srp->tc_lock);
22796f3e57acSmx205022 		mutex_destroy(&srp->dmah_lock);
22806f3e57acSmx205022 		mutex_destroy(brp->recycle_lock);
22816f3e57acSmx205022 
22826f3e57acSmx205022 		mutex_destroy(ngep->genlock);
22836f3e57acSmx205022 		mutex_destroy(ngep->softlock);
22846f3e57acSmx205022 		rw_destroy(ngep->rwlock);
22856f3e57acSmx205022 	}
22866f3e57acSmx205022 
22876f3e57acSmx205022 	if (ngep->progress & PROGRESS_REGS)
22886f3e57acSmx205022 		ddi_regs_map_free(&ngep->io_handle);
22896f3e57acSmx205022 
22906f3e57acSmx205022 	if (ngep->progress & PROGRESS_CFG)
22916f3e57acSmx205022 		pci_config_teardown(&ngep->cfg_handle);
22926f3e57acSmx205022 
22936f3e57acSmx205022 	ddi_remove_minor_node(ngep->devinfo, NULL);
22946f3e57acSmx205022 
22956f3e57acSmx205022 	kmem_free(ngep, sizeof (*ngep));
22966f3e57acSmx205022 }
22976f3e57acSmx205022 
22986f3e57acSmx205022 static int
22996f3e57acSmx205022 nge_resume(dev_info_t *devinfo)
23006f3e57acSmx205022 {
23016f3e57acSmx205022 	nge_t		*ngep;
23026f3e57acSmx205022 	chip_info_t	*infop;
23032d58516dSmx205022 	int 		err;
23046f3e57acSmx205022 
23056f3e57acSmx205022 	ASSERT(devinfo != NULL);
23066f3e57acSmx205022 
23076f3e57acSmx205022 	ngep = ddi_get_driver_private(devinfo);
23082d58516dSmx205022 	err = 0;
23092d58516dSmx205022 
23106f3e57acSmx205022 	/*
23116f3e57acSmx205022 	 * If there are state inconsistancies, this is bad.  Returning
23126f3e57acSmx205022 	 * DDI_FAILURE here will eventually cause the machine to panic,
23136f3e57acSmx205022 	 * so it is best done here so that there is a possibility of
23146f3e57acSmx205022 	 * debugging the problem.
23156f3e57acSmx205022 	 */
23166f3e57acSmx205022 	if (ngep == NULL)
23176f3e57acSmx205022 		cmn_err(CE_PANIC,
23186f3e57acSmx205022 		    "nge: ngep returned from ddi_get_driver_private was NULL");
23196f3e57acSmx205022 	infop = (chip_info_t *)&ngep->chipinfo;
23206f3e57acSmx205022 
23216f3e57acSmx205022 	if (ngep->devinfo != devinfo)
23226f3e57acSmx205022 		cmn_err(CE_PANIC,
23232d58516dSmx205022 		    "nge: passed devinfo not the same as saved devinfo");
23246f3e57acSmx205022 
23252d58516dSmx205022 	mutex_enter(ngep->genlock);
23262d58516dSmx205022 	rw_enter(ngep->rwlock, RW_WRITER);
23276f3e57acSmx205022 
23286f3e57acSmx205022 	/*
23296f3e57acSmx205022 	 * Fetch the config space.  Even though we have most of it cached,
23306f3e57acSmx205022 	 * some values *might* change across a suspend/resume.
23316f3e57acSmx205022 	 */
23326f3e57acSmx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
23336f3e57acSmx205022 
23346f3e57acSmx205022 	/*
23352d58516dSmx205022 	 * Only in one case, this conditional branch can be executed: the port
23362d58516dSmx205022 	 * hasn't been plumbed.
23376f3e57acSmx205022 	 */
23382d58516dSmx205022 	if (ngep->suspended == B_FALSE) {
23392d58516dSmx205022 		rw_exit(ngep->rwlock);
23402d58516dSmx205022 		mutex_exit(ngep->genlock);
23412d58516dSmx205022 		return (DDI_SUCCESS);
23422d58516dSmx205022 	}
23432d58516dSmx205022 
23442d58516dSmx205022 	nge_tx_recycle_all(ngep);
23452d58516dSmx205022 	err = nge_reinit_ring(ngep);
23462d58516dSmx205022 	if (!err) {
23472d58516dSmx205022 		err = nge_chip_reset(ngep);
23482d58516dSmx205022 		if (!err)
23492d58516dSmx205022 			err = nge_chip_start(ngep);
23502d58516dSmx205022 	}
23512d58516dSmx205022 
23522d58516dSmx205022 	if (err) {
23536f3e57acSmx205022 		/*
23546f3e57acSmx205022 		 * We note the failure, but return success, as the
23556f3e57acSmx205022 		 * system is still usable without this controller.
23566f3e57acSmx205022 		 */
23576f3e57acSmx205022 		cmn_err(CE_WARN, "nge: resume: failed to restart controller");
23582d58516dSmx205022 	} else {
23592d58516dSmx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
23606f3e57acSmx205022 	}
23612d58516dSmx205022 	ngep->suspended = B_FALSE;
23622d58516dSmx205022 
23632d58516dSmx205022 	rw_exit(ngep->rwlock);
23642d58516dSmx205022 	mutex_exit(ngep->genlock);
23652d58516dSmx205022 
23666f3e57acSmx205022 	return (DDI_SUCCESS);
23676f3e57acSmx205022 }
23686f3e57acSmx205022 
23696f3e57acSmx205022 /*
23706f3e57acSmx205022  * attach(9E) -- Attach a device to the system
23716f3e57acSmx205022  *
23726f3e57acSmx205022  * Called once for each board successfully probed.
23736f3e57acSmx205022  */
23746f3e57acSmx205022 static int
23756f3e57acSmx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
23766f3e57acSmx205022 {
23776f3e57acSmx205022 	int		err;
23786f3e57acSmx205022 	int		i;
23796f3e57acSmx205022 	int		instance;
23806f3e57acSmx205022 	caddr_t		regs;
23816f3e57acSmx205022 	nge_t		*ngep;
23826f3e57acSmx205022 	chip_info_t	*infop;
23836f3e57acSmx205022 	mac_register_t	*macp;
23846f3e57acSmx205022 
23856f3e57acSmx205022 	switch (cmd) {
23866f3e57acSmx205022 	default:
23876f3e57acSmx205022 		return (DDI_FAILURE);
23886f3e57acSmx205022 
23896f3e57acSmx205022 	case DDI_RESUME:
23906f3e57acSmx205022 		return (nge_resume(devinfo));
23916f3e57acSmx205022 
23926f3e57acSmx205022 	case DDI_ATTACH:
23936f3e57acSmx205022 		break;
23946f3e57acSmx205022 	}
23956f3e57acSmx205022 
23966f3e57acSmx205022 	ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
23976f3e57acSmx205022 	instance = ddi_get_instance(devinfo);
23986f3e57acSmx205022 	ddi_set_driver_private(devinfo, ngep);
23996f3e57acSmx205022 	ngep->devinfo = devinfo;
24006f3e57acSmx205022 
24016f3e57acSmx205022 	(void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
24026f3e57acSmx205022 	    NGE_DRIVER_NAME, instance);
24036f3e57acSmx205022 	err = pci_config_setup(devinfo, &ngep->cfg_handle);
24046f3e57acSmx205022 	if (err != DDI_SUCCESS) {
24056f3e57acSmx205022 		nge_problem(ngep, "nge_attach: pci_config_setup() failed");
24066f3e57acSmx205022 		goto attach_fail;
24076f3e57acSmx205022 	}
24084045d941Ssowmini 	/*
24094045d941Ssowmini 	 * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy
24104045d941Ssowmini 	 * thresholds. Bounds: min 0, max NGE_MAX_SDU
24114045d941Ssowmini 	 */
24124045d941Ssowmini 	ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE;
24134045d941Ssowmini 	ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE;
24144045d941Ssowmini 
24154045d941Ssowmini 	/*
24164045d941Ssowmini 	 * param_recv_max_packet is max packet received per interupt.
24174045d941Ssowmini 	 * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024
24184045d941Ssowmini 	 */
24194045d941Ssowmini 	ngep->param_recv_max_packet = 128;
24204045d941Ssowmini 
24214045d941Ssowmini 	/*
24224045d941Ssowmini 	 * param_poll_quiet_time and param_poll_busy_time are quiet/busy time
24234045d941Ssowmini 	 * switch from per packet interrupt to polling interrupt.
24244045d941Ssowmini 	 * Bounds: min 0, max 10000
24254045d941Ssowmini 	 */
24264045d941Ssowmini 	ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
24274045d941Ssowmini 	ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
242851fc88a8SWinson Wang - Sun Microsystems - Beijing China 	ngep->tfint_threshold = NGE_TFINT_DEFAULT;
242951fc88a8SWinson Wang - Sun Microsystems - Beijing China 	ngep->poll = B_FALSE;
243051fc88a8SWinson Wang - Sun Microsystems - Beijing China 	ngep->ch_intr_mode = B_FALSE;
24314045d941Ssowmini 
24324045d941Ssowmini 	/*
24334045d941Ssowmini 	 * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
24344045d941Ssowmini 	 * to trigger the poll_quiet_time/poll_busy_time counter.
24354045d941Ssowmini 	 * Bounds: min 0, max  NGE_RECV_SLOTS_DESC_1024.
24364045d941Ssowmini 	 */
24374045d941Ssowmini 	ngep->param_rx_intr_hwater = 1;
24384045d941Ssowmini 	ngep->param_rx_intr_lwater = 8;
24394045d941Ssowmini 
24404045d941Ssowmini 
24416f3e57acSmx205022 	infop = (chip_info_t *)&ngep->chipinfo;
24426f3e57acSmx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
24436f3e57acSmx205022 	nge_init_dev_spec_param(ngep);
24446f3e57acSmx205022 	nge_get_props(ngep);
24456f3e57acSmx205022 	ngep->progress |= PROGRESS_CFG;
24466f3e57acSmx205022 
24476f3e57acSmx205022 	err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
24486f3e57acSmx205022 	    &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
24496f3e57acSmx205022 	if (err != DDI_SUCCESS) {
24506f3e57acSmx205022 		nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
24516f3e57acSmx205022 		goto attach_fail;
24526f3e57acSmx205022 	}
24536f3e57acSmx205022 	ngep->io_regs = regs;
24546f3e57acSmx205022 	ngep->progress |= PROGRESS_REGS;
24556f3e57acSmx205022 
24566f3e57acSmx205022 	err = nge_register_intrs_and_init_locks(ngep);
24576f3e57acSmx205022 	if (err != DDI_SUCCESS) {
24586f3e57acSmx205022 		nge_problem(ngep, "nge_attach:"
24596f3e57acSmx205022 		    " register intrs and init locks failed");
24606f3e57acSmx205022 		goto attach_fail;
24616f3e57acSmx205022 	}
24626f3e57acSmx205022 	nge_init_ring_param_lock(ngep);
24636f3e57acSmx205022 	ngep->progress |= PROGRESS_INTR;
24646f3e57acSmx205022 
24656f3e57acSmx205022 	mutex_enter(ngep->genlock);
24666f3e57acSmx205022 
2467d635b452SWinson Wang - Sun Microsystems - Beijing China 	if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2468d635b452SWinson Wang - Sun Microsystems - Beijing China 	    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2469d635b452SWinson Wang - Sun Microsystems - Beijing China 		err = nge_smu_sema(ngep, B_TRUE);
2470d635b452SWinson Wang - Sun Microsystems - Beijing China 		if (err != DDI_SUCCESS) {
2471d635b452SWinson Wang - Sun Microsystems - Beijing China 			nge_problem(ngep, "nge_attach: nge_smu_sema() failed");
2472d635b452SWinson Wang - Sun Microsystems - Beijing China 			goto attach_fail;
2473d635b452SWinson Wang - Sun Microsystems - Beijing China 		}
2474d635b452SWinson Wang - Sun Microsystems - Beijing China 	}
24756f3e57acSmx205022 	/*
24766f3e57acSmx205022 	 * Initialise link state variables
24776f3e57acSmx205022 	 * Stop, reset & reinitialise the chip.
24786f3e57acSmx205022 	 * Initialise the (internal) PHY.
24796f3e57acSmx205022 	 */
24806f3e57acSmx205022 	nge_phys_init(ngep);
2481d27d4a13SMiles Xu, Sun Microsystems 	ngep->nge_chip_state = NGE_CHIP_INITIAL;
24826f3e57acSmx205022 	err = nge_chip_reset(ngep);
24836f3e57acSmx205022 	if (err != DDI_SUCCESS) {
24846f3e57acSmx205022 		nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
24856f3e57acSmx205022 		mutex_exit(ngep->genlock);
24866f3e57acSmx205022 		goto attach_fail;
24876f3e57acSmx205022 	}
24886f3e57acSmx205022 	nge_chip_sync(ngep);
24896f3e57acSmx205022 
24906f3e57acSmx205022 	/*
24916f3e57acSmx205022 	 * Now that mutex locks are initialized, enable interrupts.
24926f3e57acSmx205022 	 */
24936f3e57acSmx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
24946f3e57acSmx205022 		/* Call ddi_intr_block_enable() for MSI interrupts */
24956f3e57acSmx205022 		(void) ddi_intr_block_enable(ngep->htable,
24966f3e57acSmx205022 		    ngep->intr_actual_cnt);
24976f3e57acSmx205022 	} else {
24986f3e57acSmx205022 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
24996f3e57acSmx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
25006f3e57acSmx205022 			(void) ddi_intr_enable(ngep->htable[i]);
25016f3e57acSmx205022 		}
25026f3e57acSmx205022 	}
25036f3e57acSmx205022 
25046f3e57acSmx205022 	ngep->link_state = LINK_STATE_UNKNOWN;
25056f3e57acSmx205022 	ngep->progress |= PROGRESS_HWINT;
25066f3e57acSmx205022 
25076f3e57acSmx205022 	/*
25086f3e57acSmx205022 	 * Register NDD-tweakable parameters
25096f3e57acSmx205022 	 */
25106f3e57acSmx205022 	if (nge_nd_init(ngep)) {
25116f3e57acSmx205022 		nge_problem(ngep, "nge_attach: nge_nd_init() failed");
25126f3e57acSmx205022 		mutex_exit(ngep->genlock);
25136f3e57acSmx205022 		goto attach_fail;
25146f3e57acSmx205022 	}
25156f3e57acSmx205022 	ngep->progress |= PROGRESS_NDD;
25166f3e57acSmx205022 
25176f3e57acSmx205022 	/*
25186f3e57acSmx205022 	 * Create & initialise named kstats
25196f3e57acSmx205022 	 */
25206f3e57acSmx205022 	nge_init_kstats(ngep, instance);
25216f3e57acSmx205022 	ngep->progress |= PROGRESS_KSTATS;
25226f3e57acSmx205022 
25236f3e57acSmx205022 	mutex_exit(ngep->genlock);
25246f3e57acSmx205022 
25256f3e57acSmx205022 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
25266f3e57acSmx205022 		goto attach_fail;
25276f3e57acSmx205022 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
25286f3e57acSmx205022 	macp->m_driver = ngep;
25296f3e57acSmx205022 	macp->m_dip = devinfo;
25306f3e57acSmx205022 	macp->m_src_addr = infop->vendor_addr.addr;
25316f3e57acSmx205022 	macp->m_callbacks = &nge_m_callbacks;
25326f3e57acSmx205022 	macp->m_min_sdu = 0;
25336f3e57acSmx205022 	macp->m_max_sdu = ngep->default_mtu;
2534d62bc4baSyz147064 	macp->m_margin = VTAG_SIZE;
25354045d941Ssowmini 	macp->m_priv_props = nge_priv_props;
25366f3e57acSmx205022 	/*
25376f3e57acSmx205022 	 * Finally, we're ready to register ourselves with the mac
25386f3e57acSmx205022 	 * interface; if this succeeds, we're all ready to start()
25396f3e57acSmx205022 	 */
25406f3e57acSmx205022 	err = mac_register(macp, &ngep->mh);
25416f3e57acSmx205022 	mac_free(macp);
25426f3e57acSmx205022 	if (err != 0)
25436f3e57acSmx205022 		goto attach_fail;
25446f3e57acSmx205022 
25456f3e57acSmx205022 	/*
25466f3e57acSmx205022 	 * Register a periodical handler.
25476f3e57acSmx205022 	 * nge_chip_cyclic() is invoked in kernel context.
25486f3e57acSmx205022 	 */
25496f3e57acSmx205022 	ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
25506f3e57acSmx205022 	    NGE_CYCLIC_PERIOD, DDI_IPL_0);
25516f3e57acSmx205022 
25526f3e57acSmx205022 	ngep->progress |= PROGRESS_READY;
25536f3e57acSmx205022 	return (DDI_SUCCESS);
25546f3e57acSmx205022 
25556f3e57acSmx205022 attach_fail:
25566f3e57acSmx205022 	nge_unattach(ngep);
25576f3e57acSmx205022 	return (DDI_FAILURE);
25586f3e57acSmx205022 }
25596f3e57acSmx205022 
25602d58516dSmx205022 static int
25612d58516dSmx205022 nge_suspend(nge_t *ngep)
25622d58516dSmx205022 {
25632d58516dSmx205022 	mutex_enter(ngep->genlock);
25642d58516dSmx205022 	rw_enter(ngep->rwlock, RW_WRITER);
25652d58516dSmx205022 
25662d58516dSmx205022 	/* if the port hasn't been plumbed, just return */
25672d58516dSmx205022 	if (ngep->nge_mac_state != NGE_MAC_STARTED) {
25682d58516dSmx205022 		rw_exit(ngep->rwlock);
25692d58516dSmx205022 		mutex_exit(ngep->genlock);
25702d58516dSmx205022 		return (DDI_SUCCESS);
25712d58516dSmx205022 	}
25722d58516dSmx205022 	ngep->suspended = B_TRUE;
25732d58516dSmx205022 	(void) nge_chip_stop(ngep, B_FALSE);
25742d58516dSmx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
25752d58516dSmx205022 
25762d58516dSmx205022 	rw_exit(ngep->rwlock);
25772d58516dSmx205022 	mutex_exit(ngep->genlock);
25782d58516dSmx205022 	return (DDI_SUCCESS);
25792d58516dSmx205022 }
25802d58516dSmx205022 
25816f3e57acSmx205022 /*
25826f3e57acSmx205022  * detach(9E) -- Detach a device from the system
25836f3e57acSmx205022  */
25846f3e57acSmx205022 static int
25856f3e57acSmx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
25866f3e57acSmx205022 {
25876f3e57acSmx205022 	int i;
25886f3e57acSmx205022 	nge_t *ngep;
25896f3e57acSmx205022 	mul_item *p, *nextp;
25906f3e57acSmx205022 	buff_ring_t *brp;
25916f3e57acSmx205022 
25926f3e57acSmx205022 	NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
25936f3e57acSmx205022 
25946f3e57acSmx205022 	ngep = ddi_get_driver_private(devinfo);
25956f3e57acSmx205022 	brp = ngep->buff;
25966f3e57acSmx205022 
25976f3e57acSmx205022 	switch (cmd) {
25986f3e57acSmx205022 	default:
25996f3e57acSmx205022 		return (DDI_FAILURE);
26006f3e57acSmx205022 
26016f3e57acSmx205022 	case DDI_SUSPEND:
26026f3e57acSmx205022 		/*
26036f3e57acSmx205022 		 * Stop the NIC
26046f3e57acSmx205022 		 * Note: This driver doesn't currently support WOL, but
26056f3e57acSmx205022 		 *	should it in the future, it is important to
26066f3e57acSmx205022 		 *	make sure the PHY remains powered so that the
26076f3e57acSmx205022 		 *	wakeup packet can actually be recieved.
26086f3e57acSmx205022 		 */
26092d58516dSmx205022 		return (nge_suspend(ngep));
26106f3e57acSmx205022 
26116f3e57acSmx205022 	case DDI_DETACH:
26126f3e57acSmx205022 		break;
26136f3e57acSmx205022 	}
26146f3e57acSmx205022 
26156f3e57acSmx205022 	/* Try to wait all the buffer post to upper layer be released */
26166f3e57acSmx205022 	for (i = 0; i < 1000; i++) {
26176f3e57acSmx205022 		if (brp->rx_hold == 0)
26186f3e57acSmx205022 			break;
26196f3e57acSmx205022 		drv_usecwait(1000);
26206f3e57acSmx205022 	}
26216f3e57acSmx205022 
26226f3e57acSmx205022 	/* If there is any posted buffer, reject to detach */
26236f3e57acSmx205022 	if (brp->rx_hold != 0)
26246f3e57acSmx205022 		return (DDI_FAILURE);
26256f3e57acSmx205022 
26266f3e57acSmx205022 	/*
26276f3e57acSmx205022 	 * Unregister from the GLD subsystem.  This can fail, in
26286f3e57acSmx205022 	 * particular if there are DLPI style-2 streams still open -
26296f3e57acSmx205022 	 * in which case we just return failure without shutting
26306f3e57acSmx205022 	 * down chip operations.
26316f3e57acSmx205022 	 */
26326f3e57acSmx205022 	if (mac_unregister(ngep->mh) != DDI_SUCCESS)
26336f3e57acSmx205022 		return (DDI_FAILURE);
26346f3e57acSmx205022 
26356f3e57acSmx205022 	/*
2636c322ff79Smx205022 	 * Recycle the multicast table. mac_unregister() should be called
2637c322ff79Smx205022 	 * before it to ensure the multicast table can be used even if
2638c322ff79Smx205022 	 * mac_unregister() fails.
2639c322ff79Smx205022 	 */
2640c322ff79Smx205022 	for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
2641c322ff79Smx205022 		nextp = p->next;
2642c322ff79Smx205022 		kmem_free(p, sizeof (mul_item));
2643c322ff79Smx205022 	}
2644c322ff79Smx205022 	ngep->pcur_mulist = NULL;
2645c322ff79Smx205022 
2646c322ff79Smx205022 	/*
26476f3e57acSmx205022 	 * All activity stopped, so we can clean up & exit
26486f3e57acSmx205022 	 */
26496f3e57acSmx205022 	nge_unattach(ngep);
26506f3e57acSmx205022 	return (DDI_SUCCESS);
26516f3e57acSmx205022 }
26526f3e57acSmx205022 
265319397407SSherry Moore /*
265419397407SSherry Moore  * quiesce(9E) entry point.
265519397407SSherry Moore  *
265619397407SSherry Moore  * This function is called when the system is single-threaded at high
265719397407SSherry Moore  * PIL with preemption disabled. Therefore, this function must not be
265819397407SSherry Moore  * blocked.
265919397407SSherry Moore  *
266019397407SSherry Moore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
266119397407SSherry Moore  * DDI_FAILURE indicates an error condition and should almost never happen.
266219397407SSherry Moore  */
266319397407SSherry Moore static int
266419397407SSherry Moore nge_quiesce(dev_info_t *devinfo)
266519397407SSherry Moore {
266619397407SSherry Moore 	nge_t *ngep;
266719397407SSherry Moore 
266819397407SSherry Moore 	ngep = ddi_get_driver_private(devinfo);
266919397407SSherry Moore 
267019397407SSherry Moore 	if (ngep == NULL)
267119397407SSherry Moore 		return (DDI_FAILURE);
267219397407SSherry Moore 
267319397407SSherry Moore 	/*
267419397407SSherry Moore 	 * Turn off debug tracing
267519397407SSherry Moore 	 */
267619397407SSherry Moore 	nge_debug = 0;
267719397407SSherry Moore 	ngep->debug = 0;
267819397407SSherry Moore 
267919397407SSherry Moore 	nge_restore_mac_addr(ngep);
268019397407SSherry Moore 	(void) nge_chip_stop(ngep, B_FALSE);
268119397407SSherry Moore 
268219397407SSherry Moore 	return (DDI_SUCCESS);
268319397407SSherry Moore }
268419397407SSherry Moore 
268519397407SSherry Moore 
26866f3e57acSmx205022 
26876f3e57acSmx205022 /*
26886f3e57acSmx205022  * ========== Module Loading Data & Entry Points ==========
26896f3e57acSmx205022  */
26906f3e57acSmx205022 
26916f3e57acSmx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
269219397407SSherry Moore     NULL, NULL, D_MP, NULL, nge_quiesce);
26936f3e57acSmx205022 
26946f3e57acSmx205022 
26956f3e57acSmx205022 static struct modldrv nge_modldrv = {
26966f3e57acSmx205022 	&mod_driverops,		/* Type of module.  This one is a driver */
26976f3e57acSmx205022 	nge_ident,		/* short description */
26986f3e57acSmx205022 	&nge_dev_ops		/* driver specific ops */
26996f3e57acSmx205022 };
27006f3e57acSmx205022 
27016f3e57acSmx205022 static struct modlinkage modlinkage = {
27026f3e57acSmx205022 	MODREV_1, (void *)&nge_modldrv, NULL
27036f3e57acSmx205022 };
27046f3e57acSmx205022 
27056f3e57acSmx205022 
27066f3e57acSmx205022 int
27076f3e57acSmx205022 _info(struct modinfo *modinfop)
27086f3e57acSmx205022 {
27096f3e57acSmx205022 	return (mod_info(&modlinkage, modinfop));
27106f3e57acSmx205022 }
27116f3e57acSmx205022 
27126f3e57acSmx205022 int
27136f3e57acSmx205022 _init(void)
27146f3e57acSmx205022 {
27156f3e57acSmx205022 	int status;
27166f3e57acSmx205022 
27176f3e57acSmx205022 	mac_init_ops(&nge_dev_ops, "nge");
27186f3e57acSmx205022 	status = mod_install(&modlinkage);
27196f3e57acSmx205022 	if (status != DDI_SUCCESS)
27206f3e57acSmx205022 		mac_fini_ops(&nge_dev_ops);
27216f3e57acSmx205022 	else
27226f3e57acSmx205022 		mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
27236f3e57acSmx205022 
27246f3e57acSmx205022 	return (status);
27256f3e57acSmx205022 }
27266f3e57acSmx205022 
27276f3e57acSmx205022 int
27286f3e57acSmx205022 _fini(void)
27296f3e57acSmx205022 {
27306f3e57acSmx205022 	int status;
27316f3e57acSmx205022 
27326f3e57acSmx205022 	status = mod_remove(&modlinkage);
27336f3e57acSmx205022 	if (status == DDI_SUCCESS) {
27346f3e57acSmx205022 		mac_fini_ops(&nge_dev_ops);
27356f3e57acSmx205022 		mutex_destroy(nge_log_mutex);
27366f3e57acSmx205022 	}
27376f3e57acSmx205022 
27386f3e57acSmx205022 	return (status);
27396f3e57acSmx205022 }
27406f3e57acSmx205022 
27416f3e57acSmx205022 /*
27426f3e57acSmx205022  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
27436f3e57acSmx205022  */
27446f3e57acSmx205022 
27456f3e57acSmx205022 /*
27466f3e57acSmx205022  * Register interrupts and initialize each mutex and condition variables
27476f3e57acSmx205022  */
27486f3e57acSmx205022 
27496f3e57acSmx205022 static int
27506f3e57acSmx205022 nge_register_intrs_and_init_locks(nge_t *ngep)
27516f3e57acSmx205022 {
27526f3e57acSmx205022 	int		err;
27536f3e57acSmx205022 	int		intr_types;
27546f3e57acSmx205022 	uint_t		soft_prip;
27556f3e57acSmx205022 	nge_msi_mask	msi_mask;
27566f3e57acSmx205022 	nge_msi_map0_vec map0_vec;
27576f3e57acSmx205022 	nge_msi_map1_vec map1_vec;
27586f3e57acSmx205022 
27596f3e57acSmx205022 	/*
27606f3e57acSmx205022 	 * Add the softint handlers:
27616f3e57acSmx205022 	 *
27626f3e57acSmx205022 	 * Both of these handlers are used to avoid restrictions on the
27636f3e57acSmx205022 	 * context and/or mutexes required for some operations.  In
27646f3e57acSmx205022 	 * particular, the hardware interrupt handler and its subfunctions
27656f3e57acSmx205022 	 * can detect a number of conditions that we don't want to handle
27666f3e57acSmx205022 	 * in that context or with that set of mutexes held.  So, these
27676f3e57acSmx205022 	 * softints are triggered instead:
27686f3e57acSmx205022 	 *
27696f3e57acSmx205022 	 * the <resched> softint is triggered if if we have previously
27706f3e57acSmx205022 	 * had to refuse to send a packet because of resource shortage
27716f3e57acSmx205022 	 * (we've run out of transmit buffers), but the send completion
27726f3e57acSmx205022 	 * interrupt handler has now detected that more buffers have
27736f3e57acSmx205022 	 * become available.  Its only purpose is to call gld_sched()
27746f3e57acSmx205022 	 * to retry the pending transmits (we're not allowed to hold
27756f3e57acSmx205022 	 * driver-defined mutexes across gld_sched()).
27766f3e57acSmx205022 	 *
27776f3e57acSmx205022 	 * the <factotum> is triggered if the h/w interrupt handler
27786f3e57acSmx205022 	 * sees the <link state changed> or <error> bits in the status
27796f3e57acSmx205022 	 * block.  It's also triggered periodically to poll the link
27806f3e57acSmx205022 	 * state, just in case we aren't getting link status change
27816f3e57acSmx205022 	 * interrupts ...
27826f3e57acSmx205022 	 */
27836f3e57acSmx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
27846f3e57acSmx205022 	    DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
27856f3e57acSmx205022 	if (err != DDI_SUCCESS) {
27866f3e57acSmx205022 		nge_problem(ngep,
27876f3e57acSmx205022 		    "nge_attach: add nge_reschedule softintr failed");
27886f3e57acSmx205022 
27896f3e57acSmx205022 		return (DDI_FAILURE);
27906f3e57acSmx205022 	}
27916f3e57acSmx205022 	ngep->progress |= PROGRESS_RESCHED;
27926f3e57acSmx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
27936f3e57acSmx205022 	    DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
27946f3e57acSmx205022 	if (err != DDI_SUCCESS) {
27956f3e57acSmx205022 		nge_problem(ngep,
27966f3e57acSmx205022 		    "nge_attach: add nge_chip_factotum softintr failed!");
27976f3e57acSmx205022 
27986f3e57acSmx205022 		return (DDI_FAILURE);
27996f3e57acSmx205022 	}
28006f3e57acSmx205022 	if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
28016f3e57acSmx205022 	    != DDI_SUCCESS) {
28026f3e57acSmx205022 		nge_problem(ngep, "nge_attach: get softintr priority failed\n");
28036f3e57acSmx205022 
28046f3e57acSmx205022 		return (DDI_FAILURE);
28056f3e57acSmx205022 	}
28066f3e57acSmx205022 	ngep->soft_pri = soft_prip;
28076f3e57acSmx205022 
28086f3e57acSmx205022 	ngep->progress |= PROGRESS_FACTOTUM;
28096f3e57acSmx205022 	/* Get supported interrupt types */
28106f3e57acSmx205022 	if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
28116f3e57acSmx205022 	    != DDI_SUCCESS) {
28126f3e57acSmx205022 		nge_error(ngep, "ddi_intr_get_supported_types failed\n");
28136f3e57acSmx205022 
28146f3e57acSmx205022 		return (DDI_FAILURE);
28156f3e57acSmx205022 	}
28166f3e57acSmx205022 
28176f3e57acSmx205022 	NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
28186f3e57acSmx205022 	    intr_types));
28196f3e57acSmx205022 
28206f3e57acSmx205022 	if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
28216f3e57acSmx205022 
28226f3e57acSmx205022 		/* MSI Configurations for mcp55 chipset */
28236f3e57acSmx205022 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
28246f3e57acSmx205022 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
28256f3e57acSmx205022 
28266f3e57acSmx205022 
28276f3e57acSmx205022 			/* Enable the 8 vectors */
28286f3e57acSmx205022 			msi_mask.msi_mask_val =
28296f3e57acSmx205022 			    nge_reg_get32(ngep, NGE_MSI_MASK);
28306f3e57acSmx205022 			msi_mask.msi_msk_bits.vec0 = NGE_SET;
28316f3e57acSmx205022 			msi_mask.msi_msk_bits.vec1 = NGE_SET;
28326f3e57acSmx205022 			msi_mask.msi_msk_bits.vec2 = NGE_SET;
28336f3e57acSmx205022 			msi_mask.msi_msk_bits.vec3 = NGE_SET;
28346f3e57acSmx205022 			msi_mask.msi_msk_bits.vec4 = NGE_SET;
28356f3e57acSmx205022 			msi_mask.msi_msk_bits.vec5 = NGE_SET;
28366f3e57acSmx205022 			msi_mask.msi_msk_bits.vec6 = NGE_SET;
28376f3e57acSmx205022 			msi_mask.msi_msk_bits.vec7 = NGE_SET;
28386f3e57acSmx205022 			nge_reg_put32(ngep, NGE_MSI_MASK,
28396f3e57acSmx205022 			    msi_mask.msi_mask_val);
28406f3e57acSmx205022 
28416f3e57acSmx205022 			/*
28426f3e57acSmx205022 			 * Remapping the MSI MAP0 and MAP1. MCP55
28436f3e57acSmx205022 			 * is default mapping all the interrupt to 0 vector.
28446f3e57acSmx205022 			 * Software needs to remapping this.
28456f3e57acSmx205022 			 * This mapping is same as CK804.
28466f3e57acSmx205022 			 */
28476f3e57acSmx205022 			map0_vec.msi_map0_val =
28486f3e57acSmx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP0);
28496f3e57acSmx205022 			map1_vec.msi_map1_val =
28506f3e57acSmx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP1);
28516f3e57acSmx205022 			map0_vec.vecs_bits.reint_vec = 0;
28526f3e57acSmx205022 			map0_vec.vecs_bits.rcint_vec = 0;
28536f3e57acSmx205022 			map0_vec.vecs_bits.miss_vec = 3;
28546f3e57acSmx205022 			map0_vec.vecs_bits.teint_vec = 5;
28556f3e57acSmx205022 			map0_vec.vecs_bits.tcint_vec = 5;
28566f3e57acSmx205022 			map0_vec.vecs_bits.stint_vec = 2;
28576f3e57acSmx205022 			map0_vec.vecs_bits.mint_vec = 6;
28586f3e57acSmx205022 			map0_vec.vecs_bits.rfint_vec = 0;
28596f3e57acSmx205022 			map1_vec.vecs_bits.tfint_vec = 5;
28606f3e57acSmx205022 			map1_vec.vecs_bits.feint_vec = 6;
28616f3e57acSmx205022 			map1_vec.vecs_bits.resv8_11 = 3;
28626f3e57acSmx205022 			map1_vec.vecs_bits.resv12_15 = 1;
28636f3e57acSmx205022 			map1_vec.vecs_bits.resv16_19 = 0;
28646f3e57acSmx205022 			map1_vec.vecs_bits.resv20_23 = 7;
28656f3e57acSmx205022 			map1_vec.vecs_bits.resv24_31 = 0xff;
28666f3e57acSmx205022 			nge_reg_put32(ngep, NGE_MSI_MAP0,
28676f3e57acSmx205022 			    map0_vec.msi_map0_val);
28686f3e57acSmx205022 			nge_reg_put32(ngep, NGE_MSI_MAP1,
28696f3e57acSmx205022 			    map1_vec.msi_map1_val);
28706f3e57acSmx205022 		}
28716f3e57acSmx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
28726f3e57acSmx205022 			NGE_DEBUG(("MSI registration failed, "
28736f3e57acSmx205022 			    "trying FIXED interrupt type\n"));
28746f3e57acSmx205022 		} else {
28756f3e57acSmx205022 			nge_log(ngep, "Using MSI interrupt type\n");
28766f3e57acSmx205022 
28776f3e57acSmx205022 			ngep->intr_type = DDI_INTR_TYPE_MSI;
28786f3e57acSmx205022 			ngep->progress |= PROGRESS_SWINT;
28796f3e57acSmx205022 		}
28806f3e57acSmx205022 	}
28816f3e57acSmx205022 
28826f3e57acSmx205022 	if (!(ngep->progress & PROGRESS_SWINT) &&
28836f3e57acSmx205022 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
28846f3e57acSmx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
28856f3e57acSmx205022 			nge_error(ngep, "FIXED interrupt "
28866f3e57acSmx205022 			    "registration failed\n");
28876f3e57acSmx205022 
28886f3e57acSmx205022 			return (DDI_FAILURE);
28896f3e57acSmx205022 		}
28906f3e57acSmx205022 
28916f3e57acSmx205022 		nge_log(ngep, "Using FIXED interrupt type\n");
28926f3e57acSmx205022 
28936f3e57acSmx205022 		ngep->intr_type = DDI_INTR_TYPE_FIXED;
28946f3e57acSmx205022 		ngep->progress |= PROGRESS_SWINT;
28956f3e57acSmx205022 	}
28966f3e57acSmx205022 
28976f3e57acSmx205022 
28986f3e57acSmx205022 	if (!(ngep->progress & PROGRESS_SWINT)) {
28996f3e57acSmx205022 		nge_error(ngep, "No interrupts registered\n");
29006f3e57acSmx205022 
29016f3e57acSmx205022 		return (DDI_FAILURE);
29026f3e57acSmx205022 	}
29036f3e57acSmx205022 	mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
29046f3e57acSmx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29056f3e57acSmx205022 	mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
29066f3e57acSmx205022 	    DDI_INTR_PRI(ngep->soft_pri));
29076f3e57acSmx205022 	rw_init(ngep->rwlock, NULL, RW_DRIVER,
29086f3e57acSmx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29096f3e57acSmx205022 
29106f3e57acSmx205022 	return (DDI_SUCCESS);
29116f3e57acSmx205022 }
29126f3e57acSmx205022 
29136f3e57acSmx205022 /*
29146f3e57acSmx205022  * nge_add_intrs:
29156f3e57acSmx205022  *
29166f3e57acSmx205022  * Register FIXED or MSI interrupts.
29176f3e57acSmx205022  */
29186f3e57acSmx205022 static int
29196f3e57acSmx205022 nge_add_intrs(nge_t *ngep, int	intr_type)
29206f3e57acSmx205022 {
29216f3e57acSmx205022 	dev_info_t	*dip = ngep->devinfo;
29226f3e57acSmx205022 	int		avail, actual, intr_size, count = 0;
29236f3e57acSmx205022 	int		i, flag, ret;
29246f3e57acSmx205022 
29256f3e57acSmx205022 	NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
29266f3e57acSmx205022 
29276f3e57acSmx205022 	/* Get number of interrupts */
29286f3e57acSmx205022 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
29296f3e57acSmx205022 	if ((ret != DDI_SUCCESS) || (count == 0)) {
29306f3e57acSmx205022 		nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
29316f3e57acSmx205022 		    "count: %d", ret, count);
29326f3e57acSmx205022 
29336f3e57acSmx205022 		return (DDI_FAILURE);
29346f3e57acSmx205022 	}
29356f3e57acSmx205022 
29366f3e57acSmx205022 	/* Get number of available interrupts */
29376f3e57acSmx205022 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
29386f3e57acSmx205022 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
29396f3e57acSmx205022 		nge_error(ngep, "ddi_intr_get_navail() failure, "
29406f3e57acSmx205022 		    "ret: %d, avail: %d\n", ret, avail);
29416f3e57acSmx205022 
29426f3e57acSmx205022 		return (DDI_FAILURE);
29436f3e57acSmx205022 	}
29446f3e57acSmx205022 
29456f3e57acSmx205022 	if (avail < count) {
29466f3e57acSmx205022 		NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
29476f3e57acSmx205022 		    count, avail));
29486f3e57acSmx205022 	}
29496f3e57acSmx205022 	flag = DDI_INTR_ALLOC_NORMAL;
29506f3e57acSmx205022 
29516f3e57acSmx205022 	/* Allocate an array of interrupt handles */
29526f3e57acSmx205022 	intr_size = count * sizeof (ddi_intr_handle_t);
29536f3e57acSmx205022 	ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
29546f3e57acSmx205022 
29556f3e57acSmx205022 	/* Call ddi_intr_alloc() */
29566f3e57acSmx205022 	ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
29576f3e57acSmx205022 	    count, &actual, flag);
29586f3e57acSmx205022 
29596f3e57acSmx205022 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
29606f3e57acSmx205022 		nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
29616f3e57acSmx205022 
29626f3e57acSmx205022 		kmem_free(ngep->htable, intr_size);
29636f3e57acSmx205022 		return (DDI_FAILURE);
29646f3e57acSmx205022 	}
29656f3e57acSmx205022 
29666f3e57acSmx205022 	if (actual < count) {
29676f3e57acSmx205022 		NGE_DEBUG(("Requested: %d, Received: %d\n",
29686f3e57acSmx205022 		    count, actual));
29696f3e57acSmx205022 	}
29706f3e57acSmx205022 
29716f3e57acSmx205022 	ngep->intr_actual_cnt = actual;
29726f3e57acSmx205022 	ngep->intr_req_cnt = count;
29736f3e57acSmx205022 
29746f3e57acSmx205022 	/*
29756f3e57acSmx205022 	 * Get priority for first msi, assume remaining are all the same
29766f3e57acSmx205022 	 */
29776f3e57acSmx205022 	if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
29786f3e57acSmx205022 	    DDI_SUCCESS) {
29796f3e57acSmx205022 		nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
29806f3e57acSmx205022 
29816f3e57acSmx205022 		/* Free already allocated intr */
29826f3e57acSmx205022 		for (i = 0; i < actual; i++) {
29836f3e57acSmx205022 			(void) ddi_intr_free(ngep->htable[i]);
29846f3e57acSmx205022 		}
29856f3e57acSmx205022 
29866f3e57acSmx205022 		kmem_free(ngep->htable, intr_size);
29876f3e57acSmx205022 
29886f3e57acSmx205022 		return (DDI_FAILURE);
29896f3e57acSmx205022 	}
29906f3e57acSmx205022 	/* Test for high level mutex */
29916f3e57acSmx205022 	if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
29926f3e57acSmx205022 		nge_error(ngep, "nge_add_intrs:"
29936f3e57acSmx205022 		    "Hi level interrupt not supported");
29946f3e57acSmx205022 
29956f3e57acSmx205022 		for (i = 0; i < actual; i++)
29966f3e57acSmx205022 			(void) ddi_intr_free(ngep->htable[i]);
29976f3e57acSmx205022 
29986f3e57acSmx205022 		kmem_free(ngep->htable, intr_size);
29996f3e57acSmx205022 
30006f3e57acSmx205022 		return (DDI_FAILURE);
30016f3e57acSmx205022 	}
30026f3e57acSmx205022 
30036f3e57acSmx205022 
30046f3e57acSmx205022 	/* Call ddi_intr_add_handler() */
30056f3e57acSmx205022 	for (i = 0; i < actual; i++) {
30066f3e57acSmx205022 		if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
30076f3e57acSmx205022 		    (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
30086f3e57acSmx205022 			nge_error(ngep, "ddi_intr_add_handler() "
30096f3e57acSmx205022 			    "failed %d\n", ret);
30106f3e57acSmx205022 
30116f3e57acSmx205022 			/* Free already allocated intr */
30126f3e57acSmx205022 			for (i = 0; i < actual; i++) {
30136f3e57acSmx205022 				(void) ddi_intr_free(ngep->htable[i]);
30146f3e57acSmx205022 			}
30156f3e57acSmx205022 
30166f3e57acSmx205022 			kmem_free(ngep->htable, intr_size);
30176f3e57acSmx205022 
30186f3e57acSmx205022 			return (DDI_FAILURE);
30196f3e57acSmx205022 		}
30206f3e57acSmx205022 	}
30216f3e57acSmx205022 
30226f3e57acSmx205022 	if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
30236f3e57acSmx205022 	    != DDI_SUCCESS) {
30246f3e57acSmx205022 		nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
30256f3e57acSmx205022 
30266f3e57acSmx205022 		for (i = 0; i < actual; i++) {
30276f3e57acSmx205022 			(void) ddi_intr_remove_handler(ngep->htable[i]);
30286f3e57acSmx205022 			(void) ddi_intr_free(ngep->htable[i]);
30296f3e57acSmx205022 		}
30306f3e57acSmx205022 
30316f3e57acSmx205022 		kmem_free(ngep->htable, intr_size);
30326f3e57acSmx205022 
30336f3e57acSmx205022 		return (DDI_FAILURE);
30346f3e57acSmx205022 	}
30356f3e57acSmx205022 
30366f3e57acSmx205022 	return (DDI_SUCCESS);
30376f3e57acSmx205022 }
30386f3e57acSmx205022 
30396f3e57acSmx205022 /*
30406f3e57acSmx205022  * nge_rem_intrs:
30416f3e57acSmx205022  *
30426f3e57acSmx205022  * Unregister FIXED or MSI interrupts
30436f3e57acSmx205022  */
30446f3e57acSmx205022 static void
30456f3e57acSmx205022 nge_rem_intrs(nge_t *ngep)
30466f3e57acSmx205022 {
30476f3e57acSmx205022 	int	i;
30486f3e57acSmx205022 
30496f3e57acSmx205022 	NGE_DEBUG(("nge_rem_intrs\n"));
30506f3e57acSmx205022 
30516f3e57acSmx205022 	/* Disable all interrupts */
30526f3e57acSmx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
30536f3e57acSmx205022 		/* Call ddi_intr_block_disable() */
30546f3e57acSmx205022 		(void) ddi_intr_block_disable(ngep->htable,
30556f3e57acSmx205022 		    ngep->intr_actual_cnt);
30566f3e57acSmx205022 	} else {
30576f3e57acSmx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
30586f3e57acSmx205022 			(void) ddi_intr_disable(ngep->htable[i]);
30596f3e57acSmx205022 		}
30606f3e57acSmx205022 	}
30616f3e57acSmx205022 
30626f3e57acSmx205022 	/* Call ddi_intr_remove_handler() */
30636f3e57acSmx205022 	for (i = 0; i < ngep->intr_actual_cnt; i++) {
30646f3e57acSmx205022 		(void) ddi_intr_remove_handler(ngep->htable[i]);
30656f3e57acSmx205022 		(void) ddi_intr_free(ngep->htable[i]);
30666f3e57acSmx205022 	}
30676f3e57acSmx205022 
30686f3e57acSmx205022 	kmem_free(ngep->htable,
30696f3e57acSmx205022 	    ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
30706f3e57acSmx205022 }
3071