xref: /onnv-gate/usr/src/uts/common/io/nge/nge_main.c (revision 11878:ac93462db6d7)
15578Smx205022 /*
25578Smx205022  * CDDL HEADER START
35578Smx205022  *
45578Smx205022  * The contents of this file are subject to the terms of the
55578Smx205022  * Common Development and Distribution License (the "License").
65578Smx205022  * You may not use this file except in compliance with the License.
75578Smx205022  *
85578Smx205022  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95578Smx205022  * or http://www.opensolaris.org/os/licensing.
105578Smx205022  * See the License for the specific language governing permissions
115578Smx205022  * and limitations under the License.
125578Smx205022  *
135578Smx205022  * When distributing Covered Code, include this CDDL HEADER in each
145578Smx205022  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155578Smx205022  * If applicable, add the following below this CDDL HEADER, with the
165578Smx205022  * fields enclosed by brackets "[]" replaced with your own identifying
175578Smx205022  * information: Portions Copyright [yyyy] [name of copyright owner]
185578Smx205022  *
195578Smx205022  * CDDL HEADER END
205578Smx205022  */
215578Smx205022 
225574Smx205022 /*
23*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
245574Smx205022  * Use is subject to license terms.
255574Smx205022  */
265574Smx205022 
275574Smx205022 
285574Smx205022 #include "nge.h"
295574Smx205022 
305574Smx205022 /*
315574Smx205022  * Describes the chip's DMA engine
325574Smx205022  */
335574Smx205022 
345574Smx205022 static ddi_dma_attr_t hot_dma_attr = {
355574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
365574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
375574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
385574Smx205022 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
395574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
405574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
415574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
425574Smx205022 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
435574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
445574Smx205022 	1,				/* dma_attr_sgllen 	*/
455574Smx205022 	0x00000001,			/* dma_attr_granular 	*/
465574Smx205022 	0
475574Smx205022 };
485574Smx205022 
495574Smx205022 static ddi_dma_attr_t hot_tx_dma_attr = {
505574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
515574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
525574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
535574Smx205022 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
545574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
555574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
565574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
575574Smx205022 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
585574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
595574Smx205022 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
605574Smx205022 	1,				/* dma_attr_granular 	*/
615574Smx205022 	0
625574Smx205022 };
635574Smx205022 
645574Smx205022 static ddi_dma_attr_t sum_dma_attr = {
655574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
665574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
675574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
685574Smx205022 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
695574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
705574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
715574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
725574Smx205022 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
735574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
745574Smx205022 	1,				/* dma_attr_sgllen 	*/
755574Smx205022 	0x00000001,			/* dma_attr_granular 	*/
765574Smx205022 	0
775574Smx205022 };
785574Smx205022 
795574Smx205022 static ddi_dma_attr_t sum_tx_dma_attr = {
805574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
815574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
825574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
835574Smx205022 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
845574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
855574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
865574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
875574Smx205022 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
885574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
895574Smx205022 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
905574Smx205022 	1,				/* dma_attr_granular 	*/
915574Smx205022 	0
925574Smx205022 };
935574Smx205022 
945574Smx205022 /*
955574Smx205022  * DMA access attributes for data.
965574Smx205022  */
975574Smx205022 ddi_device_acc_attr_t nge_data_accattr = {
985574Smx205022 	DDI_DEVICE_ATTR_V0,
995574Smx205022 	DDI_STRUCTURE_LE_ACC,
1005574Smx205022 	DDI_STRICTORDER_ACC,
1015574Smx205022 	DDI_DEFAULT_ACC
1025574Smx205022 };
1035574Smx205022 
1045574Smx205022 /*
1055574Smx205022  * DMA access attributes for descriptors.
1065574Smx205022  */
1075574Smx205022 static ddi_device_acc_attr_t nge_desc_accattr = {
1085574Smx205022 	DDI_DEVICE_ATTR_V0,
1095574Smx205022 	DDI_STRUCTURE_LE_ACC,
1105574Smx205022 	DDI_STRICTORDER_ACC,
1115574Smx205022 	DDI_DEFAULT_ACC
1125574Smx205022 };
1135574Smx205022 
1145574Smx205022 /*
1155574Smx205022  * PIO access attributes for registers
1165574Smx205022  */
1175574Smx205022 static ddi_device_acc_attr_t nge_reg_accattr = {
1185574Smx205022 	DDI_DEVICE_ATTR_V0,
1195574Smx205022 	DDI_STRUCTURE_LE_ACC,
1205574Smx205022 	DDI_STRICTORDER_ACC,
1215574Smx205022 	DDI_DEFAULT_ACC
1225574Smx205022 };
1235574Smx205022 
1245574Smx205022 /*
1255574Smx205022  * NIC DESC MODE 2
1265574Smx205022  */
1275574Smx205022 
1285574Smx205022 static const nge_desc_attr_t nge_sum_desc = {
1295574Smx205022 
1305574Smx205022 	sizeof (sum_rx_bd),
1315574Smx205022 	sizeof (sum_tx_bd),
1325574Smx205022 	&sum_dma_attr,
1335574Smx205022 	&sum_tx_dma_attr,
1345574Smx205022 	nge_sum_rxd_fill,
1355574Smx205022 	nge_sum_rxd_check,
1365574Smx205022 	nge_sum_txd_fill,
1375574Smx205022 	nge_sum_txd_check,
1385574Smx205022 };
1395574Smx205022 
1405574Smx205022 /*
1415574Smx205022  * NIC DESC MODE 3
1425574Smx205022  */
1435574Smx205022 
1445574Smx205022 static const nge_desc_attr_t nge_hot_desc = {
1455574Smx205022 
1465574Smx205022 	sizeof (hot_rx_bd),
1475574Smx205022 	sizeof (hot_tx_bd),
1485574Smx205022 	&hot_dma_attr,
1495574Smx205022 	&hot_tx_dma_attr,
1505574Smx205022 	nge_hot_rxd_fill,
1515574Smx205022 	nge_hot_rxd_check,
1525574Smx205022 	nge_hot_txd_fill,
1535574Smx205022 	nge_hot_txd_check,
1545574Smx205022 };
1555574Smx205022 
1566512Ssowmini static char nge_ident[] = "nVidia 1Gb Ethernet";
1575574Smx205022 static char clsize_propname[] = "cache-line-size";
1585574Smx205022 static char latency_propname[] = "latency-timer";
1595574Smx205022 static char debug_propname[]	= "nge-debug-flags";
1605659Sjj146644 static char intr_moderation[] = "intr-moderation";
1615574Smx205022 static char rx_data_hw[] = "rx-data-hw";
1625574Smx205022 static char rx_prd_lw[] = "rx-prd-lw";
1635574Smx205022 static char rx_prd_hw[] = "rx-prd-hw";
1645574Smx205022 static char sw_intr_intv[] = "sw-intr-intvl";
1655574Smx205022 static char nge_desc_mode[] = "desc-mode";
1665574Smx205022 static char default_mtu[] = "default_mtu";
1675574Smx205022 static char low_memory_mode[] = "minimal-memory-usage";
1685574Smx205022 extern kmutex_t nge_log_mutex[1];
1695574Smx205022 
1705574Smx205022 static int		nge_m_start(void *);
1715574Smx205022 static void		nge_m_stop(void *);
1725574Smx205022 static int		nge_m_promisc(void *, boolean_t);
1735574Smx205022 static int		nge_m_multicst(void *, boolean_t, const uint8_t *);
1745574Smx205022 static int		nge_m_unicst(void *, const uint8_t *);
1755574Smx205022 static void		nge_m_ioctl(void *, queue_t *, mblk_t *);
1765574Smx205022 static boolean_t	nge_m_getcapab(void *, mac_capab_t, void *);
1776200Smx205022 static int		nge_m_setprop(void *, const char *, mac_prop_id_t,
1786200Smx205022 	uint_t, const void *);
1796200Smx205022 static int		nge_m_getprop(void *, const char *, mac_prop_id_t,
180*11878SVenu.Iyer@Sun.COM 	uint_t, void *);
181*11878SVenu.Iyer@Sun.COM static void		nge_m_propinfo(void *, const char *, mac_prop_id_t,
182*11878SVenu.Iyer@Sun.COM 	mac_prop_info_handle_t);
1836200Smx205022 static int		nge_set_priv_prop(nge_t *, const char *, uint_t,
1846200Smx205022 	const void *);
1856200Smx205022 static int		nge_get_priv_prop(nge_t *, const char *, uint_t,
186*11878SVenu.Iyer@Sun.COM 	void *);
1876200Smx205022 
1886200Smx205022 #define		NGE_M_CALLBACK_FLAGS\
189*11878SVenu.Iyer@Sun.COM 		(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | \
190*11878SVenu.Iyer@Sun.COM 		MC_PROPINFO)
1915574Smx205022 
1925574Smx205022 static mac_callbacks_t nge_m_callbacks = {
1935574Smx205022 	NGE_M_CALLBACK_FLAGS,
1945574Smx205022 	nge_m_stat,
1955574Smx205022 	nge_m_start,
1965574Smx205022 	nge_m_stop,
1975574Smx205022 	nge_m_promisc,
1985574Smx205022 	nge_m_multicst,
1995574Smx205022 	nge_m_unicst,
2005574Smx205022 	nge_m_tx,
201*11878SVenu.Iyer@Sun.COM 	NULL,
2025574Smx205022 	nge_m_ioctl,
2036200Smx205022 	nge_m_getcapab,
2046200Smx205022 	NULL,
2056200Smx205022 	NULL,
2066200Smx205022 	nge_m_setprop,
207*11878SVenu.Iyer@Sun.COM 	nge_m_getprop,
208*11878SVenu.Iyer@Sun.COM 	nge_m_propinfo
2095574Smx205022 };
2105574Smx205022 
211*11878SVenu.Iyer@Sun.COM char *nge_priv_props[] = {
212*11878SVenu.Iyer@Sun.COM 	"_tx_bcopy_threshold",
213*11878SVenu.Iyer@Sun.COM 	"_rx_bcopy_threshold",
214*11878SVenu.Iyer@Sun.COM 	"_recv_max_packet",
215*11878SVenu.Iyer@Sun.COM 	"_poll_quiet_time",
216*11878SVenu.Iyer@Sun.COM 	"_poll_busy_time",
217*11878SVenu.Iyer@Sun.COM 	"_rx_intr_hwater",
218*11878SVenu.Iyer@Sun.COM 	"_rx_intr_lwater",
219*11878SVenu.Iyer@Sun.COM 	NULL
2206512Ssowmini };
2216512Ssowmini 
2225574Smx205022 static int nge_add_intrs(nge_t *, int);
2235574Smx205022 static void nge_rem_intrs(nge_t *);
2245574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *);
2255574Smx205022 
2265574Smx205022 /*
2275574Smx205022  * NGE MSI tunable:
2285574Smx205022  */
2295574Smx205022 boolean_t nge_enable_msi = B_FALSE;
2305574Smx205022 
2315574Smx205022 static enum ioc_reply
nge_set_loop_mode(nge_t * ngep,uint32_t mode)2325574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
2335574Smx205022 {
2345574Smx205022 	/*
2355574Smx205022 	 * If the mode isn't being changed, there's nothing to do ...
2365574Smx205022 	 */
2375574Smx205022 	if (mode == ngep->param_loop_mode)
2385574Smx205022 		return (IOC_ACK);
2395574Smx205022 
2405574Smx205022 	/*
2415574Smx205022 	 * Validate the requested mode and prepare a suitable message
2425574Smx205022 	 * to explain the link down/up cycle that the change will
2435574Smx205022 	 * probably induce ...
2445574Smx205022 	 */
2455574Smx205022 	switch (mode) {
2465574Smx205022 	default:
2475574Smx205022 		return (IOC_INVAL);
2485574Smx205022 
2495574Smx205022 	case NGE_LOOP_NONE:
2505574Smx205022 	case NGE_LOOP_EXTERNAL_100:
2515574Smx205022 	case NGE_LOOP_EXTERNAL_10:
2525574Smx205022 	case NGE_LOOP_INTERNAL_PHY:
2535574Smx205022 		break;
2545574Smx205022 	}
2555574Smx205022 
2565574Smx205022 	/*
2575574Smx205022 	 * All OK; tell the caller to reprogram
2585574Smx205022 	 * the PHY and/or MAC for the new mode ...
2595574Smx205022 	 */
2605574Smx205022 	ngep->param_loop_mode = mode;
2615574Smx205022 	return (IOC_RESTART_ACK);
2625574Smx205022 }
2635574Smx205022 
2645574Smx205022 #undef	NGE_DBG
2655574Smx205022 #define	NGE_DBG		NGE_DBG_INIT
2665574Smx205022 
2675574Smx205022 /*
2685574Smx205022  * Utility routine to carve a slice off a chunk of allocated memory,
2695574Smx205022  * updating the chunk descriptor accordingly.  The size of the slice
2705574Smx205022  * is given by the product of the <qty> and <size> parameters.
2715574Smx205022  */
2725574Smx205022 void
nge_slice_chunk(dma_area_t * slice,dma_area_t * chunk,uint32_t qty,uint32_t size)2735574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
2745574Smx205022     uint32_t qty, uint32_t size)
2755574Smx205022 {
2765574Smx205022 	size_t totsize;
2775574Smx205022 
2785574Smx205022 	totsize = qty*size;
2795574Smx205022 	ASSERT(size > 0);
2805574Smx205022 	ASSERT(totsize <= chunk->alength);
2815574Smx205022 
2825574Smx205022 	*slice = *chunk;
2835574Smx205022 	slice->nslots = qty;
2845574Smx205022 	slice->size = size;
2855574Smx205022 	slice->alength = totsize;
2865574Smx205022 
2875574Smx205022 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
2885574Smx205022 	chunk->alength -= totsize;
2895574Smx205022 	chunk->offset += totsize;
2905574Smx205022 	chunk->cookie.dmac_laddress += totsize;
2915574Smx205022 	chunk->cookie.dmac_size -= totsize;
2925574Smx205022 }
2935574Smx205022 
2945574Smx205022 /*
2955574Smx205022  * Allocate an area of memory and a DMA handle for accessing it
2965574Smx205022  */
2975574Smx205022 int
nge_alloc_dma_mem(nge_t * ngep,size_t memsize,ddi_device_acc_attr_t * attr_p,uint_t dma_flags,dma_area_t * dma_p)2985574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
2995574Smx205022     uint_t dma_flags, dma_area_t *dma_p)
3005574Smx205022 {
3015574Smx205022 	int err;
3025574Smx205022 	caddr_t va;
3035574Smx205022 
3045574Smx205022 	NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
3055574Smx205022 	    (void *)ngep, memsize, attr_p, dma_flags, dma_p));
3065574Smx205022 	/*
3075574Smx205022 	 * Allocate handle
3085574Smx205022 	 */
3095574Smx205022 	err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
3105574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
3115574Smx205022 	if (err != DDI_SUCCESS)
3125574Smx205022 		goto fail;
3135574Smx205022 
3145574Smx205022 	/*
3155574Smx205022 	 * Allocate memory
3165574Smx205022 	 */
3175574Smx205022 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
3185574Smx205022 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
3195574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
3205574Smx205022 	if (err != DDI_SUCCESS)
3215574Smx205022 		goto fail;
3225574Smx205022 
3235574Smx205022 	/*
3245574Smx205022 	 * Bind the two together
3255574Smx205022 	 */
3265574Smx205022 	dma_p->mem_va = va;
3275574Smx205022 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
3285574Smx205022 	    va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
3295574Smx205022 	    &dma_p->cookie, &dma_p->ncookies);
3305574Smx205022 
3315574Smx205022 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
3325574Smx205022 		goto fail;
3335574Smx205022 
3345574Smx205022 	dma_p->nslots = ~0U;
3355574Smx205022 	dma_p->size = ~0U;
3365574Smx205022 	dma_p->offset = 0;
3375574Smx205022 
3385574Smx205022 	return (DDI_SUCCESS);
3395574Smx205022 
3405574Smx205022 fail:
3415574Smx205022 	nge_free_dma_mem(dma_p);
3425574Smx205022 	NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
3435574Smx205022 
3445574Smx205022 	return (DDI_FAILURE);
3455574Smx205022 }
3465574Smx205022 
3475574Smx205022 /*
3485574Smx205022  * Free one allocated area of DMAable memory
3495574Smx205022  */
3505574Smx205022 void
nge_free_dma_mem(dma_area_t * dma_p)3515574Smx205022 nge_free_dma_mem(dma_area_t *dma_p)
3525574Smx205022 {
3535574Smx205022 	if (dma_p->dma_hdl != NULL) {
3545574Smx205022 		if (dma_p->ncookies) {
3555574Smx205022 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
3565574Smx205022 			dma_p->ncookies = 0;
3575574Smx205022 		}
3585574Smx205022 	}
3595574Smx205022 	if (dma_p->acc_hdl != NULL) {
3605574Smx205022 		ddi_dma_mem_free(&dma_p->acc_hdl);
3615574Smx205022 		dma_p->acc_hdl = NULL;
3625574Smx205022 	}
3635574Smx205022 	if (dma_p->dma_hdl != NULL) {
3645574Smx205022 		ddi_dma_free_handle(&dma_p->dma_hdl);
3655574Smx205022 		dma_p->dma_hdl = NULL;
3665574Smx205022 	}
3675574Smx205022 }
3685574Smx205022 
3695574Smx205022 #define	ALLOC_TX_BUF	0x1
3705574Smx205022 #define	ALLOC_TX_DESC	0x2
3715574Smx205022 #define	ALLOC_RX_DESC	0x4
3725574Smx205022 
3735574Smx205022 int
nge_alloc_bufs(nge_t * ngep)3745574Smx205022 nge_alloc_bufs(nge_t *ngep)
3755574Smx205022 {
3765574Smx205022 	int err;
3775574Smx205022 	int split;
3785574Smx205022 	int progress;
3795574Smx205022 	size_t txbuffsize;
3805574Smx205022 	size_t rxdescsize;
3815574Smx205022 	size_t txdescsize;
3825574Smx205022 
3835574Smx205022 	txbuffsize = ngep->tx_desc * ngep->buf_size;
3845574Smx205022 	rxdescsize = ngep->rx_desc;
3855574Smx205022 	txdescsize = ngep->tx_desc;
3865574Smx205022 	rxdescsize *= ngep->desc_attr.rxd_size;
3875574Smx205022 	txdescsize *= ngep->desc_attr.txd_size;
3885574Smx205022 	progress = 0;
3895574Smx205022 
3905574Smx205022 	NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
3915574Smx205022 	/*
3925574Smx205022 	 * Allocate memory & handles for TX buffers
3935574Smx205022 	 */
3945574Smx205022 	ASSERT((txbuffsize % ngep->nge_split) == 0);
3955574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
3965574Smx205022 		err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
3975574Smx205022 		    &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
3985574Smx205022 		    &ngep->send->buf[split]);
3995574Smx205022 		if (err != DDI_SUCCESS)
4005574Smx205022 			goto fail;
4015574Smx205022 	}
4025574Smx205022 
4035574Smx205022 	progress |= ALLOC_TX_BUF;
4045574Smx205022 
4055574Smx205022 	/*
4065574Smx205022 	 * Allocate memory & handles for receive return rings and
4075574Smx205022 	 * buffer (producer) descriptor rings
4085574Smx205022 	 */
4095574Smx205022 	err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
4105574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
4115574Smx205022 	if (err != DDI_SUCCESS)
4125574Smx205022 		goto fail;
4135574Smx205022 	progress |= ALLOC_RX_DESC;
4145574Smx205022 
4155574Smx205022 	/*
4165574Smx205022 	 * Allocate memory & handles for TX descriptor rings,
4175574Smx205022 	 */
4185574Smx205022 	err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
4195574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
4205574Smx205022 	if (err != DDI_SUCCESS)
4215574Smx205022 		goto fail;
4225574Smx205022 	return (DDI_SUCCESS);
4235574Smx205022 
4245574Smx205022 fail:
4255574Smx205022 	if (progress & ALLOC_RX_DESC)
4265574Smx205022 		nge_free_dma_mem(&ngep->recv->desc);
4275574Smx205022 	if (progress & ALLOC_TX_BUF) {
4285574Smx205022 		for (split = 0; split < ngep->nge_split; ++split)
4295574Smx205022 			nge_free_dma_mem(&ngep->send->buf[split]);
4305574Smx205022 	}
4315574Smx205022 
4325574Smx205022 	return (DDI_FAILURE);
4335574Smx205022 }
4345574Smx205022 
4355574Smx205022 /*
4365574Smx205022  * This routine frees the transmit and receive buffers and descriptors.
4375574Smx205022  * Make sure the chip is stopped before calling it!
4385574Smx205022  */
4395574Smx205022 void
nge_free_bufs(nge_t * ngep)4405574Smx205022 nge_free_bufs(nge_t *ngep)
4415574Smx205022 {
4425574Smx205022 	int split;
4435574Smx205022 
4445574Smx205022 	NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
4455574Smx205022 
4465574Smx205022 	nge_free_dma_mem(&ngep->recv->desc);
4475574Smx205022 	nge_free_dma_mem(&ngep->send->desc);
4485574Smx205022 
4495574Smx205022 	for (split = 0; split < ngep->nge_split; ++split)
4505574Smx205022 		nge_free_dma_mem(&ngep->send->buf[split]);
4515574Smx205022 }
4525574Smx205022 
4535574Smx205022 /*
4545574Smx205022  * Clean up initialisation done above before the memory is freed
4555574Smx205022  */
4565574Smx205022 static void
nge_fini_send_ring(nge_t * ngep)4575574Smx205022 nge_fini_send_ring(nge_t *ngep)
4585574Smx205022 {
4595574Smx205022 	uint32_t slot;
4605574Smx205022 	size_t dmah_num;
4615574Smx205022 	send_ring_t *srp;
4625574Smx205022 	sw_tx_sbd_t *ssbdp;
4635574Smx205022 
4645574Smx205022 	srp = ngep->send;
4655574Smx205022 	ssbdp = srp->sw_sbds;
4665574Smx205022 
4675574Smx205022 	NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
4685574Smx205022 
4695574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
4705574Smx205022 
4715574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
4725574Smx205022 		if (srp->dmahndl[slot].hndl) {
4735574Smx205022 			(void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
4745574Smx205022 			ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
4755574Smx205022 			srp->dmahndl[slot].hndl = NULL;
4765574Smx205022 			srp->dmahndl[slot].next = NULL;
4775574Smx205022 		}
4785574Smx205022 	}
4795574Smx205022 
4805574Smx205022 	srp->dmah_free.head = NULL;
4815574Smx205022 	srp->dmah_free.tail = NULL;
4825574Smx205022 
4835574Smx205022 	kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
4845574Smx205022 
4855574Smx205022 }
4865574Smx205022 
4875574Smx205022 /*
4885574Smx205022  * Initialise the specified Send Ring, using the information in the
4895574Smx205022  * <dma_area> descriptors that it contains to set up all the other
4905574Smx205022  * fields. This routine should be called only once for each ring.
4915574Smx205022  */
4925574Smx205022 static int
nge_init_send_ring(nge_t * ngep)4935574Smx205022 nge_init_send_ring(nge_t *ngep)
4945574Smx205022 {
4955574Smx205022 	size_t dmah_num;
4965574Smx205022 	uint32_t nslots;
4975574Smx205022 	uint32_t err;
4985574Smx205022 	uint32_t slot;
4995574Smx205022 	uint32_t split;
5005574Smx205022 	send_ring_t *srp;
5015574Smx205022 	sw_tx_sbd_t *ssbdp;
5025574Smx205022 	dma_area_t desc;
5035574Smx205022 	dma_area_t pbuf;
5045574Smx205022 
5055574Smx205022 	srp = ngep->send;
5065574Smx205022 	srp->desc.nslots = ngep->tx_desc;
5075574Smx205022 	nslots = srp->desc.nslots;
5085574Smx205022 
5095574Smx205022 	NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
5105574Smx205022 	/*
5115574Smx205022 	 * Other one-off initialisation of per-ring data
5125574Smx205022 	 */
5135574Smx205022 	srp->ngep = ngep;
5145574Smx205022 
5155574Smx205022 	/*
5165574Smx205022 	 * Allocate the array of s/w Send Buffer Descriptors
5175574Smx205022 	 */
5185574Smx205022 	ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
5195574Smx205022 	srp->sw_sbds = ssbdp;
5205574Smx205022 
5215574Smx205022 	/*
5225574Smx205022 	 * Now initialise each array element once and for all
5235574Smx205022 	 */
5245574Smx205022 	desc = srp->desc;
5255574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
5265574Smx205022 		pbuf = srp->buf[split];
5275574Smx205022 		for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
5285574Smx205022 			nge_slice_chunk(&ssbdp->desc, &desc, 1,
5295574Smx205022 			    ngep->desc_attr.txd_size);
5305574Smx205022 			nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
5315574Smx205022 			    ngep->buf_size);
5325574Smx205022 		}
5335574Smx205022 		ASSERT(pbuf.alength == 0);
5345574Smx205022 	}
5355574Smx205022 	ASSERT(desc.alength == 0);
5365574Smx205022 
5375574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5385574Smx205022 
5395574Smx205022 	/* preallocate dma handles for tx buffer */
5405574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
5415574Smx205022 
5425574Smx205022 		err = ddi_dma_alloc_handle(ngep->devinfo,
5435574Smx205022 		    ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
5445574Smx205022 		    NULL, &srp->dmahndl[slot].hndl);
5455574Smx205022 
5465574Smx205022 		if (err != DDI_SUCCESS) {
5475574Smx205022 			nge_fini_send_ring(ngep);
5485574Smx205022 			nge_error(ngep,
5495574Smx205022 			    "nge_init_send_ring: alloc dma handle fails");
5505574Smx205022 			return (DDI_FAILURE);
5515574Smx205022 		}
5525574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5535574Smx205022 	}
5545574Smx205022 
5555574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5565574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5575574Smx205022 	srp->dmah_free.tail->next = NULL;
5585574Smx205022 
5595574Smx205022 	return (DDI_SUCCESS);
5605574Smx205022 }
5615574Smx205022 
5625574Smx205022 /*
5635574Smx205022  * Intialize the tx recycle pointer and tx sending pointer of tx ring
5645574Smx205022  * and set the type of tx's data descriptor by default.
5655574Smx205022  */
5665574Smx205022 static void
nge_reinit_send_ring(nge_t * ngep)5675574Smx205022 nge_reinit_send_ring(nge_t *ngep)
5685574Smx205022 {
5695574Smx205022 	size_t dmah_num;
5705574Smx205022 	uint32_t slot;
5715574Smx205022 	send_ring_t *srp;
5725574Smx205022 	sw_tx_sbd_t *ssbdp;
5735574Smx205022 
5745574Smx205022 	srp = ngep->send;
5755574Smx205022 
5765574Smx205022 	/*
5775574Smx205022 	 * Reinitialise control variables ...
5785574Smx205022 	 */
5795574Smx205022 
5805574Smx205022 	srp->tx_hwmark = NGE_DESC_MIN;
5815574Smx205022 	srp->tx_lwmark = NGE_DESC_MIN;
5825574Smx205022 
5835574Smx205022 	srp->tx_next = 0;
5845574Smx205022 	srp->tx_free = srp->desc.nslots;
5855574Smx205022 	srp->tc_next = 0;
5865574Smx205022 
5875574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5885574Smx205022 
5895574Smx205022 	for (slot = 0; slot - dmah_num != 0; ++slot)
5905574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5915574Smx205022 
5925574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5935574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5945574Smx205022 	srp->dmah_free.tail->next = NULL;
5955574Smx205022 
5965574Smx205022 	/*
5975574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
5985574Smx205022 	 */
5995574Smx205022 	for (slot = 0; slot < srp->desc.nslots; ++slot) {
6005574Smx205022 		ssbdp = &srp->sw_sbds[slot];
6015574Smx205022 		ssbdp->flags = HOST_OWN;
6025574Smx205022 	}
6035574Smx205022 
6045574Smx205022 	DMA_ZERO(srp->desc);
6055574Smx205022 	DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
6065574Smx205022 }
6075574Smx205022 
6085574Smx205022 /*
6095574Smx205022  * Initialize the slot number of rx's ring
6105574Smx205022  */
6115574Smx205022 static void
nge_init_recv_ring(nge_t * ngep)6125574Smx205022 nge_init_recv_ring(nge_t *ngep)
6135574Smx205022 {
6145574Smx205022 	recv_ring_t *rrp;
6155574Smx205022 
6165574Smx205022 	rrp = ngep->recv;
6175574Smx205022 	rrp->desc.nslots = ngep->rx_desc;
6185574Smx205022 	rrp->ngep = ngep;
6195574Smx205022 }
6205574Smx205022 
6215574Smx205022 /*
6225574Smx205022  * Intialize the rx recycle pointer and rx sending pointer of rx ring
6235574Smx205022  */
6245574Smx205022 static void
nge_reinit_recv_ring(nge_t * ngep)6255574Smx205022 nge_reinit_recv_ring(nge_t *ngep)
6265574Smx205022 {
6275574Smx205022 	recv_ring_t *rrp;
6285574Smx205022 
6295574Smx205022 	rrp = ngep->recv;
6305574Smx205022 
6315574Smx205022 	/*
6325574Smx205022 	 * Reinitialise control variables ...
6335574Smx205022 	 */
6345574Smx205022 	rrp->prod_index = 0;
6355574Smx205022 	/*
6365574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
6375574Smx205022 	 */
6385574Smx205022 	DMA_ZERO(rrp->desc);
6395574Smx205022 	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
6405574Smx205022 }
6415574Smx205022 
6425574Smx205022 /*
6435574Smx205022  * Clean up initialisation done above before the memory is freed
6445574Smx205022  */
6455574Smx205022 static void
nge_fini_buff_ring(nge_t * ngep)6465574Smx205022 nge_fini_buff_ring(nge_t *ngep)
6475574Smx205022 {
6485574Smx205022 	uint32_t i;
6495574Smx205022 	buff_ring_t *brp;
6505574Smx205022 	dma_area_t *bufp;
6515574Smx205022 	sw_rx_sbd_t *bsbdp;
6525574Smx205022 
6535574Smx205022 	brp = ngep->buff;
6545574Smx205022 	bsbdp = brp->sw_rbds;
6555574Smx205022 
6565574Smx205022 	NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
6575574Smx205022 
6585574Smx205022 	mutex_enter(brp->recycle_lock);
6595574Smx205022 	brp->buf_sign++;
6605574Smx205022 	mutex_exit(brp->recycle_lock);
6615574Smx205022 	for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
6625574Smx205022 		if (bsbdp->bufp) {
6635574Smx205022 			if (bsbdp->bufp->mp)
6645574Smx205022 				freemsg(bsbdp->bufp->mp);
6655574Smx205022 			nge_free_dma_mem(bsbdp->bufp);
6665574Smx205022 			kmem_free(bsbdp->bufp, sizeof (dma_area_t));
6675574Smx205022 			bsbdp->bufp = NULL;
6685574Smx205022 		}
6695574Smx205022 	}
6705574Smx205022 	while (brp->free_list != NULL) {
6715574Smx205022 		bufp = brp->free_list;
6725574Smx205022 		brp->free_list = bufp->next;
6735574Smx205022 		bufp->next = NULL;
6745574Smx205022 		if (bufp->mp)
6755574Smx205022 			freemsg(bufp->mp);
6765574Smx205022 		nge_free_dma_mem(bufp);
6775574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6785574Smx205022 	}
6795574Smx205022 	while (brp->recycle_list != NULL) {
6805574Smx205022 		bufp = brp->recycle_list;
6815574Smx205022 		brp->recycle_list = bufp->next;
6825574Smx205022 		bufp->next = NULL;
6835574Smx205022 		if (bufp->mp)
6845574Smx205022 			freemsg(bufp->mp);
6855574Smx205022 		nge_free_dma_mem(bufp);
6865574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6875574Smx205022 	}
6885574Smx205022 
6895574Smx205022 
6905574Smx205022 	kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
6915574Smx205022 	brp->sw_rbds = NULL;
6925574Smx205022 }
6935574Smx205022 
6945574Smx205022 /*
6955574Smx205022  * Intialize the Rx's data ring and free ring
6965574Smx205022  */
6975574Smx205022 static int
nge_init_buff_ring(nge_t * ngep)6985574Smx205022 nge_init_buff_ring(nge_t *ngep)
6995574Smx205022 {
7005574Smx205022 	uint32_t err;
7015574Smx205022 	uint32_t slot;
7025574Smx205022 	uint32_t nslots_buff;
7035574Smx205022 	uint32_t nslots_recv;
7045574Smx205022 	buff_ring_t *brp;
7055574Smx205022 	recv_ring_t *rrp;
7065574Smx205022 	dma_area_t desc;
7075574Smx205022 	dma_area_t *bufp;
7085574Smx205022 	sw_rx_sbd_t *bsbdp;
7095574Smx205022 
7105574Smx205022 	rrp = ngep->recv;
7115574Smx205022 	brp = ngep->buff;
7125574Smx205022 	brp->nslots = ngep->rx_buf;
7135574Smx205022 	brp->rx_bcopy = B_FALSE;
7145574Smx205022 	nslots_recv = rrp->desc.nslots;
7155574Smx205022 	nslots_buff = brp->nslots;
7165574Smx205022 	brp->ngep = ngep;
7175574Smx205022 
7185574Smx205022 	NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
7195574Smx205022 
7205574Smx205022 	/*
7215574Smx205022 	 * Allocate the array of s/w Recv Buffer Descriptors
7225574Smx205022 	 */
7235574Smx205022 	bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
7245574Smx205022 	brp->sw_rbds = bsbdp;
7255574Smx205022 	brp->free_list = NULL;
7265574Smx205022 	brp->recycle_list = NULL;
7275574Smx205022 	for (slot = 0; slot < nslots_buff; ++slot) {
7285574Smx205022 		bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
7295574Smx205022 		err = nge_alloc_dma_mem(ngep, (ngep->buf_size
7305574Smx205022 		    + NGE_HEADROOM),
7315574Smx205022 		    &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
7325574Smx205022 		if (err != DDI_SUCCESS) {
7335574Smx205022 			kmem_free(bufp, sizeof (dma_area_t));
7345574Smx205022 			return (DDI_FAILURE);
7355574Smx205022 		}
7365574Smx205022 
7375574Smx205022 		bufp->alength -= NGE_HEADROOM;
7385574Smx205022 		bufp->offset += NGE_HEADROOM;
7395574Smx205022 		bufp->private = (caddr_t)ngep;
7405574Smx205022 		bufp->rx_recycle.free_func = nge_recv_recycle;
7415574Smx205022 		bufp->rx_recycle.free_arg = (caddr_t)bufp;
7425574Smx205022 		bufp->signature = brp->buf_sign;
7435574Smx205022 		bufp->rx_delivered = B_FALSE;
7445574Smx205022 		bufp->mp = desballoc(DMA_VPTR(*bufp),
7455574Smx205022 		    ngep->buf_size + NGE_HEADROOM,
7465574Smx205022 		    0, &bufp->rx_recycle);
7475574Smx205022 
7485574Smx205022 		if (bufp->mp == NULL) {
7495574Smx205022 			return (DDI_FAILURE);
7505574Smx205022 		}
7515574Smx205022 		bufp->next = brp->free_list;
7525574Smx205022 		brp->free_list = bufp;
7535574Smx205022 	}
7545574Smx205022 
7555574Smx205022 	/*
7565574Smx205022 	 * Now initialise each array element once and for all
7575574Smx205022 	 */
7585574Smx205022 	desc = rrp->desc;
7595574Smx205022 	for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
7605574Smx205022 		nge_slice_chunk(&bsbdp->desc, &desc, 1,
7615574Smx205022 		    ngep->desc_attr.rxd_size);
7625574Smx205022 		bufp = brp->free_list;
7635574Smx205022 		brp->free_list = bufp->next;
7645574Smx205022 		bsbdp->bufp = bufp;
7655574Smx205022 		bsbdp->flags = CONTROLER_OWN;
7665574Smx205022 		bufp->next = NULL;
7675574Smx205022 	}
7685574Smx205022 
7695574Smx205022 	ASSERT(desc.alength == 0);
7705574Smx205022 	return (DDI_SUCCESS);
7715574Smx205022 }
7725574Smx205022 
7735574Smx205022 /*
7745574Smx205022  * Fill the host address of data in rx' descriptor
7755574Smx205022  * and initialize free pointers of rx free ring
7765574Smx205022  */
7775574Smx205022 static int
nge_reinit_buff_ring(nge_t * ngep)7785574Smx205022 nge_reinit_buff_ring(nge_t *ngep)
7795574Smx205022 {
7805574Smx205022 	uint32_t slot;
7815574Smx205022 	uint32_t nslots_recv;
7825574Smx205022 	buff_ring_t *brp;
7835574Smx205022 	recv_ring_t *rrp;
7845574Smx205022 	sw_rx_sbd_t *bsbdp;
7855574Smx205022 	void *hw_bd_p;
7865574Smx205022 
7875574Smx205022 	brp = ngep->buff;
7885574Smx205022 	rrp = ngep->recv;
7895574Smx205022 	bsbdp = brp->sw_rbds;
7905574Smx205022 	nslots_recv = rrp->desc.nslots;
7915574Smx205022 	for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
7925574Smx205022 		hw_bd_p = DMA_VPTR(bsbdp->desc);
7935574Smx205022 	/*
7945574Smx205022 	 * There is a scenario: When the traffic of small tcp
7955574Smx205022 	 * packet is heavy, suspending the tcp traffic will
7965574Smx205022 	 * cause the preallocated buffers for rx not to be
7975574Smx205022 	 * released in time by tcp taffic and cause rx's buffer
7985574Smx205022 	 * pointers not to be refilled in time.
7995574Smx205022 	 *
8005574Smx205022 	 * At this point, if we reinitialize the driver, the bufp
8015574Smx205022 	 * pointer for rx's traffic will be NULL.
8025574Smx205022 	 * So the result of the reinitializion fails.
8035574Smx205022 	 */
8045574Smx205022 		if (bsbdp->bufp == NULL)
8055574Smx205022 			return (DDI_FAILURE);
8065574Smx205022 
8075574Smx205022 		ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
8085574Smx205022 		    bsbdp->bufp->alength);
8095574Smx205022 	}
8105574Smx205022 	return (DDI_SUCCESS);
8115574Smx205022 }
8125574Smx205022 
8135574Smx205022 static void
nge_init_ring_param_lock(nge_t * ngep)8145574Smx205022 nge_init_ring_param_lock(nge_t *ngep)
8155574Smx205022 {
8165574Smx205022 	buff_ring_t *brp;
8175574Smx205022 	send_ring_t *srp;
8185574Smx205022 
8195574Smx205022 	srp = ngep->send;
8205574Smx205022 	brp = ngep->buff;
8215574Smx205022 
8225574Smx205022 	/* Init the locks for send ring */
8235574Smx205022 	mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
8245574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8255574Smx205022 	mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
8265574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8275574Smx205022 	mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
8285574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8295574Smx205022 
8305574Smx205022 	/* Init parameters of buffer ring */
8315574Smx205022 	brp->free_list = NULL;
8325574Smx205022 	brp->recycle_list = NULL;
8335574Smx205022 	brp->rx_hold = 0;
8345574Smx205022 	brp->buf_sign = 0;
8355574Smx205022 
8365574Smx205022 	/* Init recycle list lock */
8375574Smx205022 	mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
8385574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8395574Smx205022 }
8405574Smx205022 
8415574Smx205022 int
nge_init_rings(nge_t * ngep)8425574Smx205022 nge_init_rings(nge_t *ngep)
8435574Smx205022 {
8445574Smx205022 	uint32_t err;
8455574Smx205022 
8465574Smx205022 	err = nge_init_send_ring(ngep);
8475574Smx205022 	if (err != DDI_SUCCESS) {
8485574Smx205022 		return (err);
8495574Smx205022 	}
8505574Smx205022 	nge_init_recv_ring(ngep);
8515574Smx205022 
8525574Smx205022 	err = nge_init_buff_ring(ngep);
8535574Smx205022 	if (err != DDI_SUCCESS) {
8545574Smx205022 		nge_fini_send_ring(ngep);
8555574Smx205022 		return (DDI_FAILURE);
8565574Smx205022 	}
8575574Smx205022 
8585574Smx205022 	return (err);
8595574Smx205022 }
8605574Smx205022 
8615574Smx205022 static int
nge_reinit_ring(nge_t * ngep)8625574Smx205022 nge_reinit_ring(nge_t *ngep)
8635574Smx205022 {
8645574Smx205022 	int err;
8655574Smx205022 
8665574Smx205022 	nge_reinit_recv_ring(ngep);
8675574Smx205022 	nge_reinit_send_ring(ngep);
8685574Smx205022 	err = nge_reinit_buff_ring(ngep);
8695574Smx205022 	return (err);
8705574Smx205022 }
8715574Smx205022 
8725574Smx205022 
8735574Smx205022 void
nge_fini_rings(nge_t * ngep)8745574Smx205022 nge_fini_rings(nge_t *ngep)
8755574Smx205022 {
8765574Smx205022 	/*
8775574Smx205022 	 * For receive ring, nothing need to be finished.
8785574Smx205022 	 * So only finish buffer ring and send ring here.
8795574Smx205022 	 */
8805574Smx205022 	nge_fini_buff_ring(ngep);
8815574Smx205022 	nge_fini_send_ring(ngep);
8825574Smx205022 }
8835574Smx205022 
8845574Smx205022 /*
8855574Smx205022  * Loopback ioctl code
8865574Smx205022  */
8875574Smx205022 
8885574Smx205022 static lb_property_t loopmodes[] = {
8895574Smx205022 	{ normal,	"normal",	NGE_LOOP_NONE		},
8905574Smx205022 	{ external,	"100Mbps",	NGE_LOOP_EXTERNAL_100	},
8915574Smx205022 	{ external,	"10Mbps",	NGE_LOOP_EXTERNAL_10	},
8925574Smx205022 	{ internal,	"PHY",		NGE_LOOP_INTERNAL_PHY	},
8935574Smx205022 };
8945574Smx205022 
8955574Smx205022 enum ioc_reply
nge_loop_ioctl(nge_t * ngep,mblk_t * mp,struct iocblk * iocp)8965574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
8975574Smx205022 {
8985574Smx205022 	int cmd;
8995574Smx205022 	uint32_t *lbmp;
9005574Smx205022 	lb_info_sz_t *lbsp;
9015574Smx205022 	lb_property_t *lbpp;
9025574Smx205022 
9035574Smx205022 	/*
9045574Smx205022 	 * Validate format of ioctl
9055574Smx205022 	 */
9065574Smx205022 	if (mp->b_cont == NULL)
9075574Smx205022 		return (IOC_INVAL);
9085574Smx205022 
9095574Smx205022 	cmd = iocp->ioc_cmd;
9105574Smx205022 
9115574Smx205022 	switch (cmd) {
9125574Smx205022 	default:
9135574Smx205022 		return (IOC_INVAL);
9145574Smx205022 
9155574Smx205022 	case LB_GET_INFO_SIZE:
9165574Smx205022 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
9175574Smx205022 			return (IOC_INVAL);
9185574Smx205022 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
9195574Smx205022 		*lbsp = sizeof (loopmodes);
9205574Smx205022 		return (IOC_REPLY);
9215574Smx205022 
9225574Smx205022 	case LB_GET_INFO:
9235574Smx205022 		if (iocp->ioc_count != sizeof (loopmodes))
9245574Smx205022 			return (IOC_INVAL);
9255574Smx205022 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
9265574Smx205022 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
9275574Smx205022 		return (IOC_REPLY);
9285574Smx205022 
9295574Smx205022 	case LB_GET_MODE:
9305574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9315574Smx205022 			return (IOC_INVAL);
9325574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9335574Smx205022 		*lbmp = ngep->param_loop_mode;
9345574Smx205022 		return (IOC_REPLY);
9355574Smx205022 
9365574Smx205022 	case LB_SET_MODE:
9375574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9385574Smx205022 			return (IOC_INVAL);
9395574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9405574Smx205022 		return (nge_set_loop_mode(ngep, *lbmp));
9415574Smx205022 	}
9425574Smx205022 }
9435574Smx205022 
9445574Smx205022 #undef	NGE_DBG
9455574Smx205022 #define	NGE_DBG	NGE_DBG_NEMO
9465574Smx205022 
9475574Smx205022 
9485574Smx205022 static void
nge_check_desc_prop(nge_t * ngep)9495574Smx205022 nge_check_desc_prop(nge_t *ngep)
9505574Smx205022 {
9515574Smx205022 	if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
9525574Smx205022 		ngep->desc_mode = DESC_HOT;
9535574Smx205022 
9545574Smx205022 	if (ngep->desc_mode == DESC_OFFLOAD)	{
9555574Smx205022 
9565574Smx205022 		ngep->desc_attr = nge_sum_desc;
9575574Smx205022 
9585574Smx205022 	}	else if (ngep->desc_mode == DESC_HOT)	{
9595574Smx205022 
9605574Smx205022 		ngep->desc_attr = nge_hot_desc;
9615574Smx205022 	}
9625574Smx205022 }
9635574Smx205022 
9645574Smx205022 /*
9655574Smx205022  * nge_get_props -- get the parameters to tune the driver
9665574Smx205022  */
9675574Smx205022 static void
nge_get_props(nge_t * ngep)9685574Smx205022 nge_get_props(nge_t *ngep)
9695574Smx205022 {
9705574Smx205022 	chip_info_t *infop;
9715574Smx205022 	dev_info_t *devinfo;
9725574Smx205022 	nge_dev_spec_param_t *dev_param_p;
9735574Smx205022 
9745574Smx205022 	devinfo = ngep->devinfo;
9755574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
9765574Smx205022 	dev_param_p = &ngep->dev_spec_param;
9775574Smx205022 
9785574Smx205022 	infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9795574Smx205022 	    DDI_PROP_DONTPASS, clsize_propname, 32);
9805574Smx205022 
9815574Smx205022 	infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9825574Smx205022 	    DDI_PROP_DONTPASS, latency_propname, 64);
9835659Sjj146644 	ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9845659Sjj146644 	    DDI_PROP_DONTPASS, intr_moderation, NGE_SET);
9855574Smx205022 	ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9865574Smx205022 	    DDI_PROP_DONTPASS, rx_data_hw, 0x20);
9875574Smx205022 	ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9885574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
9895574Smx205022 	ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9905574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
9915574Smx205022 
9925574Smx205022 	ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9935574Smx205022 	    DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
9945574Smx205022 	ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9955574Smx205022 	    DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
9965574Smx205022 	ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9975574Smx205022 	    DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
9985574Smx205022 	ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9995574Smx205022 	    DDI_PROP_DONTPASS, low_memory_mode, 0);
10005574Smx205022 
10015574Smx205022 	if (dev_param_p->jumbo) {
10025574Smx205022 		ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10035574Smx205022 		    DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
10045574Smx205022 	} else
10055574Smx205022 		ngep->default_mtu = ETHERMTU;
100610496SLi-Zhen.You@Sun.COM 	if (dev_param_p->tx_pause_frame)
100710496SLi-Zhen.You@Sun.COM 			ngep->param_link_tx_pause = B_TRUE;
100810496SLi-Zhen.You@Sun.COM 	else
100910496SLi-Zhen.You@Sun.COM 			ngep->param_link_tx_pause = B_FALSE;
101010496SLi-Zhen.You@Sun.COM 
101110496SLi-Zhen.You@Sun.COM 	if (dev_param_p->rx_pause_frame)
101210496SLi-Zhen.You@Sun.COM 			ngep->param_link_rx_pause = B_TRUE;
101310496SLi-Zhen.You@Sun.COM 	else
101410496SLi-Zhen.You@Sun.COM 			ngep->param_link_rx_pause = B_FALSE;
10155574Smx205022 
10165574Smx205022 	if (ngep->default_mtu > ETHERMTU &&
10175574Smx205022 	    ngep->default_mtu <= NGE_MTU_2500) {
10185574Smx205022 		ngep->buf_size = NGE_JB2500_BUFSZ;
10195574Smx205022 		ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
10205574Smx205022 		ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
10215574Smx205022 		ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
10225574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10235574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_2500 &&
10245574Smx205022 	    ngep->default_mtu <= NGE_MTU_4500) {
10255574Smx205022 		ngep->buf_size = NGE_JB4500_BUFSZ;
10265574Smx205022 		ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
10275574Smx205022 		ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
10285574Smx205022 		ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
10295574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10305574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_4500 &&
10315574Smx205022 	    ngep->default_mtu <= NGE_MAX_MTU) {
10325574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10335574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10345574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10355574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10365574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10375574Smx205022 	} else if (ngep->default_mtu > NGE_MAX_MTU) {
10385574Smx205022 		ngep->default_mtu = NGE_MAX_MTU;
10395574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10405574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10415574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10425574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10435574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10445574Smx205022 	} else if (ngep->lowmem_mode != 0) {
10455574Smx205022 		ngep->default_mtu = ETHERMTU;
10465574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10475574Smx205022 		ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
10485574Smx205022 		ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
10495574Smx205022 		ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
10505574Smx205022 		ngep->nge_split = NGE_SPLIT_32;
10515574Smx205022 	} else {
10525574Smx205022 		ngep->default_mtu = ETHERMTU;
10535574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10545574Smx205022 		ngep->tx_desc = dev_param_p->tx_desc_num;
10555574Smx205022 		ngep->rx_desc = dev_param_p->rx_desc_num;
10565574Smx205022 		ngep->rx_buf = dev_param_p->rx_desc_num * 2;
10575574Smx205022 		ngep->nge_split = dev_param_p->nge_split;
10585574Smx205022 	}
10595574Smx205022 
10605574Smx205022 	nge_check_desc_prop(ngep);
10615574Smx205022 }
10625574Smx205022 
10635574Smx205022 
10645574Smx205022 static int
nge_reset_dev(nge_t * ngep)10657656SSherry.Moore@Sun.COM nge_reset_dev(nge_t *ngep)
10665574Smx205022 {
10675574Smx205022 	int err;
10685869Smx205022 	nge_mul_addr1 maddr1;
10695869Smx205022 	nge_sw_statistics_t *sw_stp;
10705869Smx205022 	sw_stp = &ngep->statistics.sw_statistics;
10715574Smx205022 	send_ring_t *srp = ngep->send;
10725574Smx205022 
10735574Smx205022 	ASSERT(mutex_owned(ngep->genlock));
10745574Smx205022 	mutex_enter(srp->tc_lock);
10755574Smx205022 	mutex_enter(srp->tx_lock);
10765574Smx205022 
10775574Smx205022 	nge_tx_recycle_all(ngep);
10785574Smx205022 	err = nge_reinit_ring(ngep);
10795574Smx205022 	if (err == DDI_FAILURE) {
10805574Smx205022 		mutex_exit(srp->tx_lock);
10815574Smx205022 		mutex_exit(srp->tc_lock);
10825574Smx205022 		return (err);
10835574Smx205022 	}
10845574Smx205022 	err = nge_chip_reset(ngep);
10855869Smx205022 	/*
10865869Smx205022 	 * Clear the Multicast mac address table
10875869Smx205022 	 */
10885869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
10895869Smx205022 	maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
10905869Smx205022 	maddr1.addr_bits.addr = 0;
10915869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
10925869Smx205022 
10935574Smx205022 	mutex_exit(srp->tx_lock);
10945574Smx205022 	mutex_exit(srp->tc_lock);
10955574Smx205022 	if (err == DDI_FAILURE)
10965574Smx205022 		return (err);
10975574Smx205022 	ngep->watchdog = 0;
10985574Smx205022 	ngep->resched_needed = B_FALSE;
10995574Smx205022 	ngep->promisc = B_FALSE;
11005574Smx205022 	ngep->param_loop_mode = NGE_LOOP_NONE;
11015574Smx205022 	ngep->factotum_flag = 0;
11025574Smx205022 	ngep->resched_needed = 0;
11035574Smx205022 	ngep->nge_mac_state = NGE_MAC_RESET;
11045574Smx205022 	ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
11055574Smx205022 	ngep->max_sdu += VTAG_SIZE;
11065574Smx205022 	ngep->rx_def = 0x16;
11075869Smx205022 
11085869Smx205022 	/* Clear the software statistics */
11095869Smx205022 	sw_stp->recv_count = 0;
11105869Smx205022 	sw_stp->xmit_count = 0;
11115869Smx205022 	sw_stp->rbytes = 0;
11125869Smx205022 	sw_stp->obytes = 0;
11135869Smx205022 
11145574Smx205022 	return (DDI_SUCCESS);
11155574Smx205022 }
11165574Smx205022 
11175574Smx205022 static void
nge_m_stop(void * arg)11185574Smx205022 nge_m_stop(void *arg)
11195574Smx205022 {
11205574Smx205022 	nge_t *ngep = arg;		/* private device info	*/
11219708SZhen.W@Sun.COM 	int err;
11225574Smx205022 
11235574Smx205022 	NGE_TRACE(("nge_m_stop($%p)", arg));
11245574Smx205022 
11255574Smx205022 	/*
11265574Smx205022 	 * Just stop processing, then record new MAC state
11275574Smx205022 	 */
11285574Smx205022 	mutex_enter(ngep->genlock);
11295869Smx205022 	/* If suspended, the adapter is already stopped, just return. */
11305869Smx205022 	if (ngep->suspended) {
11315869Smx205022 		ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
11325869Smx205022 		mutex_exit(ngep->genlock);
11335869Smx205022 		return;
11345869Smx205022 	}
11355574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11365574Smx205022 
11379708SZhen.W@Sun.COM 	err = nge_chip_stop(ngep, B_FALSE);
11389708SZhen.W@Sun.COM 	if (err == DDI_FAILURE)
11399708SZhen.W@Sun.COM 		err = nge_chip_reset(ngep);
11409708SZhen.W@Sun.COM 	if (err == DDI_FAILURE)
11419708SZhen.W@Sun.COM 		nge_problem(ngep, "nge_m_stop: stop chip failed");
11425574Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
11435574Smx205022 
11445574Smx205022 	/* Recycle all the TX BD */
11455574Smx205022 	nge_tx_recycle_all(ngep);
11465574Smx205022 	nge_fini_rings(ngep);
11475574Smx205022 	nge_free_bufs(ngep);
11485574Smx205022 
11495574Smx205022 	NGE_DEBUG(("nge_m_stop($%p) done", arg));
11505574Smx205022 
11515574Smx205022 	rw_exit(ngep->rwlock);
11525574Smx205022 	mutex_exit(ngep->genlock);
11535574Smx205022 }
11545574Smx205022 
11555574Smx205022 static int
nge_m_start(void * arg)11565574Smx205022 nge_m_start(void *arg)
11575574Smx205022 {
11585574Smx205022 	int err;
11595574Smx205022 	nge_t *ngep = arg;
11605574Smx205022 
11615574Smx205022 	NGE_TRACE(("nge_m_start($%p)", arg));
11625869Smx205022 
11635869Smx205022 	/*
11645869Smx205022 	 * Start processing and record new MAC state
11655869Smx205022 	 */
11665869Smx205022 	mutex_enter(ngep->genlock);
11675574Smx205022 	/*
11685574Smx205022 	 * If suspended, don't start, as the resume processing
11695574Smx205022 	 * will recall this function with the suspended flag off.
11705574Smx205022 	 */
11715869Smx205022 	if (ngep->suspended) {
11725869Smx205022 		mutex_exit(ngep->genlock);
11735988Svb160487 		return (EIO);
11745869Smx205022 	}
11755574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11765574Smx205022 	err = nge_alloc_bufs(ngep);
11775574Smx205022 	if (err != DDI_SUCCESS) {
11785574Smx205022 		nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
11795574Smx205022 		goto finish;
11805574Smx205022 	}
11815574Smx205022 	err = nge_init_rings(ngep);
11825574Smx205022 	if (err != DDI_SUCCESS) {
11835574Smx205022 		nge_free_bufs(ngep);
11845988Svb160487 		nge_problem(ngep, "nge_init_rings() failed,err=%x", err);
11855574Smx205022 		goto finish;
11865574Smx205022 	}
11875574Smx205022 	err = nge_restart(ngep);
11885574Smx205022 
11895574Smx205022 	NGE_DEBUG(("nge_m_start($%p) done", arg));
11905988Svb160487 finish:
11915988Svb160487 	rw_exit(ngep->rwlock);
11925988Svb160487 	mutex_exit(ngep->genlock);
11935574Smx205022 
11945988Svb160487 	return (err == DDI_SUCCESS ? 0 : EIO);
11955574Smx205022 }
11965574Smx205022 
11975574Smx205022 static int
nge_m_unicst(void * arg,const uint8_t * macaddr)11985574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr)
11995574Smx205022 {
12005574Smx205022 	nge_t *ngep = arg;
12015574Smx205022 
12025574Smx205022 	NGE_TRACE(("nge_m_unicst($%p)", arg));
12035574Smx205022 	/*
12045574Smx205022 	 * Remember the new current address in the driver state
12055574Smx205022 	 * Sync the chip's idea of the address too ...
12065574Smx205022 	 */
12075574Smx205022 	mutex_enter(ngep->genlock);
12085574Smx205022 
12095574Smx205022 	ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
12105574Smx205022 	ngep->cur_uni_addr.set = 1;
12115574Smx205022 
12125574Smx205022 	/*
12135574Smx205022 	 * If we are suspended, we want to quit now, and not update
12145574Smx205022 	 * the chip.  Doing so might put it in a bad state, but the
12155574Smx205022 	 * resume will get the unicast address installed.
12165574Smx205022 	 */
12175869Smx205022 	if (ngep->suspended) {
12185869Smx205022 		mutex_exit(ngep->genlock);
12195574Smx205022 		return (DDI_SUCCESS);
12205869Smx205022 	}
12215574Smx205022 	nge_chip_sync(ngep);
12225574Smx205022 
12235574Smx205022 	NGE_DEBUG(("nge_m_unicst($%p) done", arg));
12245574Smx205022 	mutex_exit(ngep->genlock);
12255574Smx205022 
12265574Smx205022 	return (0);
12275574Smx205022 }
12285574Smx205022 
12295574Smx205022 static int
nge_m_promisc(void * arg,boolean_t on)12305574Smx205022 nge_m_promisc(void *arg, boolean_t on)
12315574Smx205022 {
12325574Smx205022 	nge_t *ngep = arg;
12335574Smx205022 
12345574Smx205022 	NGE_TRACE(("nge_m_promisc($%p)", arg));
12355574Smx205022 
12365574Smx205022 	/*
12375574Smx205022 	 * Store specified mode and pass to chip layer to update h/w
12385574Smx205022 	 */
12395574Smx205022 	mutex_enter(ngep->genlock);
12405869Smx205022 	/*
12415869Smx205022 	 * If suspended, there is no need to do anything, even
12425869Smx205022 	 * recording the promiscuious mode is not neccessary, as
12435869Smx205022 	 * it won't be properly set on resume.  Just return failing.
12445869Smx205022 	 */
12455869Smx205022 	if (ngep->suspended) {
12465869Smx205022 		mutex_exit(ngep->genlock);
12475869Smx205022 		return (DDI_FAILURE);
12485869Smx205022 	}
12495574Smx205022 	if (ngep->promisc == on) {
12505574Smx205022 		mutex_exit(ngep->genlock);
12515574Smx205022 		NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12525574Smx205022 		return (0);
12535574Smx205022 	}
12545574Smx205022 	ngep->promisc = on;
12557155Smx205022 	ngep->record_promisc = ngep->promisc;
12565574Smx205022 	nge_chip_sync(ngep);
12575574Smx205022 	NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12585574Smx205022 	mutex_exit(ngep->genlock);
12595574Smx205022 
12605574Smx205022 	return (0);
12615574Smx205022 }
12625574Smx205022 
nge_mulparam(nge_t * ngep)12635574Smx205022 static void nge_mulparam(nge_t *ngep)
12645574Smx205022 {
12655574Smx205022 	uint8_t number;
12665574Smx205022 	ether_addr_t pand;
12675574Smx205022 	ether_addr_t por;
12685574Smx205022 	mul_item *plist;
12695574Smx205022 
12705574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12715574Smx205022 		pand[number] = 0x00;
12725574Smx205022 		por[number] = 0x00;
12735574Smx205022 	}
12745574Smx205022 	for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
12755574Smx205022 		for (number = 0; number < ETHERADDRL; number++) {
12765574Smx205022 			pand[number] &= plist->mul_addr[number];
12775574Smx205022 			por[number] |= plist->mul_addr[number];
12785574Smx205022 		}
12795574Smx205022 	}
12805574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12815574Smx205022 		ngep->cur_mul_addr.addr[number]
12825574Smx205022 		    = pand[number] & por[number];
12835574Smx205022 		ngep->cur_mul_mask.addr[number]
12845574Smx205022 		    = pand [number] | (~por[number]);
12855574Smx205022 	}
12865574Smx205022 }
12875574Smx205022 static int
nge_m_multicst(void * arg,boolean_t add,const uint8_t * mca)12885574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
12895574Smx205022 {
12905574Smx205022 	boolean_t update;
12915574Smx205022 	boolean_t b_eq;
12925574Smx205022 	nge_t *ngep = arg;
12935574Smx205022 	mul_item *plist;
12945574Smx205022 	mul_item *plist_prev;
12955574Smx205022 	mul_item *pitem;
12965574Smx205022 
12975574Smx205022 	NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
12985574Smx205022 	    (add) ? "add" : "remove", ether_sprintf((void *)mca)));
12995574Smx205022 
13005574Smx205022 	update = B_FALSE;
13015574Smx205022 	plist = plist_prev = NULL;
13025574Smx205022 	mutex_enter(ngep->genlock);
13035574Smx205022 	if (add) {
13045574Smx205022 		if (ngep->pcur_mulist != NULL) {
13055574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13065574Smx205022 			    plist = plist->next) {
13075574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13085574Smx205022 				if (b_eq) {
13095574Smx205022 					plist->ref_cnt++;
13105574Smx205022 					break;
13115574Smx205022 				}
13125574Smx205022 				plist_prev = plist;
13135574Smx205022 			}
13145574Smx205022 		}
13155574Smx205022 
13165574Smx205022 		if (plist == NULL) {
13175574Smx205022 			pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
13185574Smx205022 			ether_copy(mca, pitem->mul_addr);
13195574Smx205022 			pitem ->ref_cnt++;
13205574Smx205022 			pitem ->next = NULL;
13215574Smx205022 			if (plist_prev == NULL)
13225574Smx205022 				ngep->pcur_mulist = pitem;
13235574Smx205022 			else
13245574Smx205022 				plist_prev->next = pitem;
13255574Smx205022 			update = B_TRUE;
13265574Smx205022 		}
13275574Smx205022 	} else {
13285574Smx205022 		if (ngep->pcur_mulist != NULL) {
13295574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13305574Smx205022 			    plist = plist->next) {
13315574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13325574Smx205022 				if (b_eq) {
13335574Smx205022 					update = B_TRUE;
13345574Smx205022 					break;
13355574Smx205022 				}
13365574Smx205022 				plist_prev = plist;
13375574Smx205022 			}
13385574Smx205022 
13395574Smx205022 			if (update) {
13405574Smx205022 				if ((plist_prev == NULL) &&
13415574Smx205022 				    (plist->next == NULL))
13425574Smx205022 					ngep->pcur_mulist = NULL;
13435574Smx205022 				else if ((plist_prev == NULL) &&
13445574Smx205022 				    (plist->next != NULL))
13455574Smx205022 					ngep->pcur_mulist = plist->next;
13465574Smx205022 				else
13475574Smx205022 					plist_prev->next = plist->next;
13485574Smx205022 				kmem_free(plist, sizeof (mul_item));
13495574Smx205022 			}
13505574Smx205022 		}
13515574Smx205022 	}
13525574Smx205022 
13535869Smx205022 	if (update && !ngep->suspended) {
13545574Smx205022 		nge_mulparam(ngep);
13555574Smx205022 		nge_chip_sync(ngep);
13565574Smx205022 	}
13575574Smx205022 	NGE_DEBUG(("nge_m_multicst($%p) done", arg));
13585574Smx205022 	mutex_exit(ngep->genlock);
13595574Smx205022 
13605574Smx205022 	return (0);
13615574Smx205022 }
13625574Smx205022 
13635574Smx205022 static void
nge_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)13645574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
13655574Smx205022 {
13665574Smx205022 	int err;
13675574Smx205022 	int cmd;
13685574Smx205022 	nge_t *ngep = arg;
13695574Smx205022 	struct iocblk *iocp;
13705574Smx205022 	enum ioc_reply status;
13715574Smx205022 	boolean_t need_privilege;
13725574Smx205022 
13735574Smx205022 	/*
13745574Smx205022 	 * If suspended, we might actually be able to do some of
13755574Smx205022 	 * these ioctls, but it is harder to make sure they occur
13765574Smx205022 	 * without actually putting the hardware in an undesireable
13775574Smx205022 	 * state.  So just NAK it.
13785574Smx205022 	 */
13795869Smx205022 	mutex_enter(ngep->genlock);
13805574Smx205022 	if (ngep->suspended) {
13815574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13825869Smx205022 		mutex_exit(ngep->genlock);
13835574Smx205022 		return;
13845574Smx205022 	}
13855869Smx205022 	mutex_exit(ngep->genlock);
13865574Smx205022 
13875574Smx205022 	/*
13885574Smx205022 	 * Validate the command before bothering with the mutex ...
13895574Smx205022 	 */
13905574Smx205022 	iocp = (struct iocblk *)mp->b_rptr;
13915574Smx205022 	iocp->ioc_error = 0;
13925574Smx205022 	need_privilege = B_TRUE;
13935574Smx205022 	cmd = iocp->ioc_cmd;
13945574Smx205022 
13955574Smx205022 	NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
13965574Smx205022 	switch (cmd) {
13975574Smx205022 	default:
13985574Smx205022 		NGE_LDB(NGE_DBG_BADIOC,
13995574Smx205022 		    ("nge_m_ioctl: unknown cmd 0x%x", cmd));
14005574Smx205022 
14015574Smx205022 		miocnak(wq, mp, 0, EINVAL);
14025574Smx205022 		return;
14035574Smx205022 
14045574Smx205022 	case NGE_MII_READ:
14055574Smx205022 	case NGE_MII_WRITE:
14065574Smx205022 	case NGE_SEE_READ:
14075574Smx205022 	case NGE_SEE_WRITE:
14085574Smx205022 	case NGE_DIAG:
14095574Smx205022 	case NGE_PEEK:
14105574Smx205022 	case NGE_POKE:
14115574Smx205022 	case NGE_PHY_RESET:
14125574Smx205022 	case NGE_SOFT_RESET:
14135574Smx205022 	case NGE_HARD_RESET:
14145574Smx205022 		break;
14155574Smx205022 
14165574Smx205022 	case LB_GET_INFO_SIZE:
14175574Smx205022 	case LB_GET_INFO:
14185574Smx205022 	case LB_GET_MODE:
14195574Smx205022 		need_privilege = B_FALSE;
14205574Smx205022 		break;
14215574Smx205022 	case LB_SET_MODE:
14225574Smx205022 		break;
14235574Smx205022 	}
14245574Smx205022 
14255574Smx205022 	if (need_privilege) {
14265574Smx205022 		/*
14275574Smx205022 		 * Check for specific net_config privilege.
14285574Smx205022 		 */
14295574Smx205022 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
14305574Smx205022 		if (err != 0) {
14315574Smx205022 			NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
14325574Smx205022 			    cmd, err));
14335574Smx205022 			miocnak(wq, mp, 0, err);
14345574Smx205022 			return;
14355574Smx205022 		}
14365574Smx205022 	}
14375574Smx205022 
14385574Smx205022 	mutex_enter(ngep->genlock);
14395574Smx205022 
14405574Smx205022 	switch (cmd) {
14415574Smx205022 	default:
14425574Smx205022 		_NOTE(NOTREACHED)
14435574Smx205022 		status = IOC_INVAL;
14445574Smx205022 	break;
14455574Smx205022 
14465574Smx205022 	case NGE_MII_READ:
14475574Smx205022 	case NGE_MII_WRITE:
14485574Smx205022 	case NGE_SEE_READ:
14495574Smx205022 	case NGE_SEE_WRITE:
14505574Smx205022 	case NGE_DIAG:
14515574Smx205022 	case NGE_PEEK:
14525574Smx205022 	case NGE_POKE:
14535574Smx205022 	case NGE_PHY_RESET:
14545574Smx205022 	case NGE_SOFT_RESET:
14555574Smx205022 	case NGE_HARD_RESET:
14565574Smx205022 		status = nge_chip_ioctl(ngep, mp, iocp);
14575574Smx205022 	break;
14585574Smx205022 
14595574Smx205022 	case LB_GET_INFO_SIZE:
14605574Smx205022 	case LB_GET_INFO:
14615574Smx205022 	case LB_GET_MODE:
14625574Smx205022 	case LB_SET_MODE:
14635574Smx205022 		status = nge_loop_ioctl(ngep, mp, iocp);
14645574Smx205022 	break;
14655574Smx205022 
14665574Smx205022 	}
14675574Smx205022 
14685574Smx205022 	/*
14695574Smx205022 	 * Do we need to reprogram the PHY and/or the MAC?
14705574Smx205022 	 * Do it now, while we still have the mutex.
14715574Smx205022 	 *
14725574Smx205022 	 * Note: update the PHY first, 'cos it controls the
14735574Smx205022 	 * speed/duplex parameters that the MAC code uses.
14745574Smx205022 	 */
14755574Smx205022 
14765574Smx205022 	NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
14775574Smx205022 
14785574Smx205022 	switch (status) {
14795574Smx205022 	case IOC_RESTART_REPLY:
14805574Smx205022 	case IOC_RESTART_ACK:
14815574Smx205022 		(*ngep->physops->phys_update)(ngep);
14825574Smx205022 		nge_chip_sync(ngep);
14835574Smx205022 		break;
14845574Smx205022 
14855574Smx205022 	default:
14865574Smx205022 	break;
14875574Smx205022 	}
14885574Smx205022 
14895574Smx205022 	mutex_exit(ngep->genlock);
14905574Smx205022 
14915574Smx205022 	/*
14925574Smx205022 	 * Finally, decide how to reply
14935574Smx205022 	 */
14945574Smx205022 	switch (status) {
14955574Smx205022 
14965574Smx205022 	default:
14975574Smx205022 	case IOC_INVAL:
14985574Smx205022 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
14995574Smx205022 		    EINVAL : iocp->ioc_error);
15005574Smx205022 		break;
15015574Smx205022 
15025574Smx205022 	case IOC_DONE:
15035574Smx205022 		break;
15045574Smx205022 
15055574Smx205022 	case IOC_RESTART_ACK:
15065574Smx205022 	case IOC_ACK:
15075574Smx205022 		miocack(wq, mp, 0, 0);
15085574Smx205022 		break;
15095574Smx205022 
15105574Smx205022 	case IOC_RESTART_REPLY:
15115574Smx205022 	case IOC_REPLY:
15125574Smx205022 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
15135574Smx205022 		    M_IOCACK : M_IOCNAK;
15145574Smx205022 		qreply(wq, mp);
15155574Smx205022 		break;
15165574Smx205022 	}
15175574Smx205022 }
15185574Smx205022 
15196200Smx205022 static boolean_t
nge_param_locked(mac_prop_id_t pr_num)15206200Smx205022 nge_param_locked(mac_prop_id_t pr_num)
15216200Smx205022 {
15226200Smx205022 	/*
15236200Smx205022 	 * All adv_* parameters are locked (read-only) while
15246200Smx205022 	 * the device is in any sort of loopback mode ...
15256200Smx205022 	 */
15266200Smx205022 	switch (pr_num) {
15276789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15286789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15296789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15306789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
15316789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15326789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15336789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15346789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15356789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15366789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15376789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15386789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15396789Sam223141 		case MAC_PROP_AUTONEG:
15406789Sam223141 		case MAC_PROP_FLOWCTRL:
15416200Smx205022 			return (B_TRUE);
15426200Smx205022 	}
15436200Smx205022 	return (B_FALSE);
15446200Smx205022 }
15456200Smx205022 
15466200Smx205022 /*
15476200Smx205022  * callback functions for set/get of properties
15486200Smx205022  */
15496200Smx205022 static int
nge_m_setprop(void * barg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)15506200Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
15516200Smx205022     uint_t pr_valsize, const void *pr_val)
15526200Smx205022 {
15536200Smx205022 	nge_t *ngep = barg;
15546200Smx205022 	int err = 0;
15556512Ssowmini 	uint32_t cur_mtu, new_mtu;
15566200Smx205022 	link_flowctrl_t fl;
15576200Smx205022 
15586200Smx205022 	mutex_enter(ngep->genlock);
15596200Smx205022 	if (ngep->param_loop_mode != NGE_LOOP_NONE &&
15606200Smx205022 	    nge_param_locked(pr_num)) {
15616200Smx205022 		/*
15626200Smx205022 		 * All adv_* parameters are locked (read-only)
15636200Smx205022 		 * while the device is in any sort of loopback mode.
15646200Smx205022 		 */
15656200Smx205022 		mutex_exit(ngep->genlock);
15666200Smx205022 		return (EBUSY);
15676200Smx205022 	}
15686200Smx205022 	switch (pr_num) {
15696789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15706200Smx205022 			ngep->param_en_1000fdx = *(uint8_t *)pr_val;
15716200Smx205022 			ngep->param_adv_1000fdx = *(uint8_t *)pr_val;
15726200Smx205022 			goto reprogram;
15736789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15746200Smx205022 			ngep->param_en_100fdx = *(uint8_t *)pr_val;
15756200Smx205022 			ngep->param_adv_100fdx = *(uint8_t *)pr_val;
15766200Smx205022 			goto reprogram;
15776789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15786200Smx205022 			ngep->param_en_100hdx = *(uint8_t *)pr_val;
15796200Smx205022 			ngep->param_adv_100hdx = *(uint8_t *)pr_val;
15806200Smx205022 			goto reprogram;
15816789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15826200Smx205022 			ngep->param_en_10fdx = *(uint8_t *)pr_val;
15836200Smx205022 			ngep->param_adv_10fdx = *(uint8_t *)pr_val;
15846200Smx205022 			goto reprogram;
15856789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15866200Smx205022 			ngep->param_en_10hdx = *(uint8_t *)pr_val;
15876200Smx205022 			ngep->param_adv_10hdx = *(uint8_t *)pr_val;
15886200Smx205022 reprogram:
15896200Smx205022 		(*ngep->physops->phys_update)(ngep);
15906200Smx205022 		nge_chip_sync(ngep);
15916200Smx205022 		break;
15926200Smx205022 
15936789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15946789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15956789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15966789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15976789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15986789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15996789Sam223141 		case MAC_PROP_STATUS:
16006789Sam223141 		case MAC_PROP_SPEED:
16016789Sam223141 		case MAC_PROP_DUPLEX:
16026789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
16036200Smx205022 			err = ENOTSUP; /* read-only prop. Can't set this */
16046200Smx205022 			break;
16056789Sam223141 		case MAC_PROP_AUTONEG:
16066200Smx205022 			ngep->param_adv_autoneg = *(uint8_t *)pr_val;
16076200Smx205022 			(*ngep->physops->phys_update)(ngep);
16086200Smx205022 			nge_chip_sync(ngep);
16096200Smx205022 			break;
16106789Sam223141 		case MAC_PROP_MTU:
16116200Smx205022 			cur_mtu = ngep->default_mtu;
16126200Smx205022 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
16136200Smx205022 			if (new_mtu == cur_mtu) {
16146200Smx205022 				err = 0;
16156200Smx205022 				break;
16166200Smx205022 			}
16176200Smx205022 			if (new_mtu < ETHERMTU ||
16186200Smx205022 			    new_mtu > NGE_MAX_MTU) {
16196200Smx205022 				err = EINVAL;
16206200Smx205022 				break;
16216200Smx205022 			}
16226200Smx205022 			if ((new_mtu > ETHERMTU) &&
16236200Smx205022 			    (!ngep->dev_spec_param.jumbo)) {
16246200Smx205022 				err = EINVAL;
16256200Smx205022 				break;
16266200Smx205022 			}
16276200Smx205022 			if (ngep->nge_mac_state == NGE_MAC_STARTED) {
16286200Smx205022 				err = EBUSY;
16296200Smx205022 				break;
16306200Smx205022 			}
16316200Smx205022 
16326200Smx205022 			ngep->default_mtu = new_mtu;
16336200Smx205022 			if (ngep->default_mtu > ETHERMTU &&
16346200Smx205022 			    ngep->default_mtu <= NGE_MTU_2500) {
16356200Smx205022 				ngep->buf_size = NGE_JB2500_BUFSZ;
16366200Smx205022 				ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
16376200Smx205022 				ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
16386200Smx205022 				ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
16396200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16406200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_2500 &&
16416200Smx205022 			    ngep->default_mtu <= NGE_MTU_4500) {
16426200Smx205022 				ngep->buf_size = NGE_JB4500_BUFSZ;
16436200Smx205022 				ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
16446200Smx205022 				ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
16456200Smx205022 				ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
16466200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16476200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_4500 &&
16486200Smx205022 			    ngep->default_mtu <= NGE_MAX_MTU) {
16496200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16506200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16516200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16526200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16536200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16546200Smx205022 			} else if (ngep->default_mtu > NGE_MAX_MTU) {
16556200Smx205022 				ngep->default_mtu = NGE_MAX_MTU;
16566200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16576200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16586200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16596200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16606200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16616200Smx205022 			} else if (ngep->lowmem_mode != 0) {
16626200Smx205022 				ngep->default_mtu = ETHERMTU;
16636200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16646200Smx205022 				ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
16656200Smx205022 				ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
16666200Smx205022 				ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
16676200Smx205022 				ngep->nge_split = NGE_SPLIT_32;
16686200Smx205022 			} else {
16696200Smx205022 				ngep->default_mtu = ETHERMTU;
16706200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16716200Smx205022 				ngep->tx_desc =
16726200Smx205022 				    ngep->dev_spec_param.tx_desc_num;
16736200Smx205022 				ngep->rx_desc =
16746200Smx205022 				    ngep->dev_spec_param.rx_desc_num;
16756200Smx205022 				ngep->rx_buf =
16766200Smx205022 				    ngep->dev_spec_param.rx_desc_num * 2;
16776200Smx205022 				ngep->nge_split =
16786200Smx205022 				    ngep->dev_spec_param.nge_split;
16796200Smx205022 			}
16806200Smx205022 
16816200Smx205022 			err = mac_maxsdu_update(ngep->mh, ngep->default_mtu);
16826200Smx205022 
16836200Smx205022 			break;
16846789Sam223141 		case MAC_PROP_FLOWCTRL:
16856200Smx205022 			bcopy(pr_val, &fl, sizeof (fl));
16866200Smx205022 			switch (fl) {
16876200Smx205022 			default:
16886200Smx205022 				err = ENOTSUP;
16896200Smx205022 				break;
16906200Smx205022 			case LINK_FLOWCTRL_NONE:
16916200Smx205022 				ngep->param_adv_pause = 0;
16926200Smx205022 				ngep->param_adv_asym_pause = 0;
16936200Smx205022 
16946200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
16956200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
16966200Smx205022 				break;
16976200Smx205022 			case LINK_FLOWCTRL_RX:
16986200Smx205022 				if (!((ngep->param_lp_pause == 0) &&
16996200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
17006200Smx205022 					err = EINVAL;
17016200Smx205022 					break;
17026200Smx205022 				}
17036200Smx205022 				ngep->param_adv_pause = 1;
17046200Smx205022 				ngep->param_adv_asym_pause = 1;
17056200Smx205022 
17066200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17076200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
17086200Smx205022 				break;
17096200Smx205022 			case LINK_FLOWCTRL_TX:
17106200Smx205022 				if (!((ngep->param_lp_pause == 1) &&
17116200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
17126200Smx205022 					err = EINVAL;
17136200Smx205022 					break;
17146200Smx205022 				}
17156200Smx205022 				ngep->param_adv_pause = 0;
17166200Smx205022 				ngep->param_adv_asym_pause = 1;
17176200Smx205022 
17186200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
17196200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17206200Smx205022 				break;
17216200Smx205022 			case LINK_FLOWCTRL_BI:
17226200Smx205022 				if (ngep->param_lp_pause != 1) {
17236200Smx205022 					err = EINVAL;
17246200Smx205022 					break;
17256200Smx205022 				}
17266200Smx205022 				ngep->param_adv_pause = 1;
17276200Smx205022 
17286200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17296200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17306200Smx205022 				break;
17316200Smx205022 			}
17326200Smx205022 
17336200Smx205022 			if (err == 0) {
17346200Smx205022 				(*ngep->physops->phys_update)(ngep);
17356200Smx205022 				nge_chip_sync(ngep);
17366200Smx205022 			}
17376200Smx205022 
17386200Smx205022 			break;
17396789Sam223141 		case MAC_PROP_PRIVATE:
17406200Smx205022 			err = nge_set_priv_prop(ngep, pr_name, pr_valsize,
17416200Smx205022 			    pr_val);
17426200Smx205022 			if (err == 0) {
17436200Smx205022 				(*ngep->physops->phys_update)(ngep);
17446200Smx205022 				nge_chip_sync(ngep);
17456200Smx205022 			}
17466200Smx205022 			break;
17476200Smx205022 		default:
17486200Smx205022 			err = ENOTSUP;
17496200Smx205022 	}
17506200Smx205022 	mutex_exit(ngep->genlock);
17516200Smx205022 	return (err);
17526200Smx205022 }
17536200Smx205022 
17546200Smx205022 static int
nge_m_getprop(void * barg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)17556200Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1756*11878SVenu.Iyer@Sun.COM     uint_t pr_valsize, void *pr_val)
17576200Smx205022 {
17586200Smx205022 	nge_t *ngep = barg;
17596512Ssowmini 	int err = 0;
17606200Smx205022 	link_flowctrl_t fl;
17616512Ssowmini 	uint64_t speed;
17628118SVasumathi.Sundaram@Sun.COM 
17636200Smx205022 	switch (pr_num) {
17646789Sam223141 		case MAC_PROP_DUPLEX:
1765*11878SVenu.Iyer@Sun.COM 			ASSERT(pr_valsize >= sizeof (link_duplex_t));
1766*11878SVenu.Iyer@Sun.COM 			bcopy(&ngep->param_link_duplex, pr_val,
1767*11878SVenu.Iyer@Sun.COM 			    sizeof (link_duplex_t));
17686200Smx205022 			break;
17696789Sam223141 		case MAC_PROP_SPEED:
1770*11878SVenu.Iyer@Sun.COM 			ASSERT(pr_valsize >= sizeof (uint64_t));
1771*11878SVenu.Iyer@Sun.COM 			speed = ngep->param_link_speed * 1000000ull;
1772*11878SVenu.Iyer@Sun.COM 			bcopy(&speed, pr_val, sizeof (speed));
17736200Smx205022 			break;
17746789Sam223141 		case MAC_PROP_AUTONEG:
1775*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_adv_autoneg;
17766200Smx205022 			break;
17776789Sam223141 		case MAC_PROP_FLOWCTRL:
1778*11878SVenu.Iyer@Sun.COM 			ASSERT(pr_valsize >= sizeof (link_flowctrl_t));
1779*11878SVenu.Iyer@Sun.COM 			if (ngep->param_link_rx_pause &&
1780*11878SVenu.Iyer@Sun.COM 			    !ngep->param_link_tx_pause)
1781*11878SVenu.Iyer@Sun.COM 				fl = LINK_FLOWCTRL_RX;
1782*11878SVenu.Iyer@Sun.COM 
1783*11878SVenu.Iyer@Sun.COM 			if (!ngep->param_link_rx_pause &&
1784*11878SVenu.Iyer@Sun.COM 			    !ngep->param_link_tx_pause)
1785*11878SVenu.Iyer@Sun.COM 				fl = LINK_FLOWCTRL_NONE;
1786*11878SVenu.Iyer@Sun.COM 
1787*11878SVenu.Iyer@Sun.COM 			if (!ngep->param_link_rx_pause &&
1788*11878SVenu.Iyer@Sun.COM 			    ngep->param_link_tx_pause)
1789*11878SVenu.Iyer@Sun.COM 				fl = LINK_FLOWCTRL_TX;
1790*11878SVenu.Iyer@Sun.COM 
1791*11878SVenu.Iyer@Sun.COM 			if (ngep->param_link_rx_pause &&
1792*11878SVenu.Iyer@Sun.COM 			    ngep->param_link_tx_pause)
1793*11878SVenu.Iyer@Sun.COM 				fl = LINK_FLOWCTRL_BI;
1794*11878SVenu.Iyer@Sun.COM 			bcopy(&fl, pr_val, sizeof (fl));
17956200Smx205022 			break;
17966789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
1797*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_adv_1000fdx;
17986200Smx205022 			break;
17996789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
1800*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_en_1000fdx;
18016200Smx205022 			break;
18026789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
1803*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_adv_1000hdx;
18046200Smx205022 			break;
18056789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
1806*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_en_1000hdx;
18076200Smx205022 			break;
18086789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
1809*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_adv_100fdx;
18106200Smx205022 			break;
18116789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
1812*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_en_100fdx;
18136200Smx205022 			break;
18146789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
1815*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_adv_100hdx;
18166200Smx205022 			break;
18176789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
1818*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_en_100hdx;
18196200Smx205022 			break;
18206789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
1821*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_adv_10fdx;
18226200Smx205022 			break;
18236789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
1824*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_en_10fdx;
18256200Smx205022 			break;
18266789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
1827*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_adv_10hdx;
18286200Smx205022 			break;
18296789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
1830*11878SVenu.Iyer@Sun.COM 			*(uint8_t *)pr_val = ngep->param_en_10hdx;
18316200Smx205022 			break;
18326789Sam223141 		case MAC_PROP_ADV_100T4_CAP:
18336789Sam223141 		case MAC_PROP_EN_100T4_CAP:
18346512Ssowmini 			*(uint8_t *)pr_val = 0;
18356512Ssowmini 			break;
18366789Sam223141 		case MAC_PROP_PRIVATE:
1837*11878SVenu.Iyer@Sun.COM 			err = nge_get_priv_prop(ngep, pr_name,
18386512Ssowmini 			    pr_valsize, pr_val);
18396200Smx205022 			break;
18406200Smx205022 		default:
18416200Smx205022 			err = ENOTSUP;
18426200Smx205022 	}
18436200Smx205022 	return (err);
18446200Smx205022 }
18456200Smx205022 
1846*11878SVenu.Iyer@Sun.COM static void
nge_m_propinfo(void * barg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)1847*11878SVenu.Iyer@Sun.COM nge_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num,
1848*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t prh)
1849*11878SVenu.Iyer@Sun.COM {
1850*11878SVenu.Iyer@Sun.COM 	nge_t *ngep = barg;
1851*11878SVenu.Iyer@Sun.COM 
1852*11878SVenu.Iyer@Sun.COM 	switch (pr_num) {
1853*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_DUPLEX:
1854*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_SPEED:
1855*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_1000FDX_CAP:
1856*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_1000HDX_CAP:
1857*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
1858*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_1000HDX_CAP:
1859*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
1860*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
1861*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
1862*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
1863*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
1864*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1865*11878SVenu.Iyer@Sun.COM 		break;
1866*11878SVenu.Iyer@Sun.COM 
1867*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_1000FDX_CAP:
1868*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
1869*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
1870*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
1871*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
1872*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, 1);
1873*11878SVenu.Iyer@Sun.COM 		break;
1874*11878SVenu.Iyer@Sun.COM 
1875*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_AUTONEG:
1876*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_uint8(prh, 1);
1877*11878SVenu.Iyer@Sun.COM 		break;
1878*11878SVenu.Iyer@Sun.COM 
1879*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_FLOWCTRL:
1880*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI);
1881*11878SVenu.Iyer@Sun.COM 		break;
1882*11878SVenu.Iyer@Sun.COM 
1883*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_MTU:
1884*11878SVenu.Iyer@Sun.COM 		mac_prop_info_set_range_uint32(prh, ETHERMTU,
1885*11878SVenu.Iyer@Sun.COM 		    ngep->dev_spec_param.jumbo ? NGE_MAX_MTU : ETHERMTU);
1886*11878SVenu.Iyer@Sun.COM 		break;
1887*11878SVenu.Iyer@Sun.COM 
1888*11878SVenu.Iyer@Sun.COM 	case MAC_PROP_PRIVATE: {
1889*11878SVenu.Iyer@Sun.COM 		char valstr[64];
1890*11878SVenu.Iyer@Sun.COM 		int value;
1891*11878SVenu.Iyer@Sun.COM 
1892*11878SVenu.Iyer@Sun.COM 		bzero(valstr, sizeof (valstr));
1893*11878SVenu.Iyer@Sun.COM 		if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
1894*11878SVenu.Iyer@Sun.COM 			value = NGE_TX_COPY_SIZE;
1895*11878SVenu.Iyer@Sun.COM 		} else 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
1896*11878SVenu.Iyer@Sun.COM 			value = NGE_RX_COPY_SIZE;
1897*11878SVenu.Iyer@Sun.COM 		} else 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
1898*11878SVenu.Iyer@Sun.COM 			value = 128;
1899*11878SVenu.Iyer@Sun.COM 		} else 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
1900*11878SVenu.Iyer@Sun.COM 			value = NGE_POLL_QUIET_TIME;
1901*11878SVenu.Iyer@Sun.COM 		} else 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
1902*11878SVenu.Iyer@Sun.COM 			value = NGE_POLL_BUSY_TIME;
1903*11878SVenu.Iyer@Sun.COM 		} else	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
1904*11878SVenu.Iyer@Sun.COM 			value = 1;
1905*11878SVenu.Iyer@Sun.COM 		} else 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
1906*11878SVenu.Iyer@Sun.COM 			value = 8;
1907*11878SVenu.Iyer@Sun.COM 		} else {
1908*11878SVenu.Iyer@Sun.COM 			return;
1909*11878SVenu.Iyer@Sun.COM 		}
1910*11878SVenu.Iyer@Sun.COM 
1911*11878SVenu.Iyer@Sun.COM 		(void) snprintf(valstr, sizeof (valstr), "%d", value);
1912*11878SVenu.Iyer@Sun.COM 	}
1913*11878SVenu.Iyer@Sun.COM 	}
1914*11878SVenu.Iyer@Sun.COM 
1915*11878SVenu.Iyer@Sun.COM }
1916*11878SVenu.Iyer@Sun.COM 
19176200Smx205022 /* ARGSUSED */
19186200Smx205022 static int
nge_set_priv_prop(nge_t * ngep,const char * pr_name,uint_t pr_valsize,const void * pr_val)19196200Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
19206200Smx205022     const void *pr_val)
19216200Smx205022 {
19226200Smx205022 	int err = 0;
19236200Smx205022 	long result;
19246200Smx205022 
19256200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
19266200Smx205022 		if (pr_val == NULL) {
19276200Smx205022 			err = EINVAL;
19286200Smx205022 			return (err);
19296200Smx205022 		}
19306200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19316200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19326200Smx205022 			err = EINVAL;
19336200Smx205022 		} else {
19346200Smx205022 			ngep->param_txbcopy_threshold = (uint32_t)result;
19356200Smx205022 			goto reprogram;
19366200Smx205022 		}
19376200Smx205022 		return (err);
19386200Smx205022 	}
19396200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
19406200Smx205022 		if (pr_val == NULL) {
19416200Smx205022 			err = EINVAL;
19426200Smx205022 			return (err);
19436200Smx205022 		}
19446200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19456200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19466200Smx205022 			err = EINVAL;
19476200Smx205022 		} else {
19486200Smx205022 			ngep->param_rxbcopy_threshold = (uint32_t)result;
19496200Smx205022 			goto reprogram;
19506200Smx205022 		}
19516200Smx205022 		return (err);
19526200Smx205022 	}
19536200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
19546200Smx205022 		if (pr_val == NULL) {
19556200Smx205022 			err = EINVAL;
19566200Smx205022 			return (err);
19576200Smx205022 		}
19586200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19596200Smx205022 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
19606200Smx205022 			err = EINVAL;
19616200Smx205022 		} else {
19626200Smx205022 			ngep->param_recv_max_packet = (uint32_t)result;
19636200Smx205022 			goto reprogram;
19646200Smx205022 		}
19656200Smx205022 		return (err);
19666200Smx205022 	}
19676200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
19686200Smx205022 		if (pr_val == NULL) {
19696200Smx205022 			err = EINVAL;
19706200Smx205022 			return (err);
19716200Smx205022 		}
19726200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19736200Smx205022 		if (result < 0 || result > 10000) {
19746200Smx205022 			err = EINVAL;
19756200Smx205022 		} else {
19766200Smx205022 			ngep->param_poll_quiet_time = (uint32_t)result;
19776200Smx205022 			goto reprogram;
19786200Smx205022 		}
19796200Smx205022 		return (err);
19806200Smx205022 	}
19816200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
19826200Smx205022 		if (pr_val == NULL) {
19836200Smx205022 			err = EINVAL;
19846200Smx205022 			return (err);
19856200Smx205022 		}
19866200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19876200Smx205022 		if (result < 0 || result > 10000) {
19886200Smx205022 			err = EINVAL;
19896200Smx205022 		} else {
19906200Smx205022 			ngep->param_poll_busy_time = (uint32_t)result;
19916200Smx205022 			goto reprogram;
19926200Smx205022 		}
19936200Smx205022 		return (err);
19946200Smx205022 	}
19956200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
19966200Smx205022 		if (pr_val == NULL) {
19976200Smx205022 			err = EINVAL;
19986200Smx205022 			return (err);
19996200Smx205022 		}
20006200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20016512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20026200Smx205022 			err = EINVAL;
20036200Smx205022 		} else {
20046200Smx205022 			ngep->param_rx_intr_hwater = (uint32_t)result;
20056200Smx205022 			goto reprogram;
20066200Smx205022 		}
20076200Smx205022 		return (err);
20086200Smx205022 	}
20096200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
20106200Smx205022 		if (pr_val == NULL) {
20116200Smx205022 			err = EINVAL;
20126200Smx205022 			return (err);
20136200Smx205022 		}
20146200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20156512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20166200Smx205022 			err = EINVAL;
20176200Smx205022 		} else {
20186200Smx205022 			ngep->param_rx_intr_lwater = (uint32_t)result;
20196200Smx205022 			goto reprogram;
20206200Smx205022 		}
20216200Smx205022 		return (err);
20226200Smx205022 	}
20236200Smx205022 	err = ENOTSUP;
20246200Smx205022 	return (err);
20256200Smx205022 
20266200Smx205022 reprogram:
20276200Smx205022 	if (err == 0) {
20286200Smx205022 		(*ngep->physops->phys_update)(ngep);
20296200Smx205022 		nge_chip_sync(ngep);
20306200Smx205022 	}
20316200Smx205022 
20326200Smx205022 	return (err);
20336200Smx205022 }
20346200Smx205022 
20356200Smx205022 static int
nge_get_priv_prop(nge_t * ngep,const char * pr_name,uint_t pr_valsize,void * pr_val)2036*11878SVenu.Iyer@Sun.COM nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
2037*11878SVenu.Iyer@Sun.COM     void *pr_val)
20386200Smx205022 {
20396200Smx205022 	int err = ENOTSUP;
20406512Ssowmini 	int value;
20416512Ssowmini 
20426200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
2043*11878SVenu.Iyer@Sun.COM 		value = ngep->param_txbcopy_threshold;
20446200Smx205022 		err = 0;
20456200Smx205022 		goto done;
20466200Smx205022 	}
20476200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
2048*11878SVenu.Iyer@Sun.COM 		value = ngep->param_rxbcopy_threshold;
20496200Smx205022 		err = 0;
20506200Smx205022 		goto done;
20516200Smx205022 	}
20526200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
2053*11878SVenu.Iyer@Sun.COM 		value = ngep->param_recv_max_packet;
20546200Smx205022 		err = 0;
20556200Smx205022 		goto done;
20566200Smx205022 	}
20576200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
2058*11878SVenu.Iyer@Sun.COM 		value = ngep->param_poll_quiet_time;
20596200Smx205022 		err = 0;
20606200Smx205022 		goto done;
20616200Smx205022 	}
20626200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
2063*11878SVenu.Iyer@Sun.COM 		value = ngep->param_poll_busy_time;
20646200Smx205022 		err = 0;
20656200Smx205022 		goto done;
20666200Smx205022 	}
20676200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
2068*11878SVenu.Iyer@Sun.COM 		value = ngep->param_rx_intr_hwater;
20696200Smx205022 		err = 0;
20706200Smx205022 		goto done;
20716200Smx205022 	}
20726200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
2073*11878SVenu.Iyer@Sun.COM 		value = ngep->param_rx_intr_lwater;
20746200Smx205022 		err = 0;
20756200Smx205022 		goto done;
20766200Smx205022 	}
20776200Smx205022 
20786200Smx205022 done:
20796200Smx205022 	if (err == 0) {
20806512Ssowmini 		(void) snprintf(pr_val, pr_valsize, "%d", value);
20816200Smx205022 	}
20826200Smx205022 	return (err);
20836200Smx205022 }
20846200Smx205022 
20855574Smx205022 /* ARGSUSED */
20865574Smx205022 static boolean_t
nge_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)20875574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
20885574Smx205022 {
20895574Smx205022 	nge_t	*ngep = arg;
20905574Smx205022 	nge_dev_spec_param_t *dev_param_p;
20915574Smx205022 
20925574Smx205022 	dev_param_p = &ngep->dev_spec_param;
20935574Smx205022 
20945574Smx205022 	switch (cap) {
20955574Smx205022 	case MAC_CAPAB_HCKSUM: {
20965574Smx205022 		uint32_t *hcksum_txflags = cap_data;
20975574Smx205022 
20985574Smx205022 		if (dev_param_p->tx_hw_checksum) {
20995574Smx205022 			*hcksum_txflags = dev_param_p->tx_hw_checksum;
21005574Smx205022 		} else
21015574Smx205022 			return (B_FALSE);
21025574Smx205022 		break;
21035574Smx205022 	}
21045574Smx205022 	default:
21055574Smx205022 		return (B_FALSE);
21065574Smx205022 	}
21075574Smx205022 	return (B_TRUE);
21085574Smx205022 }
21095574Smx205022 
21105574Smx205022 #undef	NGE_DBG
21115574Smx205022 #define	NGE_DBG	NGE_DBG_INIT	/* debug flag for this code	*/
21125574Smx205022 int
nge_restart(nge_t * ngep)21135574Smx205022 nge_restart(nge_t *ngep)
21145574Smx205022 {
21155574Smx205022 	int err = 0;
21167656SSherry.Moore@Sun.COM 	err = nge_reset_dev(ngep);
21177155Smx205022 	/* write back the promisc setting */
21187155Smx205022 	ngep->promisc = ngep->record_promisc;
21196366Smx205022 	nge_chip_sync(ngep);
21205869Smx205022 	if (!err)
21215869Smx205022 		err = nge_chip_start(ngep);
21225574Smx205022 
21235574Smx205022 	if (err) {
21245574Smx205022 		ngep->nge_mac_state = NGE_MAC_STOPPED;
21255574Smx205022 		return (DDI_FAILURE);
21265574Smx205022 	} else {
21275574Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
21285574Smx205022 		return (DDI_SUCCESS);
21295574Smx205022 	}
21305574Smx205022 }
21315574Smx205022 
21325574Smx205022 void
nge_wake_factotum(nge_t * ngep)21335574Smx205022 nge_wake_factotum(nge_t *ngep)
21345574Smx205022 {
21355574Smx205022 	mutex_enter(ngep->softlock);
21365574Smx205022 	if (ngep->factotum_flag == 0) {
21375574Smx205022 		ngep->factotum_flag = 1;
21385574Smx205022 		(void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
21395574Smx205022 	}
21405574Smx205022 	mutex_exit(ngep->softlock);
21415574Smx205022 }
21425574Smx205022 
214310615SZhen.W@Sun.COM void
nge_interrupt_optimize(nge_t * ngep)214410615SZhen.W@Sun.COM nge_interrupt_optimize(nge_t *ngep)
214510615SZhen.W@Sun.COM {
214610615SZhen.W@Sun.COM 	uint32_t tx_pkts;
214710615SZhen.W@Sun.COM 	tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last;
214810615SZhen.W@Sun.COM 	ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count;
214910615SZhen.W@Sun.COM 	if ((tx_pkts > NGE_POLL_TUNE) &&
215010615SZhen.W@Sun.COM 	    (tx_pkts <= NGE_POLL_MAX))
215110615SZhen.W@Sun.COM 		ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER);
215210615SZhen.W@Sun.COM 	else
215310615SZhen.W@Sun.COM 		ngep->tfint_threshold = NGE_TFINT_DEFAULT;
215410615SZhen.W@Sun.COM }
215510615SZhen.W@Sun.COM 
21565574Smx205022 /*
21575574Smx205022  * High-level cyclic handler
21585574Smx205022  *
21595574Smx205022  * This routine schedules a (low-level) softint callback to the
21605574Smx205022  * factotum.
21615574Smx205022  */
21625574Smx205022 
21635574Smx205022 static void
nge_chip_cyclic(void * arg)21645574Smx205022 nge_chip_cyclic(void *arg)
21655574Smx205022 {
21665574Smx205022 	nge_t *ngep;
21675574Smx205022 
21685574Smx205022 	ngep = (nge_t *)arg;
21695574Smx205022 
21705574Smx205022 	switch (ngep->nge_chip_state) {
21715574Smx205022 	default:
21725574Smx205022 		return;
21735574Smx205022 
21745574Smx205022 	case NGE_CHIP_RUNNING:
217510615SZhen.W@Sun.COM 		nge_interrupt_optimize(ngep);
21765574Smx205022 		break;
21775574Smx205022 
21785574Smx205022 	case NGE_CHIP_FAULT:
21795574Smx205022 	case NGE_CHIP_ERROR:
21805574Smx205022 		break;
21815574Smx205022 	}
21825574Smx205022 
21835574Smx205022 	nge_wake_factotum(ngep);
21845574Smx205022 }
21855574Smx205022 
21869604SZhen.W@Sun.COM /*
21879604SZhen.W@Sun.COM  * Get/Release semaphore of SMU
21889604SZhen.W@Sun.COM  * For SMU enabled chipset
21899604SZhen.W@Sun.COM  * When nge driver is attached, driver should acquire
21909604SZhen.W@Sun.COM  * semaphore before PHY init and accessing MAC registers.
21919604SZhen.W@Sun.COM  * When nge driver is unattached, driver should release
21929604SZhen.W@Sun.COM  * semaphore.
21939604SZhen.W@Sun.COM  */
21949604SZhen.W@Sun.COM 
21959604SZhen.W@Sun.COM static int
nge_smu_sema(nge_t * ngep,boolean_t acquire)21969604SZhen.W@Sun.COM nge_smu_sema(nge_t *ngep, boolean_t acquire)
21979604SZhen.W@Sun.COM {
21989604SZhen.W@Sun.COM 	nge_tx_en tx_en;
21999604SZhen.W@Sun.COM 	uint32_t tries;
22009604SZhen.W@Sun.COM 
22019604SZhen.W@Sun.COM 	if (acquire) {
22029604SZhen.W@Sun.COM 		for (tries = 0; tries < 5; tries++) {
22039604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
22049604SZhen.W@Sun.COM 			if (tx_en.bits.smu2mac == NGE_SMU_FREE)
22059604SZhen.W@Sun.COM 				break;
22069604SZhen.W@Sun.COM 			delay(drv_usectohz(1000000));
22079604SZhen.W@Sun.COM 		}
22089604SZhen.W@Sun.COM 		if (tx_en.bits.smu2mac != NGE_SMU_FREE)
22099604SZhen.W@Sun.COM 			return (DDI_FAILURE);
22109604SZhen.W@Sun.COM 		for (tries = 0; tries < 5; tries++) {
22119604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
22129604SZhen.W@Sun.COM 			tx_en.bits.mac2smu = NGE_SMU_GET;
22139604SZhen.W@Sun.COM 			nge_reg_put32(ngep, NGE_TX_EN, tx_en.val);
22149604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
22159604SZhen.W@Sun.COM 
22169604SZhen.W@Sun.COM 			if (tx_en.bits.mac2smu == NGE_SMU_GET &&
22179604SZhen.W@Sun.COM 			    tx_en.bits.smu2mac == NGE_SMU_FREE)
22189604SZhen.W@Sun.COM 				return (DDI_SUCCESS);
22199604SZhen.W@Sun.COM 			drv_usecwait(10);
22209604SZhen.W@Sun.COM 		}
22219604SZhen.W@Sun.COM 		return (DDI_FAILURE);
22229604SZhen.W@Sun.COM 	} else
22239604SZhen.W@Sun.COM 		nge_reg_put32(ngep, NGE_TX_EN, 0x0);
22249604SZhen.W@Sun.COM 
22259604SZhen.W@Sun.COM 	return (DDI_SUCCESS);
22269604SZhen.W@Sun.COM 
22279604SZhen.W@Sun.COM }
22285574Smx205022 static void
nge_unattach(nge_t * ngep)22295574Smx205022 nge_unattach(nge_t *ngep)
22305574Smx205022 {
22315574Smx205022 	send_ring_t *srp;
22325574Smx205022 	buff_ring_t *brp;
22335574Smx205022 
22345574Smx205022 	srp = ngep->send;
22355574Smx205022 	brp = ngep->buff;
22365574Smx205022 	NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
22375574Smx205022 
22385574Smx205022 	/*
22395574Smx205022 	 * Flag that no more activity may be initiated
22405574Smx205022 	 */
22415574Smx205022 	ngep->progress &= ~PROGRESS_READY;
22425574Smx205022 	ngep->nge_mac_state = NGE_MAC_UNATTACH;
22435574Smx205022 
22445574Smx205022 	/*
22455574Smx205022 	 * Quiesce the PHY and MAC (leave it reset but still powered).
22465574Smx205022 	 * Clean up and free all NGE data structures
22475574Smx205022 	 */
22485574Smx205022 	if (ngep->periodic_id != NULL) {
22495574Smx205022 		ddi_periodic_delete(ngep->periodic_id);
22505574Smx205022 		ngep->periodic_id = NULL;
22515574Smx205022 	}
22525574Smx205022 
22535574Smx205022 	if (ngep->progress & PROGRESS_KSTATS)
22545574Smx205022 		nge_fini_kstats(ngep);
22555574Smx205022 
22565574Smx205022 	if (ngep->progress & PROGRESS_HWINT) {
22575574Smx205022 		mutex_enter(ngep->genlock);
22585574Smx205022 		nge_restore_mac_addr(ngep);
22595574Smx205022 		(void) nge_chip_stop(ngep, B_FALSE);
22609604SZhen.W@Sun.COM 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
22619604SZhen.W@Sun.COM 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
22629604SZhen.W@Sun.COM 			(void) nge_smu_sema(ngep, B_FALSE);
22639604SZhen.W@Sun.COM 		}
22645574Smx205022 		mutex_exit(ngep->genlock);
22655574Smx205022 	}
22665574Smx205022 
22675574Smx205022 	if (ngep->progress & PROGRESS_SWINT)
22685574Smx205022 		nge_rem_intrs(ngep);
22695574Smx205022 
22705574Smx205022 	if (ngep->progress & PROGRESS_FACTOTUM)
22715574Smx205022 		(void) ddi_intr_remove_softint(ngep->factotum_hdl);
22725574Smx205022 
22735574Smx205022 	if (ngep->progress & PROGRESS_RESCHED)
22745574Smx205022 		(void) ddi_intr_remove_softint(ngep->resched_hdl);
22755574Smx205022 
22765574Smx205022 	if (ngep->progress & PROGRESS_INTR) {
22775574Smx205022 		mutex_destroy(srp->tx_lock);
22785574Smx205022 		mutex_destroy(srp->tc_lock);
22795574Smx205022 		mutex_destroy(&srp->dmah_lock);
22805574Smx205022 		mutex_destroy(brp->recycle_lock);
22815574Smx205022 
22825574Smx205022 		mutex_destroy(ngep->genlock);
22835574Smx205022 		mutex_destroy(ngep->softlock);
22845574Smx205022 		rw_destroy(ngep->rwlock);
22855574Smx205022 	}
22865574Smx205022 
22875574Smx205022 	if (ngep->progress & PROGRESS_REGS)
22885574Smx205022 		ddi_regs_map_free(&ngep->io_handle);
22895574Smx205022 
22905574Smx205022 	if (ngep->progress & PROGRESS_CFG)
22915574Smx205022 		pci_config_teardown(&ngep->cfg_handle);
22925574Smx205022 
22935574Smx205022 	ddi_remove_minor_node(ngep->devinfo, NULL);
22945574Smx205022 
22955574Smx205022 	kmem_free(ngep, sizeof (*ngep));
22965574Smx205022 }
22975574Smx205022 
22985574Smx205022 static int
nge_resume(dev_info_t * devinfo)22995574Smx205022 nge_resume(dev_info_t *devinfo)
23005574Smx205022 {
23015574Smx205022 	nge_t		*ngep;
23025574Smx205022 	chip_info_t	*infop;
23035869Smx205022 	int 		err;
23045574Smx205022 
23055574Smx205022 	ASSERT(devinfo != NULL);
23065574Smx205022 
23075574Smx205022 	ngep = ddi_get_driver_private(devinfo);
23085869Smx205022 	err = 0;
23095869Smx205022 
23105574Smx205022 	/*
23115574Smx205022 	 * If there are state inconsistancies, this is bad.  Returning
23125574Smx205022 	 * DDI_FAILURE here will eventually cause the machine to panic,
23135574Smx205022 	 * so it is best done here so that there is a possibility of
23145574Smx205022 	 * debugging the problem.
23155574Smx205022 	 */
23165574Smx205022 	if (ngep == NULL)
23175574Smx205022 		cmn_err(CE_PANIC,
23185574Smx205022 		    "nge: ngep returned from ddi_get_driver_private was NULL");
23195574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
23205574Smx205022 
23215574Smx205022 	if (ngep->devinfo != devinfo)
23225574Smx205022 		cmn_err(CE_PANIC,
23235869Smx205022 		    "nge: passed devinfo not the same as saved devinfo");
23245574Smx205022 
23255869Smx205022 	mutex_enter(ngep->genlock);
23265869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
23275574Smx205022 
23285574Smx205022 	/*
23295574Smx205022 	 * Fetch the config space.  Even though we have most of it cached,
23305574Smx205022 	 * some values *might* change across a suspend/resume.
23315574Smx205022 	 */
23325574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
23335574Smx205022 
23345574Smx205022 	/*
23355869Smx205022 	 * Only in one case, this conditional branch can be executed: the port
23365869Smx205022 	 * hasn't been plumbed.
23375574Smx205022 	 */
23385869Smx205022 	if (ngep->suspended == B_FALSE) {
23395869Smx205022 		rw_exit(ngep->rwlock);
23405869Smx205022 		mutex_exit(ngep->genlock);
23415869Smx205022 		return (DDI_SUCCESS);
23425869Smx205022 	}
23435869Smx205022 
23445869Smx205022 	nge_tx_recycle_all(ngep);
23455869Smx205022 	err = nge_reinit_ring(ngep);
23465869Smx205022 	if (!err) {
23475869Smx205022 		err = nge_chip_reset(ngep);
23485869Smx205022 		if (!err)
23495869Smx205022 			err = nge_chip_start(ngep);
23505869Smx205022 	}
23515869Smx205022 
23525869Smx205022 	if (err) {
23535574Smx205022 		/*
23545574Smx205022 		 * We note the failure, but return success, as the
23555574Smx205022 		 * system is still usable without this controller.
23565574Smx205022 		 */
23575574Smx205022 		cmn_err(CE_WARN, "nge: resume: failed to restart controller");
23585869Smx205022 	} else {
23595869Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
23605574Smx205022 	}
23615869Smx205022 	ngep->suspended = B_FALSE;
23625869Smx205022 
23635869Smx205022 	rw_exit(ngep->rwlock);
23645869Smx205022 	mutex_exit(ngep->genlock);
23655869Smx205022 
23665574Smx205022 	return (DDI_SUCCESS);
23675574Smx205022 }
23685574Smx205022 
23695574Smx205022 /*
23705574Smx205022  * attach(9E) -- Attach a device to the system
23715574Smx205022  *
23725574Smx205022  * Called once for each board successfully probed.
23735574Smx205022  */
23745574Smx205022 static int
nge_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)23755574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
23765574Smx205022 {
23775574Smx205022 	int		err;
23785574Smx205022 	int		i;
23795574Smx205022 	int		instance;
23805574Smx205022 	caddr_t		regs;
23815574Smx205022 	nge_t		*ngep;
23825574Smx205022 	chip_info_t	*infop;
23835574Smx205022 	mac_register_t	*macp;
23845574Smx205022 
23855574Smx205022 	switch (cmd) {
23865574Smx205022 	default:
23875574Smx205022 		return (DDI_FAILURE);
23885574Smx205022 
23895574Smx205022 	case DDI_RESUME:
23905574Smx205022 		return (nge_resume(devinfo));
23915574Smx205022 
23925574Smx205022 	case DDI_ATTACH:
23935574Smx205022 		break;
23945574Smx205022 	}
23955574Smx205022 
23965574Smx205022 	ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
23975574Smx205022 	instance = ddi_get_instance(devinfo);
23985574Smx205022 	ddi_set_driver_private(devinfo, ngep);
23995574Smx205022 	ngep->devinfo = devinfo;
24005574Smx205022 
24015574Smx205022 	(void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
24025574Smx205022 	    NGE_DRIVER_NAME, instance);
24035574Smx205022 	err = pci_config_setup(devinfo, &ngep->cfg_handle);
24045574Smx205022 	if (err != DDI_SUCCESS) {
24055574Smx205022 		nge_problem(ngep, "nge_attach: pci_config_setup() failed");
24065574Smx205022 		goto attach_fail;
24075574Smx205022 	}
24086512Ssowmini 	/*
24096512Ssowmini 	 * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy
24106512Ssowmini 	 * thresholds. Bounds: min 0, max NGE_MAX_SDU
24116512Ssowmini 	 */
24126512Ssowmini 	ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE;
24136512Ssowmini 	ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE;
24146512Ssowmini 
24156512Ssowmini 	/*
24166512Ssowmini 	 * param_recv_max_packet is max packet received per interupt.
24176512Ssowmini 	 * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024
24186512Ssowmini 	 */
24196512Ssowmini 	ngep->param_recv_max_packet = 128;
24206512Ssowmini 
24216512Ssowmini 	/*
24226512Ssowmini 	 * param_poll_quiet_time and param_poll_busy_time are quiet/busy time
24236512Ssowmini 	 * switch from per packet interrupt to polling interrupt.
24246512Ssowmini 	 * Bounds: min 0, max 10000
24256512Ssowmini 	 */
24266512Ssowmini 	ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
24276512Ssowmini 	ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
242810615SZhen.W@Sun.COM 	ngep->tfint_threshold = NGE_TFINT_DEFAULT;
242910615SZhen.W@Sun.COM 	ngep->poll = B_FALSE;
243010615SZhen.W@Sun.COM 	ngep->ch_intr_mode = B_FALSE;
24316512Ssowmini 
24326512Ssowmini 	/*
24336512Ssowmini 	 * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
24346512Ssowmini 	 * to trigger the poll_quiet_time/poll_busy_time counter.
24356512Ssowmini 	 * Bounds: min 0, max  NGE_RECV_SLOTS_DESC_1024.
24366512Ssowmini 	 */
24376512Ssowmini 	ngep->param_rx_intr_hwater = 1;
24386512Ssowmini 	ngep->param_rx_intr_lwater = 8;
24396512Ssowmini 
24406512Ssowmini 
24415574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
24425574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
24435574Smx205022 	nge_init_dev_spec_param(ngep);
24445574Smx205022 	nge_get_props(ngep);
24455574Smx205022 	ngep->progress |= PROGRESS_CFG;
24465574Smx205022 
24475574Smx205022 	err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
24485574Smx205022 	    &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
24495574Smx205022 	if (err != DDI_SUCCESS) {
24505574Smx205022 		nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
24515574Smx205022 		goto attach_fail;
24525574Smx205022 	}
24535574Smx205022 	ngep->io_regs = regs;
24545574Smx205022 	ngep->progress |= PROGRESS_REGS;
24555574Smx205022 
24565574Smx205022 	err = nge_register_intrs_and_init_locks(ngep);
24575574Smx205022 	if (err != DDI_SUCCESS) {
24585574Smx205022 		nge_problem(ngep, "nge_attach:"
24595574Smx205022 		    " register intrs and init locks failed");
24605574Smx205022 		goto attach_fail;
24615574Smx205022 	}
24625574Smx205022 	nge_init_ring_param_lock(ngep);
24635574Smx205022 	ngep->progress |= PROGRESS_INTR;
24645574Smx205022 
24655574Smx205022 	mutex_enter(ngep->genlock);
24665574Smx205022 
24679604SZhen.W@Sun.COM 	if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
24689604SZhen.W@Sun.COM 	    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
24699604SZhen.W@Sun.COM 		err = nge_smu_sema(ngep, B_TRUE);
24709604SZhen.W@Sun.COM 		if (err != DDI_SUCCESS) {
24719604SZhen.W@Sun.COM 			nge_problem(ngep, "nge_attach: nge_smu_sema() failed");
24729604SZhen.W@Sun.COM 			goto attach_fail;
24739604SZhen.W@Sun.COM 		}
24749604SZhen.W@Sun.COM 	}
24755574Smx205022 	/*
24765574Smx205022 	 * Initialise link state variables
24775574Smx205022 	 * Stop, reset & reinitialise the chip.
24785574Smx205022 	 * Initialise the (internal) PHY.
24795574Smx205022 	 */
24805574Smx205022 	nge_phys_init(ngep);
24818218SMin.Xu@Sun.COM 	ngep->nge_chip_state = NGE_CHIP_INITIAL;
24825574Smx205022 	err = nge_chip_reset(ngep);
24835574Smx205022 	if (err != DDI_SUCCESS) {
24845574Smx205022 		nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
24855574Smx205022 		mutex_exit(ngep->genlock);
24865574Smx205022 		goto attach_fail;
24875574Smx205022 	}
24885574Smx205022 	nge_chip_sync(ngep);
24895574Smx205022 
24905574Smx205022 	/*
24915574Smx205022 	 * Now that mutex locks are initialized, enable interrupts.
24925574Smx205022 	 */
24935574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
24945574Smx205022 		/* Call ddi_intr_block_enable() for MSI interrupts */
24955574Smx205022 		(void) ddi_intr_block_enable(ngep->htable,
24965574Smx205022 		    ngep->intr_actual_cnt);
24975574Smx205022 	} else {
24985574Smx205022 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
24995574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
25005574Smx205022 			(void) ddi_intr_enable(ngep->htable[i]);
25015574Smx205022 		}
25025574Smx205022 	}
25035574Smx205022 
25045574Smx205022 	ngep->link_state = LINK_STATE_UNKNOWN;
25055574Smx205022 	ngep->progress |= PROGRESS_HWINT;
25065574Smx205022 
25075574Smx205022 	/*
25085574Smx205022 	 * Register NDD-tweakable parameters
25095574Smx205022 	 */
25105574Smx205022 	if (nge_nd_init(ngep)) {
25115574Smx205022 		nge_problem(ngep, "nge_attach: nge_nd_init() failed");
25125574Smx205022 		mutex_exit(ngep->genlock);
25135574Smx205022 		goto attach_fail;
25145574Smx205022 	}
25155574Smx205022 	ngep->progress |= PROGRESS_NDD;
25165574Smx205022 
25175574Smx205022 	/*
25185574Smx205022 	 * Create & initialise named kstats
25195574Smx205022 	 */
25205574Smx205022 	nge_init_kstats(ngep, instance);
25215574Smx205022 	ngep->progress |= PROGRESS_KSTATS;
25225574Smx205022 
25235574Smx205022 	mutex_exit(ngep->genlock);
25245574Smx205022 
25255574Smx205022 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
25265574Smx205022 		goto attach_fail;
25275574Smx205022 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
25285574Smx205022 	macp->m_driver = ngep;
25295574Smx205022 	macp->m_dip = devinfo;
25305574Smx205022 	macp->m_src_addr = infop->vendor_addr.addr;
25315574Smx205022 	macp->m_callbacks = &nge_m_callbacks;
25325574Smx205022 	macp->m_min_sdu = 0;
25335574Smx205022 	macp->m_max_sdu = ngep->default_mtu;
25345895Syz147064 	macp->m_margin = VTAG_SIZE;
25356512Ssowmini 	macp->m_priv_props = nge_priv_props;
25365574Smx205022 	/*
25375574Smx205022 	 * Finally, we're ready to register ourselves with the mac
25385574Smx205022 	 * interface; if this succeeds, we're all ready to start()
25395574Smx205022 	 */
25405574Smx205022 	err = mac_register(macp, &ngep->mh);
25415574Smx205022 	mac_free(macp);
25425574Smx205022 	if (err != 0)
25435574Smx205022 		goto attach_fail;
25445574Smx205022 
25455574Smx205022 	/*
25465574Smx205022 	 * Register a periodical handler.
25475574Smx205022 	 * nge_chip_cyclic() is invoked in kernel context.
25485574Smx205022 	 */
25495574Smx205022 	ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
25505574Smx205022 	    NGE_CYCLIC_PERIOD, DDI_IPL_0);
25515574Smx205022 
25525574Smx205022 	ngep->progress |= PROGRESS_READY;
25535574Smx205022 	return (DDI_SUCCESS);
25545574Smx205022 
25555574Smx205022 attach_fail:
25565574Smx205022 	nge_unattach(ngep);
25575574Smx205022 	return (DDI_FAILURE);
25585574Smx205022 }
25595574Smx205022 
25605869Smx205022 static int
nge_suspend(nge_t * ngep)25615869Smx205022 nge_suspend(nge_t *ngep)
25625869Smx205022 {
25635869Smx205022 	mutex_enter(ngep->genlock);
25645869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
25655869Smx205022 
25665869Smx205022 	/* if the port hasn't been plumbed, just return */
25675869Smx205022 	if (ngep->nge_mac_state != NGE_MAC_STARTED) {
25685869Smx205022 		rw_exit(ngep->rwlock);
25695869Smx205022 		mutex_exit(ngep->genlock);
25705869Smx205022 		return (DDI_SUCCESS);
25715869Smx205022 	}
25725869Smx205022 	ngep->suspended = B_TRUE;
25735869Smx205022 	(void) nge_chip_stop(ngep, B_FALSE);
25745869Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
25755869Smx205022 
25765869Smx205022 	rw_exit(ngep->rwlock);
25775869Smx205022 	mutex_exit(ngep->genlock);
25785869Smx205022 	return (DDI_SUCCESS);
25795869Smx205022 }
25805869Smx205022 
25815574Smx205022 /*
25825574Smx205022  * detach(9E) -- Detach a device from the system
25835574Smx205022  */
25845574Smx205022 static int
nge_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)25855574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
25865574Smx205022 {
25875574Smx205022 	int i;
25885574Smx205022 	nge_t *ngep;
25895574Smx205022 	mul_item *p, *nextp;
25905574Smx205022 	buff_ring_t *brp;
25915574Smx205022 
25925574Smx205022 	NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
25935574Smx205022 
25945574Smx205022 	ngep = ddi_get_driver_private(devinfo);
25955574Smx205022 	brp = ngep->buff;
25965574Smx205022 
25975574Smx205022 	switch (cmd) {
25985574Smx205022 	default:
25995574Smx205022 		return (DDI_FAILURE);
26005574Smx205022 
26015574Smx205022 	case DDI_SUSPEND:
26025574Smx205022 		/*
26035574Smx205022 		 * Stop the NIC
26045574Smx205022 		 * Note: This driver doesn't currently support WOL, but
26055574Smx205022 		 *	should it in the future, it is important to
26065574Smx205022 		 *	make sure the PHY remains powered so that the
26075574Smx205022 		 *	wakeup packet can actually be recieved.
26085574Smx205022 		 */
26095869Smx205022 		return (nge_suspend(ngep));
26105574Smx205022 
26115574Smx205022 	case DDI_DETACH:
26125574Smx205022 		break;
26135574Smx205022 	}
26145574Smx205022 
26155574Smx205022 	/* Try to wait all the buffer post to upper layer be released */
26165574Smx205022 	for (i = 0; i < 1000; i++) {
26175574Smx205022 		if (brp->rx_hold == 0)
26185574Smx205022 			break;
26195574Smx205022 		drv_usecwait(1000);
26205574Smx205022 	}
26215574Smx205022 
26225574Smx205022 	/* If there is any posted buffer, reject to detach */
26235574Smx205022 	if (brp->rx_hold != 0)
26245574Smx205022 		return (DDI_FAILURE);
26255574Smx205022 
26265574Smx205022 	/*
26275574Smx205022 	 * Unregister from the GLD subsystem.  This can fail, in
26285574Smx205022 	 * particular if there are DLPI style-2 streams still open -
26295574Smx205022 	 * in which case we just return failure without shutting
26305574Smx205022 	 * down chip operations.
26315574Smx205022 	 */
26325574Smx205022 	if (mac_unregister(ngep->mh) != DDI_SUCCESS)
26335574Smx205022 		return (DDI_FAILURE);
26345574Smx205022 
26355574Smx205022 	/*
26366366Smx205022 	 * Recycle the multicast table. mac_unregister() should be called
26376366Smx205022 	 * before it to ensure the multicast table can be used even if
26386366Smx205022 	 * mac_unregister() fails.
26396366Smx205022 	 */
26406366Smx205022 	for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
26416366Smx205022 		nextp = p->next;
26426366Smx205022 		kmem_free(p, sizeof (mul_item));
26436366Smx205022 	}
26446366Smx205022 	ngep->pcur_mulist = NULL;
26456366Smx205022 
26466366Smx205022 	/*
26475574Smx205022 	 * All activity stopped, so we can clean up & exit
26485574Smx205022 	 */
26495574Smx205022 	nge_unattach(ngep);
26505574Smx205022 	return (DDI_SUCCESS);
26515574Smx205022 }
26525574Smx205022 
26537656SSherry.Moore@Sun.COM /*
26547656SSherry.Moore@Sun.COM  * quiesce(9E) entry point.
26557656SSherry.Moore@Sun.COM  *
26567656SSherry.Moore@Sun.COM  * This function is called when the system is single-threaded at high
26577656SSherry.Moore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
26587656SSherry.Moore@Sun.COM  * blocked.
26597656SSherry.Moore@Sun.COM  *
26607656SSherry.Moore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
26617656SSherry.Moore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
26627656SSherry.Moore@Sun.COM  */
26637656SSherry.Moore@Sun.COM static int
nge_quiesce(dev_info_t * devinfo)26647656SSherry.Moore@Sun.COM nge_quiesce(dev_info_t *devinfo)
26657656SSherry.Moore@Sun.COM {
26667656SSherry.Moore@Sun.COM 	nge_t *ngep;
26677656SSherry.Moore@Sun.COM 
26687656SSherry.Moore@Sun.COM 	ngep = ddi_get_driver_private(devinfo);
26697656SSherry.Moore@Sun.COM 
26707656SSherry.Moore@Sun.COM 	if (ngep == NULL)
26717656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
26727656SSherry.Moore@Sun.COM 
26737656SSherry.Moore@Sun.COM 	/*
26747656SSherry.Moore@Sun.COM 	 * Turn off debug tracing
26757656SSherry.Moore@Sun.COM 	 */
26767656SSherry.Moore@Sun.COM 	nge_debug = 0;
26777656SSherry.Moore@Sun.COM 	ngep->debug = 0;
26787656SSherry.Moore@Sun.COM 
26797656SSherry.Moore@Sun.COM 	nge_restore_mac_addr(ngep);
26807656SSherry.Moore@Sun.COM 	(void) nge_chip_stop(ngep, B_FALSE);
26817656SSherry.Moore@Sun.COM 
26827656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
26837656SSherry.Moore@Sun.COM }
26847656SSherry.Moore@Sun.COM 
26857656SSherry.Moore@Sun.COM 
26865574Smx205022 
26875574Smx205022 /*
26885574Smx205022  * ========== Module Loading Data & Entry Points ==========
26895574Smx205022  */
26905574Smx205022 
26915574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
26927656SSherry.Moore@Sun.COM     NULL, NULL, D_MP, NULL, nge_quiesce);
26935574Smx205022 
26945574Smx205022 
26955574Smx205022 static struct modldrv nge_modldrv = {
26965574Smx205022 	&mod_driverops,		/* Type of module.  This one is a driver */
26975574Smx205022 	nge_ident,		/* short description */
26985574Smx205022 	&nge_dev_ops		/* driver specific ops */
26995574Smx205022 };
27005574Smx205022 
27015574Smx205022 static struct modlinkage modlinkage = {
27025574Smx205022 	MODREV_1, (void *)&nge_modldrv, NULL
27035574Smx205022 };
27045574Smx205022 
27055574Smx205022 
27065574Smx205022 int
_info(struct modinfo * modinfop)27075574Smx205022 _info(struct modinfo *modinfop)
27085574Smx205022 {
27095574Smx205022 	return (mod_info(&modlinkage, modinfop));
27105574Smx205022 }
27115574Smx205022 
27125574Smx205022 int
_init(void)27135574Smx205022 _init(void)
27145574Smx205022 {
27155574Smx205022 	int status;
27165574Smx205022 
27175574Smx205022 	mac_init_ops(&nge_dev_ops, "nge");
27185574Smx205022 	status = mod_install(&modlinkage);
27195574Smx205022 	if (status != DDI_SUCCESS)
27205574Smx205022 		mac_fini_ops(&nge_dev_ops);
27215574Smx205022 	else
27225574Smx205022 		mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
27235574Smx205022 
27245574Smx205022 	return (status);
27255574Smx205022 }
27265574Smx205022 
27275574Smx205022 int
_fini(void)27285574Smx205022 _fini(void)
27295574Smx205022 {
27305574Smx205022 	int status;
27315574Smx205022 
27325574Smx205022 	status = mod_remove(&modlinkage);
27335574Smx205022 	if (status == DDI_SUCCESS) {
27345574Smx205022 		mac_fini_ops(&nge_dev_ops);
27355574Smx205022 		mutex_destroy(nge_log_mutex);
27365574Smx205022 	}
27375574Smx205022 
27385574Smx205022 	return (status);
27395574Smx205022 }
27405574Smx205022 
27415574Smx205022 /*
27425574Smx205022  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
27435574Smx205022  */
27445574Smx205022 
27455574Smx205022 /*
27465574Smx205022  * Register interrupts and initialize each mutex and condition variables
27475574Smx205022  */
27485574Smx205022 
27495574Smx205022 static int
nge_register_intrs_and_init_locks(nge_t * ngep)27505574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep)
27515574Smx205022 {
27525574Smx205022 	int		err;
27535574Smx205022 	int		intr_types;
27545574Smx205022 	uint_t		soft_prip;
27555574Smx205022 	nge_msi_mask	msi_mask;
27565574Smx205022 	nge_msi_map0_vec map0_vec;
27575574Smx205022 	nge_msi_map1_vec map1_vec;
27585574Smx205022 
27595574Smx205022 	/*
27605574Smx205022 	 * Add the softint handlers:
27615574Smx205022 	 *
27625574Smx205022 	 * Both of these handlers are used to avoid restrictions on the
27635574Smx205022 	 * context and/or mutexes required for some operations.  In
27645574Smx205022 	 * particular, the hardware interrupt handler and its subfunctions
27655574Smx205022 	 * can detect a number of conditions that we don't want to handle
27665574Smx205022 	 * in that context or with that set of mutexes held.  So, these
27675574Smx205022 	 * softints are triggered instead:
27685574Smx205022 	 *
27695574Smx205022 	 * the <resched> softint is triggered if if we have previously
27705574Smx205022 	 * had to refuse to send a packet because of resource shortage
27715574Smx205022 	 * (we've run out of transmit buffers), but the send completion
27725574Smx205022 	 * interrupt handler has now detected that more buffers have
27735574Smx205022 	 * become available.  Its only purpose is to call gld_sched()
27745574Smx205022 	 * to retry the pending transmits (we're not allowed to hold
27755574Smx205022 	 * driver-defined mutexes across gld_sched()).
27765574Smx205022 	 *
27775574Smx205022 	 * the <factotum> is triggered if the h/w interrupt handler
27785574Smx205022 	 * sees the <link state changed> or <error> bits in the status
27795574Smx205022 	 * block.  It's also triggered periodically to poll the link
27805574Smx205022 	 * state, just in case we aren't getting link status change
27815574Smx205022 	 * interrupts ...
27825574Smx205022 	 */
27835574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
27845574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
27855574Smx205022 	if (err != DDI_SUCCESS) {
27865574Smx205022 		nge_problem(ngep,
27875574Smx205022 		    "nge_attach: add nge_reschedule softintr failed");
27885574Smx205022 
27895574Smx205022 		return (DDI_FAILURE);
27905574Smx205022 	}
27915574Smx205022 	ngep->progress |= PROGRESS_RESCHED;
27925574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
27935574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
27945574Smx205022 	if (err != DDI_SUCCESS) {
27955574Smx205022 		nge_problem(ngep,
27965574Smx205022 		    "nge_attach: add nge_chip_factotum softintr failed!");
27975574Smx205022 
27985574Smx205022 		return (DDI_FAILURE);
27995574Smx205022 	}
28005574Smx205022 	if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
28015574Smx205022 	    != DDI_SUCCESS) {
28025574Smx205022 		nge_problem(ngep, "nge_attach: get softintr priority failed\n");
28035574Smx205022 
28045574Smx205022 		return (DDI_FAILURE);
28055574Smx205022 	}
28065574Smx205022 	ngep->soft_pri = soft_prip;
28075574Smx205022 
28085574Smx205022 	ngep->progress |= PROGRESS_FACTOTUM;
28095574Smx205022 	/* Get supported interrupt types */
28105574Smx205022 	if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
28115574Smx205022 	    != DDI_SUCCESS) {
28125574Smx205022 		nge_error(ngep, "ddi_intr_get_supported_types failed\n");
28135574Smx205022 
28145574Smx205022 		return (DDI_FAILURE);
28155574Smx205022 	}
28165574Smx205022 
28175574Smx205022 	NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
28185574Smx205022 	    intr_types));
28195574Smx205022 
28205574Smx205022 	if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
28215574Smx205022 
28225574Smx205022 		/* MSI Configurations for mcp55 chipset */
28235574Smx205022 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
28245574Smx205022 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
28255574Smx205022 
28265574Smx205022 
28275574Smx205022 			/* Enable the 8 vectors */
28285574Smx205022 			msi_mask.msi_mask_val =
28295574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MASK);
28305574Smx205022 			msi_mask.msi_msk_bits.vec0 = NGE_SET;
28315574Smx205022 			msi_mask.msi_msk_bits.vec1 = NGE_SET;
28325574Smx205022 			msi_mask.msi_msk_bits.vec2 = NGE_SET;
28335574Smx205022 			msi_mask.msi_msk_bits.vec3 = NGE_SET;
28345574Smx205022 			msi_mask.msi_msk_bits.vec4 = NGE_SET;
28355574Smx205022 			msi_mask.msi_msk_bits.vec5 = NGE_SET;
28365574Smx205022 			msi_mask.msi_msk_bits.vec6 = NGE_SET;
28375574Smx205022 			msi_mask.msi_msk_bits.vec7 = NGE_SET;
28385574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MASK,
28395574Smx205022 			    msi_mask.msi_mask_val);
28405574Smx205022 
28415574Smx205022 			/*
28425574Smx205022 			 * Remapping the MSI MAP0 and MAP1. MCP55
28435574Smx205022 			 * is default mapping all the interrupt to 0 vector.
28445574Smx205022 			 * Software needs to remapping this.
28455574Smx205022 			 * This mapping is same as CK804.
28465574Smx205022 			 */
28475574Smx205022 			map0_vec.msi_map0_val =
28485574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP0);
28495574Smx205022 			map1_vec.msi_map1_val =
28505574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP1);
28515574Smx205022 			map0_vec.vecs_bits.reint_vec = 0;
28525574Smx205022 			map0_vec.vecs_bits.rcint_vec = 0;
28535574Smx205022 			map0_vec.vecs_bits.miss_vec = 3;
28545574Smx205022 			map0_vec.vecs_bits.teint_vec = 5;
28555574Smx205022 			map0_vec.vecs_bits.tcint_vec = 5;
28565574Smx205022 			map0_vec.vecs_bits.stint_vec = 2;
28575574Smx205022 			map0_vec.vecs_bits.mint_vec = 6;
28585574Smx205022 			map0_vec.vecs_bits.rfint_vec = 0;
28595574Smx205022 			map1_vec.vecs_bits.tfint_vec = 5;
28605574Smx205022 			map1_vec.vecs_bits.feint_vec = 6;
28615574Smx205022 			map1_vec.vecs_bits.resv8_11 = 3;
28625574Smx205022 			map1_vec.vecs_bits.resv12_15 = 1;
28635574Smx205022 			map1_vec.vecs_bits.resv16_19 = 0;
28645574Smx205022 			map1_vec.vecs_bits.resv20_23 = 7;
28655574Smx205022 			map1_vec.vecs_bits.resv24_31 = 0xff;
28665574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP0,
28675574Smx205022 			    map0_vec.msi_map0_val);
28685574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP1,
28695574Smx205022 			    map1_vec.msi_map1_val);
28705574Smx205022 		}
28715574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
28725574Smx205022 			NGE_DEBUG(("MSI registration failed, "
28735574Smx205022 			    "trying FIXED interrupt type\n"));
28745574Smx205022 		} else {
28755574Smx205022 			nge_log(ngep, "Using MSI interrupt type\n");
28765574Smx205022 
28775574Smx205022 			ngep->intr_type = DDI_INTR_TYPE_MSI;
28785574Smx205022 			ngep->progress |= PROGRESS_SWINT;
28795574Smx205022 		}
28805574Smx205022 	}
28815574Smx205022 
28825574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT) &&
28835574Smx205022 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
28845574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
28855574Smx205022 			nge_error(ngep, "FIXED interrupt "
28865574Smx205022 			    "registration failed\n");
28875574Smx205022 
28885574Smx205022 			return (DDI_FAILURE);
28895574Smx205022 		}
28905574Smx205022 
28915574Smx205022 		nge_log(ngep, "Using FIXED interrupt type\n");
28925574Smx205022 
28935574Smx205022 		ngep->intr_type = DDI_INTR_TYPE_FIXED;
28945574Smx205022 		ngep->progress |= PROGRESS_SWINT;
28955574Smx205022 	}
28965574Smx205022 
28975574Smx205022 
28985574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT)) {
28995574Smx205022 		nge_error(ngep, "No interrupts registered\n");
29005574Smx205022 
29015574Smx205022 		return (DDI_FAILURE);
29025574Smx205022 	}
29035574Smx205022 	mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
29045574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29055574Smx205022 	mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
29065574Smx205022 	    DDI_INTR_PRI(ngep->soft_pri));
29075574Smx205022 	rw_init(ngep->rwlock, NULL, RW_DRIVER,
29085574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29095574Smx205022 
29105574Smx205022 	return (DDI_SUCCESS);
29115574Smx205022 }
29125574Smx205022 
29135574Smx205022 /*
29145574Smx205022  * nge_add_intrs:
29155574Smx205022  *
29165574Smx205022  * Register FIXED or MSI interrupts.
29175574Smx205022  */
29185574Smx205022 static int
nge_add_intrs(nge_t * ngep,int intr_type)29195574Smx205022 nge_add_intrs(nge_t *ngep, int	intr_type)
29205574Smx205022 {
29215574Smx205022 	dev_info_t	*dip = ngep->devinfo;
29225574Smx205022 	int		avail, actual, intr_size, count = 0;
29235574Smx205022 	int		i, flag, ret;
29245574Smx205022 
29255574Smx205022 	NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
29265574Smx205022 
29275574Smx205022 	/* Get number of interrupts */
29285574Smx205022 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
29295574Smx205022 	if ((ret != DDI_SUCCESS) || (count == 0)) {
29305574Smx205022 		nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
29315574Smx205022 		    "count: %d", ret, count);
29325574Smx205022 
29335574Smx205022 		return (DDI_FAILURE);
29345574Smx205022 	}
29355574Smx205022 
29365574Smx205022 	/* Get number of available interrupts */
29375574Smx205022 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
29385574Smx205022 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
29395574Smx205022 		nge_error(ngep, "ddi_intr_get_navail() failure, "
29405574Smx205022 		    "ret: %d, avail: %d\n", ret, avail);
29415574Smx205022 
29425574Smx205022 		return (DDI_FAILURE);
29435574Smx205022 	}
29445574Smx205022 
29455574Smx205022 	if (avail < count) {
29465574Smx205022 		NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
29475574Smx205022 		    count, avail));
29485574Smx205022 	}
29495574Smx205022 	flag = DDI_INTR_ALLOC_NORMAL;
29505574Smx205022 
29515574Smx205022 	/* Allocate an array of interrupt handles */
29525574Smx205022 	intr_size = count * sizeof (ddi_intr_handle_t);
29535574Smx205022 	ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
29545574Smx205022 
29555574Smx205022 	/* Call ddi_intr_alloc() */
29565574Smx205022 	ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
29575574Smx205022 	    count, &actual, flag);
29585574Smx205022 
29595574Smx205022 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
29605574Smx205022 		nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
29615574Smx205022 
29625574Smx205022 		kmem_free(ngep->htable, intr_size);
29635574Smx205022 		return (DDI_FAILURE);
29645574Smx205022 	}
29655574Smx205022 
29665574Smx205022 	if (actual < count) {
29675574Smx205022 		NGE_DEBUG(("Requested: %d, Received: %d\n",
29685574Smx205022 		    count, actual));
29695574Smx205022 	}
29705574Smx205022 
29715574Smx205022 	ngep->intr_actual_cnt = actual;
29725574Smx205022 	ngep->intr_req_cnt = count;
29735574Smx205022 
29745574Smx205022 	/*
29755574Smx205022 	 * Get priority for first msi, assume remaining are all the same
29765574Smx205022 	 */
29775574Smx205022 	if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
29785574Smx205022 	    DDI_SUCCESS) {
29795574Smx205022 		nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
29805574Smx205022 
29815574Smx205022 		/* Free already allocated intr */
29825574Smx205022 		for (i = 0; i < actual; i++) {
29835574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
29845574Smx205022 		}
29855574Smx205022 
29865574Smx205022 		kmem_free(ngep->htable, intr_size);
29875574Smx205022 
29885574Smx205022 		return (DDI_FAILURE);
29895574Smx205022 	}
29905574Smx205022 	/* Test for high level mutex */
29915574Smx205022 	if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
29925574Smx205022 		nge_error(ngep, "nge_add_intrs:"
29935574Smx205022 		    "Hi level interrupt not supported");
29945574Smx205022 
29955574Smx205022 		for (i = 0; i < actual; i++)
29965574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
29975574Smx205022 
29985574Smx205022 		kmem_free(ngep->htable, intr_size);
29995574Smx205022 
30005574Smx205022 		return (DDI_FAILURE);
30015574Smx205022 	}
30025574Smx205022 
30035574Smx205022 
30045574Smx205022 	/* Call ddi_intr_add_handler() */
30055574Smx205022 	for (i = 0; i < actual; i++) {
30065574Smx205022 		if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
30075574Smx205022 		    (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
30085574Smx205022 			nge_error(ngep, "ddi_intr_add_handler() "
30095574Smx205022 			    "failed %d\n", ret);
30105574Smx205022 
30115574Smx205022 			/* Free already allocated intr */
30125574Smx205022 			for (i = 0; i < actual; i++) {
30135574Smx205022 				(void) ddi_intr_free(ngep->htable[i]);
30145574Smx205022 			}
30155574Smx205022 
30165574Smx205022 			kmem_free(ngep->htable, intr_size);
30175574Smx205022 
30185574Smx205022 			return (DDI_FAILURE);
30195574Smx205022 		}
30205574Smx205022 	}
30215574Smx205022 
30225574Smx205022 	if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
30235574Smx205022 	    != DDI_SUCCESS) {
30245574Smx205022 		nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
30255574Smx205022 
30265574Smx205022 		for (i = 0; i < actual; i++) {
30275574Smx205022 			(void) ddi_intr_remove_handler(ngep->htable[i]);
30285574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
30295574Smx205022 		}
30305574Smx205022 
30315574Smx205022 		kmem_free(ngep->htable, intr_size);
30325574Smx205022 
30335574Smx205022 		return (DDI_FAILURE);
30345574Smx205022 	}
30355574Smx205022 
30365574Smx205022 	return (DDI_SUCCESS);
30375574Smx205022 }
30385574Smx205022 
30395574Smx205022 /*
30405574Smx205022  * nge_rem_intrs:
30415574Smx205022  *
30425574Smx205022  * Unregister FIXED or MSI interrupts
30435574Smx205022  */
30445574Smx205022 static void
nge_rem_intrs(nge_t * ngep)30455574Smx205022 nge_rem_intrs(nge_t *ngep)
30465574Smx205022 {
30475574Smx205022 	int	i;
30485574Smx205022 
30495574Smx205022 	NGE_DEBUG(("nge_rem_intrs\n"));
30505574Smx205022 
30515574Smx205022 	/* Disable all interrupts */
30525574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
30535574Smx205022 		/* Call ddi_intr_block_disable() */
30545574Smx205022 		(void) ddi_intr_block_disable(ngep->htable,
30555574Smx205022 		    ngep->intr_actual_cnt);
30565574Smx205022 	} else {
30575574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
30585574Smx205022 			(void) ddi_intr_disable(ngep->htable[i]);
30595574Smx205022 		}
30605574Smx205022 	}
30615574Smx205022 
30625574Smx205022 	/* Call ddi_intr_remove_handler() */
30635574Smx205022 	for (i = 0; i < ngep->intr_actual_cnt; i++) {
30645574Smx205022 		(void) ddi_intr_remove_handler(ngep->htable[i]);
30655574Smx205022 		(void) ddi_intr_free(ngep->htable[i]);
30665574Smx205022 	}
30675574Smx205022 
30685574Smx205022 	kmem_free(ngep->htable,
30695574Smx205022 	    ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
30705574Smx205022 }
3071