xref: /onnv-gate/usr/src/uts/common/io/nge/nge_main.c (revision 9604:8496ba65ce8f)
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 /*
239514SGirish.Moodalbail@Sun.COM  * Copyright 2009 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";
1688218SMin.Xu@Sun.COM static char mac_addr_reversion[] = "mac-addr-reversion";
1695574Smx205022 extern kmutex_t nge_log_mutex[1];
1705574Smx205022 
1715574Smx205022 static int		nge_m_start(void *);
1725574Smx205022 static void		nge_m_stop(void *);
1735574Smx205022 static int		nge_m_promisc(void *, boolean_t);
1745574Smx205022 static int		nge_m_multicst(void *, boolean_t, const uint8_t *);
1755574Smx205022 static int		nge_m_unicst(void *, const uint8_t *);
1765574Smx205022 static void		nge_m_ioctl(void *, queue_t *, mblk_t *);
1775574Smx205022 static boolean_t	nge_m_getcapab(void *, mac_capab_t, void *);
1786200Smx205022 static int		nge_m_setprop(void *, const char *, mac_prop_id_t,
1796200Smx205022 	uint_t, const void *);
1806200Smx205022 static int		nge_m_getprop(void *, const char *, mac_prop_id_t,
1818118SVasumathi.Sundaram@Sun.COM 	uint_t, uint_t, void *, uint_t *);
1826200Smx205022 static int		nge_set_priv_prop(nge_t *, const char *, uint_t,
1836200Smx205022 	const void *);
1846200Smx205022 static int		nge_get_priv_prop(nge_t *, const char *, uint_t,
1856512Ssowmini 	uint_t, void *);
1866200Smx205022 
1876200Smx205022 #define		NGE_M_CALLBACK_FLAGS\
1886200Smx205022 		(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
1895574Smx205022 
1905574Smx205022 static mac_callbacks_t nge_m_callbacks = {
1915574Smx205022 	NGE_M_CALLBACK_FLAGS,
1925574Smx205022 	nge_m_stat,
1935574Smx205022 	nge_m_start,
1945574Smx205022 	nge_m_stop,
1955574Smx205022 	nge_m_promisc,
1965574Smx205022 	nge_m_multicst,
1975574Smx205022 	nge_m_unicst,
1985574Smx205022 	nge_m_tx,
1995574Smx205022 	nge_m_ioctl,
2006200Smx205022 	nge_m_getcapab,
2016200Smx205022 	NULL,
2026200Smx205022 	NULL,
2036200Smx205022 	nge_m_setprop,
2046200Smx205022 	nge_m_getprop
2055574Smx205022 };
2065574Smx205022 
2076512Ssowmini mac_priv_prop_t nge_priv_props[] = {
2086512Ssowmini 	{"_tx_bcopy_threshold", MAC_PROP_PERM_RW},
2096512Ssowmini 	{"_rx_bcopy_threshold", MAC_PROP_PERM_RW},
2106512Ssowmini 	{"_recv_max_packet", MAC_PROP_PERM_RW},
2116512Ssowmini 	{"_poll_quiet_time", MAC_PROP_PERM_RW},
2126512Ssowmini 	{"_poll_busy_time", MAC_PROP_PERM_RW},
2136512Ssowmini 	{"_rx_intr_hwater", MAC_PROP_PERM_RW},
2146512Ssowmini 	{"_rx_intr_lwater", MAC_PROP_PERM_RW},
2156512Ssowmini 	{"_adv_pause_cap", MAC_PROP_PERM_RW},
2166512Ssowmini 	{"_adv_asym_pause_cap", MAC_PROP_PERM_RW},
2176512Ssowmini 	{"_tx_n_intr", MAC_PROP_PERM_RW}
2186512Ssowmini };
2196512Ssowmini 
2206512Ssowmini #define	NGE_MAX_PRIV_PROPS \
2216512Ssowmini 	(sizeof (nge_priv_props)/sizeof (mac_priv_prop_t))
2226512Ssowmini 
2235574Smx205022 static int nge_add_intrs(nge_t *, int);
2245574Smx205022 static void nge_rem_intrs(nge_t *);
2255574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *);
2265574Smx205022 
2275574Smx205022 /*
2285574Smx205022  * NGE MSI tunable:
2295574Smx205022  */
2305574Smx205022 boolean_t nge_enable_msi = B_FALSE;
2315574Smx205022 
2325574Smx205022 static enum ioc_reply
2335574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
2345574Smx205022 {
2355574Smx205022 	/*
2365574Smx205022 	 * If the mode isn't being changed, there's nothing to do ...
2375574Smx205022 	 */
2385574Smx205022 	if (mode == ngep->param_loop_mode)
2395574Smx205022 		return (IOC_ACK);
2405574Smx205022 
2415574Smx205022 	/*
2425574Smx205022 	 * Validate the requested mode and prepare a suitable message
2435574Smx205022 	 * to explain the link down/up cycle that the change will
2445574Smx205022 	 * probably induce ...
2455574Smx205022 	 */
2465574Smx205022 	switch (mode) {
2475574Smx205022 	default:
2485574Smx205022 		return (IOC_INVAL);
2495574Smx205022 
2505574Smx205022 	case NGE_LOOP_NONE:
2515574Smx205022 	case NGE_LOOP_EXTERNAL_100:
2525574Smx205022 	case NGE_LOOP_EXTERNAL_10:
2535574Smx205022 	case NGE_LOOP_INTERNAL_PHY:
2545574Smx205022 		break;
2555574Smx205022 	}
2565574Smx205022 
2575574Smx205022 	/*
2585574Smx205022 	 * All OK; tell the caller to reprogram
2595574Smx205022 	 * the PHY and/or MAC for the new mode ...
2605574Smx205022 	 */
2615574Smx205022 	ngep->param_loop_mode = mode;
2625574Smx205022 	return (IOC_RESTART_ACK);
2635574Smx205022 }
2645574Smx205022 
2655574Smx205022 #undef	NGE_DBG
2665574Smx205022 #define	NGE_DBG		NGE_DBG_INIT
2675574Smx205022 
2685574Smx205022 /*
2695574Smx205022  * Utility routine to carve a slice off a chunk of allocated memory,
2705574Smx205022  * updating the chunk descriptor accordingly.  The size of the slice
2715574Smx205022  * is given by the product of the <qty> and <size> parameters.
2725574Smx205022  */
2735574Smx205022 void
2745574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
2755574Smx205022     uint32_t qty, uint32_t size)
2765574Smx205022 {
2775574Smx205022 	size_t totsize;
2785574Smx205022 
2795574Smx205022 	totsize = qty*size;
2805574Smx205022 	ASSERT(size > 0);
2815574Smx205022 	ASSERT(totsize <= chunk->alength);
2825574Smx205022 
2835574Smx205022 	*slice = *chunk;
2845574Smx205022 	slice->nslots = qty;
2855574Smx205022 	slice->size = size;
2865574Smx205022 	slice->alength = totsize;
2875574Smx205022 
2885574Smx205022 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
2895574Smx205022 	chunk->alength -= totsize;
2905574Smx205022 	chunk->offset += totsize;
2915574Smx205022 	chunk->cookie.dmac_laddress += totsize;
2925574Smx205022 	chunk->cookie.dmac_size -= totsize;
2935574Smx205022 }
2945574Smx205022 
2955574Smx205022 /*
2965574Smx205022  * Allocate an area of memory and a DMA handle for accessing it
2975574Smx205022  */
2985574Smx205022 int
2995574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
3005574Smx205022     uint_t dma_flags, dma_area_t *dma_p)
3015574Smx205022 {
3025574Smx205022 	int err;
3035574Smx205022 	caddr_t va;
3045574Smx205022 
3055574Smx205022 	NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
3065574Smx205022 	    (void *)ngep, memsize, attr_p, dma_flags, dma_p));
3075574Smx205022 	/*
3085574Smx205022 	 * Allocate handle
3095574Smx205022 	 */
3105574Smx205022 	err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
3115574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
3125574Smx205022 	if (err != DDI_SUCCESS)
3135574Smx205022 		goto fail;
3145574Smx205022 
3155574Smx205022 	/*
3165574Smx205022 	 * Allocate memory
3175574Smx205022 	 */
3185574Smx205022 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
3195574Smx205022 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
3205574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
3215574Smx205022 	if (err != DDI_SUCCESS)
3225574Smx205022 		goto fail;
3235574Smx205022 
3245574Smx205022 	/*
3255574Smx205022 	 * Bind the two together
3265574Smx205022 	 */
3275574Smx205022 	dma_p->mem_va = va;
3285574Smx205022 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
3295574Smx205022 	    va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
3305574Smx205022 	    &dma_p->cookie, &dma_p->ncookies);
3315574Smx205022 
3325574Smx205022 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
3335574Smx205022 		goto fail;
3345574Smx205022 
3355574Smx205022 	dma_p->nslots = ~0U;
3365574Smx205022 	dma_p->size = ~0U;
3375574Smx205022 	dma_p->offset = 0;
3385574Smx205022 
3395574Smx205022 	return (DDI_SUCCESS);
3405574Smx205022 
3415574Smx205022 fail:
3425574Smx205022 	nge_free_dma_mem(dma_p);
3435574Smx205022 	NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
3445574Smx205022 
3455574Smx205022 	return (DDI_FAILURE);
3465574Smx205022 }
3475574Smx205022 
3485574Smx205022 /*
3495574Smx205022  * Free one allocated area of DMAable memory
3505574Smx205022  */
3515574Smx205022 void
3525574Smx205022 nge_free_dma_mem(dma_area_t *dma_p)
3535574Smx205022 {
3545574Smx205022 	if (dma_p->dma_hdl != NULL) {
3555574Smx205022 		if (dma_p->ncookies) {
3565574Smx205022 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
3575574Smx205022 			dma_p->ncookies = 0;
3585574Smx205022 		}
3595574Smx205022 	}
3605574Smx205022 	if (dma_p->acc_hdl != NULL) {
3615574Smx205022 		ddi_dma_mem_free(&dma_p->acc_hdl);
3625574Smx205022 		dma_p->acc_hdl = NULL;
3635574Smx205022 	}
3645574Smx205022 	if (dma_p->dma_hdl != NULL) {
3655574Smx205022 		ddi_dma_free_handle(&dma_p->dma_hdl);
3665574Smx205022 		dma_p->dma_hdl = NULL;
3675574Smx205022 	}
3685574Smx205022 }
3695574Smx205022 
3705574Smx205022 #define	ALLOC_TX_BUF	0x1
3715574Smx205022 #define	ALLOC_TX_DESC	0x2
3725574Smx205022 #define	ALLOC_RX_DESC	0x4
3735574Smx205022 
3745574Smx205022 int
3755574Smx205022 nge_alloc_bufs(nge_t *ngep)
3765574Smx205022 {
3775574Smx205022 	int err;
3785574Smx205022 	int split;
3795574Smx205022 	int progress;
3805574Smx205022 	size_t txbuffsize;
3815574Smx205022 	size_t rxdescsize;
3825574Smx205022 	size_t txdescsize;
3835574Smx205022 
3845574Smx205022 	txbuffsize = ngep->tx_desc * ngep->buf_size;
3855574Smx205022 	rxdescsize = ngep->rx_desc;
3865574Smx205022 	txdescsize = ngep->tx_desc;
3875574Smx205022 	rxdescsize *= ngep->desc_attr.rxd_size;
3885574Smx205022 	txdescsize *= ngep->desc_attr.txd_size;
3895574Smx205022 	progress = 0;
3905574Smx205022 
3915574Smx205022 	NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
3925574Smx205022 	/*
3935574Smx205022 	 * Allocate memory & handles for TX buffers
3945574Smx205022 	 */
3955574Smx205022 	ASSERT((txbuffsize % ngep->nge_split) == 0);
3965574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
3975574Smx205022 		err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
3985574Smx205022 		    &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
3995574Smx205022 		    &ngep->send->buf[split]);
4005574Smx205022 		if (err != DDI_SUCCESS)
4015574Smx205022 			goto fail;
4025574Smx205022 	}
4035574Smx205022 
4045574Smx205022 	progress |= ALLOC_TX_BUF;
4055574Smx205022 
4065574Smx205022 	/*
4075574Smx205022 	 * Allocate memory & handles for receive return rings and
4085574Smx205022 	 * buffer (producer) descriptor rings
4095574Smx205022 	 */
4105574Smx205022 	err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
4115574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
4125574Smx205022 	if (err != DDI_SUCCESS)
4135574Smx205022 		goto fail;
4145574Smx205022 	progress |= ALLOC_RX_DESC;
4155574Smx205022 
4165574Smx205022 	/*
4175574Smx205022 	 * Allocate memory & handles for TX descriptor rings,
4185574Smx205022 	 */
4195574Smx205022 	err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
4205574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
4215574Smx205022 	if (err != DDI_SUCCESS)
4225574Smx205022 		goto fail;
4235574Smx205022 	return (DDI_SUCCESS);
4245574Smx205022 
4255574Smx205022 fail:
4265574Smx205022 	if (progress & ALLOC_RX_DESC)
4275574Smx205022 		nge_free_dma_mem(&ngep->recv->desc);
4285574Smx205022 	if (progress & ALLOC_TX_BUF) {
4295574Smx205022 		for (split = 0; split < ngep->nge_split; ++split)
4305574Smx205022 			nge_free_dma_mem(&ngep->send->buf[split]);
4315574Smx205022 	}
4325574Smx205022 
4335574Smx205022 	return (DDI_FAILURE);
4345574Smx205022 }
4355574Smx205022 
4365574Smx205022 /*
4375574Smx205022  * This routine frees the transmit and receive buffers and descriptors.
4385574Smx205022  * Make sure the chip is stopped before calling it!
4395574Smx205022  */
4405574Smx205022 void
4415574Smx205022 nge_free_bufs(nge_t *ngep)
4425574Smx205022 {
4435574Smx205022 	int split;
4445574Smx205022 
4455574Smx205022 	NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
4465574Smx205022 
4475574Smx205022 	nge_free_dma_mem(&ngep->recv->desc);
4485574Smx205022 	nge_free_dma_mem(&ngep->send->desc);
4495574Smx205022 
4505574Smx205022 	for (split = 0; split < ngep->nge_split; ++split)
4515574Smx205022 		nge_free_dma_mem(&ngep->send->buf[split]);
4525574Smx205022 }
4535574Smx205022 
4545574Smx205022 /*
4555574Smx205022  * Clean up initialisation done above before the memory is freed
4565574Smx205022  */
4575574Smx205022 static void
4585574Smx205022 nge_fini_send_ring(nge_t *ngep)
4595574Smx205022 {
4605574Smx205022 	uint32_t slot;
4615574Smx205022 	size_t dmah_num;
4625574Smx205022 	send_ring_t *srp;
4635574Smx205022 	sw_tx_sbd_t *ssbdp;
4645574Smx205022 
4655574Smx205022 	srp = ngep->send;
4665574Smx205022 	ssbdp = srp->sw_sbds;
4675574Smx205022 
4685574Smx205022 	NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
4695574Smx205022 
4705574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
4715574Smx205022 
4725574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
4735574Smx205022 		if (srp->dmahndl[slot].hndl) {
4745574Smx205022 			(void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
4755574Smx205022 			ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
4765574Smx205022 			srp->dmahndl[slot].hndl = NULL;
4775574Smx205022 			srp->dmahndl[slot].next = NULL;
4785574Smx205022 		}
4795574Smx205022 	}
4805574Smx205022 
4815574Smx205022 	srp->dmah_free.head = NULL;
4825574Smx205022 	srp->dmah_free.tail = NULL;
4835574Smx205022 
4845574Smx205022 	kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
4855574Smx205022 
4865574Smx205022 }
4875574Smx205022 
4885574Smx205022 /*
4895574Smx205022  * Initialise the specified Send Ring, using the information in the
4905574Smx205022  * <dma_area> descriptors that it contains to set up all the other
4915574Smx205022  * fields. This routine should be called only once for each ring.
4925574Smx205022  */
4935574Smx205022 static int
4945574Smx205022 nge_init_send_ring(nge_t *ngep)
4955574Smx205022 {
4965574Smx205022 	size_t dmah_num;
4975574Smx205022 	uint32_t nslots;
4985574Smx205022 	uint32_t err;
4995574Smx205022 	uint32_t slot;
5005574Smx205022 	uint32_t split;
5015574Smx205022 	send_ring_t *srp;
5025574Smx205022 	sw_tx_sbd_t *ssbdp;
5035574Smx205022 	dma_area_t desc;
5045574Smx205022 	dma_area_t pbuf;
5055574Smx205022 
5065574Smx205022 	srp = ngep->send;
5075574Smx205022 	srp->desc.nslots = ngep->tx_desc;
5085574Smx205022 	nslots = srp->desc.nslots;
5095574Smx205022 
5105574Smx205022 	NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
5115574Smx205022 	/*
5125574Smx205022 	 * Other one-off initialisation of per-ring data
5135574Smx205022 	 */
5145574Smx205022 	srp->ngep = ngep;
5155574Smx205022 
5165574Smx205022 	/*
5175574Smx205022 	 * Allocate the array of s/w Send Buffer Descriptors
5185574Smx205022 	 */
5195574Smx205022 	ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
5205574Smx205022 	srp->sw_sbds = ssbdp;
5215574Smx205022 
5225574Smx205022 	/*
5235574Smx205022 	 * Now initialise each array element once and for all
5245574Smx205022 	 */
5255574Smx205022 	desc = srp->desc;
5265574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
5275574Smx205022 		pbuf = srp->buf[split];
5285574Smx205022 		for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
5295574Smx205022 			nge_slice_chunk(&ssbdp->desc, &desc, 1,
5305574Smx205022 			    ngep->desc_attr.txd_size);
5315574Smx205022 			nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
5325574Smx205022 			    ngep->buf_size);
5335574Smx205022 		}
5345574Smx205022 		ASSERT(pbuf.alength == 0);
5355574Smx205022 	}
5365574Smx205022 	ASSERT(desc.alength == 0);
5375574Smx205022 
5385574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5395574Smx205022 
5405574Smx205022 	/* preallocate dma handles for tx buffer */
5415574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
5425574Smx205022 
5435574Smx205022 		err = ddi_dma_alloc_handle(ngep->devinfo,
5445574Smx205022 		    ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
5455574Smx205022 		    NULL, &srp->dmahndl[slot].hndl);
5465574Smx205022 
5475574Smx205022 		if (err != DDI_SUCCESS) {
5485574Smx205022 			nge_fini_send_ring(ngep);
5495574Smx205022 			nge_error(ngep,
5505574Smx205022 			    "nge_init_send_ring: alloc dma handle fails");
5515574Smx205022 			return (DDI_FAILURE);
5525574Smx205022 		}
5535574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5545574Smx205022 	}
5555574Smx205022 
5565574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5575574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5585574Smx205022 	srp->dmah_free.tail->next = NULL;
5595574Smx205022 
5605574Smx205022 	return (DDI_SUCCESS);
5615574Smx205022 }
5625574Smx205022 
5635574Smx205022 /*
5645574Smx205022  * Intialize the tx recycle pointer and tx sending pointer of tx ring
5655574Smx205022  * and set the type of tx's data descriptor by default.
5665574Smx205022  */
5675574Smx205022 static void
5685574Smx205022 nge_reinit_send_ring(nge_t *ngep)
5695574Smx205022 {
5705574Smx205022 	size_t dmah_num;
5715574Smx205022 	uint32_t slot;
5725574Smx205022 	send_ring_t *srp;
5735574Smx205022 	sw_tx_sbd_t *ssbdp;
5745574Smx205022 
5755574Smx205022 	srp = ngep->send;
5765574Smx205022 
5775574Smx205022 	/*
5785574Smx205022 	 * Reinitialise control variables ...
5795574Smx205022 	 */
5805574Smx205022 
5815574Smx205022 	srp->tx_hwmark = NGE_DESC_MIN;
5825574Smx205022 	srp->tx_lwmark = NGE_DESC_MIN;
5835574Smx205022 
5845574Smx205022 	srp->tx_next = 0;
5855574Smx205022 	srp->tx_free = srp->desc.nslots;
5865574Smx205022 	srp->tc_next = 0;
5875574Smx205022 
5885574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5895574Smx205022 
5905574Smx205022 	for (slot = 0; slot - dmah_num != 0; ++slot)
5915574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5925574Smx205022 
5935574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5945574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5955574Smx205022 	srp->dmah_free.tail->next = NULL;
5965574Smx205022 
5975574Smx205022 	/*
5985574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
5995574Smx205022 	 */
6005574Smx205022 	for (slot = 0; slot < srp->desc.nslots; ++slot) {
6015574Smx205022 		ssbdp = &srp->sw_sbds[slot];
6025574Smx205022 		ssbdp->flags = HOST_OWN;
6035574Smx205022 	}
6045574Smx205022 
6055574Smx205022 	DMA_ZERO(srp->desc);
6065574Smx205022 	DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
6075574Smx205022 }
6085574Smx205022 
6095574Smx205022 /*
6105574Smx205022  * Initialize the slot number of rx's ring
6115574Smx205022  */
6125574Smx205022 static void
6135574Smx205022 nge_init_recv_ring(nge_t *ngep)
6145574Smx205022 {
6155574Smx205022 	recv_ring_t *rrp;
6165574Smx205022 
6175574Smx205022 	rrp = ngep->recv;
6185574Smx205022 	rrp->desc.nslots = ngep->rx_desc;
6195574Smx205022 	rrp->ngep = ngep;
6205574Smx205022 }
6215574Smx205022 
6225574Smx205022 /*
6235574Smx205022  * Intialize the rx recycle pointer and rx sending pointer of rx ring
6245574Smx205022  */
6255574Smx205022 static void
6265574Smx205022 nge_reinit_recv_ring(nge_t *ngep)
6275574Smx205022 {
6285574Smx205022 	recv_ring_t *rrp;
6295574Smx205022 
6305574Smx205022 	rrp = ngep->recv;
6315574Smx205022 
6325574Smx205022 	/*
6335574Smx205022 	 * Reinitialise control variables ...
6345574Smx205022 	 */
6355574Smx205022 	rrp->prod_index = 0;
6365574Smx205022 	/*
6375574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
6385574Smx205022 	 */
6395574Smx205022 	DMA_ZERO(rrp->desc);
6405574Smx205022 	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
6415574Smx205022 }
6425574Smx205022 
6435574Smx205022 /*
6445574Smx205022  * Clean up initialisation done above before the memory is freed
6455574Smx205022  */
6465574Smx205022 static void
6475574Smx205022 nge_fini_buff_ring(nge_t *ngep)
6485574Smx205022 {
6495574Smx205022 	uint32_t i;
6505574Smx205022 	buff_ring_t *brp;
6515574Smx205022 	dma_area_t *bufp;
6525574Smx205022 	sw_rx_sbd_t *bsbdp;
6535574Smx205022 
6545574Smx205022 	brp = ngep->buff;
6555574Smx205022 	bsbdp = brp->sw_rbds;
6565574Smx205022 
6575574Smx205022 	NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
6585574Smx205022 
6595574Smx205022 	mutex_enter(brp->recycle_lock);
6605574Smx205022 	brp->buf_sign++;
6615574Smx205022 	mutex_exit(brp->recycle_lock);
6625574Smx205022 	for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
6635574Smx205022 		if (bsbdp->bufp) {
6645574Smx205022 			if (bsbdp->bufp->mp)
6655574Smx205022 				freemsg(bsbdp->bufp->mp);
6665574Smx205022 			nge_free_dma_mem(bsbdp->bufp);
6675574Smx205022 			kmem_free(bsbdp->bufp, sizeof (dma_area_t));
6685574Smx205022 			bsbdp->bufp = NULL;
6695574Smx205022 		}
6705574Smx205022 	}
6715574Smx205022 	while (brp->free_list != NULL) {
6725574Smx205022 		bufp = brp->free_list;
6735574Smx205022 		brp->free_list = bufp->next;
6745574Smx205022 		bufp->next = NULL;
6755574Smx205022 		if (bufp->mp)
6765574Smx205022 			freemsg(bufp->mp);
6775574Smx205022 		nge_free_dma_mem(bufp);
6785574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6795574Smx205022 	}
6805574Smx205022 	while (brp->recycle_list != NULL) {
6815574Smx205022 		bufp = brp->recycle_list;
6825574Smx205022 		brp->recycle_list = bufp->next;
6835574Smx205022 		bufp->next = NULL;
6845574Smx205022 		if (bufp->mp)
6855574Smx205022 			freemsg(bufp->mp);
6865574Smx205022 		nge_free_dma_mem(bufp);
6875574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6885574Smx205022 	}
6895574Smx205022 
6905574Smx205022 
6915574Smx205022 	kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
6925574Smx205022 	brp->sw_rbds = NULL;
6935574Smx205022 }
6945574Smx205022 
6955574Smx205022 /*
6965574Smx205022  * Intialize the Rx's data ring and free ring
6975574Smx205022  */
6985574Smx205022 static int
6995574Smx205022 nge_init_buff_ring(nge_t *ngep)
7005574Smx205022 {
7015574Smx205022 	uint32_t err;
7025574Smx205022 	uint32_t slot;
7035574Smx205022 	uint32_t nslots_buff;
7045574Smx205022 	uint32_t nslots_recv;
7055574Smx205022 	buff_ring_t *brp;
7065574Smx205022 	recv_ring_t *rrp;
7075574Smx205022 	dma_area_t desc;
7085574Smx205022 	dma_area_t *bufp;
7095574Smx205022 	sw_rx_sbd_t *bsbdp;
7105574Smx205022 
7115574Smx205022 	rrp = ngep->recv;
7125574Smx205022 	brp = ngep->buff;
7135574Smx205022 	brp->nslots = ngep->rx_buf;
7145574Smx205022 	brp->rx_bcopy = B_FALSE;
7155574Smx205022 	nslots_recv = rrp->desc.nslots;
7165574Smx205022 	nslots_buff = brp->nslots;
7175574Smx205022 	brp->ngep = ngep;
7185574Smx205022 
7195574Smx205022 	NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
7205574Smx205022 
7215574Smx205022 	/*
7225574Smx205022 	 * Allocate the array of s/w Recv Buffer Descriptors
7235574Smx205022 	 */
7245574Smx205022 	bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
7255574Smx205022 	brp->sw_rbds = bsbdp;
7265574Smx205022 	brp->free_list = NULL;
7275574Smx205022 	brp->recycle_list = NULL;
7285574Smx205022 	for (slot = 0; slot < nslots_buff; ++slot) {
7295574Smx205022 		bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
7305574Smx205022 		err = nge_alloc_dma_mem(ngep, (ngep->buf_size
7315574Smx205022 		    + NGE_HEADROOM),
7325574Smx205022 		    &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
7335574Smx205022 		if (err != DDI_SUCCESS) {
7345574Smx205022 			kmem_free(bufp, sizeof (dma_area_t));
7355574Smx205022 			return (DDI_FAILURE);
7365574Smx205022 		}
7375574Smx205022 
7385574Smx205022 		bufp->alength -= NGE_HEADROOM;
7395574Smx205022 		bufp->offset += NGE_HEADROOM;
7405574Smx205022 		bufp->private = (caddr_t)ngep;
7415574Smx205022 		bufp->rx_recycle.free_func = nge_recv_recycle;
7425574Smx205022 		bufp->rx_recycle.free_arg = (caddr_t)bufp;
7435574Smx205022 		bufp->signature = brp->buf_sign;
7445574Smx205022 		bufp->rx_delivered = B_FALSE;
7455574Smx205022 		bufp->mp = desballoc(DMA_VPTR(*bufp),
7465574Smx205022 		    ngep->buf_size + NGE_HEADROOM,
7475574Smx205022 		    0, &bufp->rx_recycle);
7485574Smx205022 
7495574Smx205022 		if (bufp->mp == NULL) {
7505574Smx205022 			return (DDI_FAILURE);
7515574Smx205022 		}
7525574Smx205022 		bufp->next = brp->free_list;
7535574Smx205022 		brp->free_list = bufp;
7545574Smx205022 	}
7555574Smx205022 
7565574Smx205022 	/*
7575574Smx205022 	 * Now initialise each array element once and for all
7585574Smx205022 	 */
7595574Smx205022 	desc = rrp->desc;
7605574Smx205022 	for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
7615574Smx205022 		nge_slice_chunk(&bsbdp->desc, &desc, 1,
7625574Smx205022 		    ngep->desc_attr.rxd_size);
7635574Smx205022 		bufp = brp->free_list;
7645574Smx205022 		brp->free_list = bufp->next;
7655574Smx205022 		bsbdp->bufp = bufp;
7665574Smx205022 		bsbdp->flags = CONTROLER_OWN;
7675574Smx205022 		bufp->next = NULL;
7685574Smx205022 	}
7695574Smx205022 
7705574Smx205022 	ASSERT(desc.alength == 0);
7715574Smx205022 	return (DDI_SUCCESS);
7725574Smx205022 }
7735574Smx205022 
7745574Smx205022 /*
7755574Smx205022  * Fill the host address of data in rx' descriptor
7765574Smx205022  * and initialize free pointers of rx free ring
7775574Smx205022  */
7785574Smx205022 static int
7795574Smx205022 nge_reinit_buff_ring(nge_t *ngep)
7805574Smx205022 {
7815574Smx205022 	uint32_t slot;
7825574Smx205022 	uint32_t nslots_recv;
7835574Smx205022 	buff_ring_t *brp;
7845574Smx205022 	recv_ring_t *rrp;
7855574Smx205022 	sw_rx_sbd_t *bsbdp;
7865574Smx205022 	void *hw_bd_p;
7875574Smx205022 
7885574Smx205022 	brp = ngep->buff;
7895574Smx205022 	rrp = ngep->recv;
7905574Smx205022 	bsbdp = brp->sw_rbds;
7915574Smx205022 	nslots_recv = rrp->desc.nslots;
7925574Smx205022 	for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
7935574Smx205022 		hw_bd_p = DMA_VPTR(bsbdp->desc);
7945574Smx205022 	/*
7955574Smx205022 	 * There is a scenario: When the traffic of small tcp
7965574Smx205022 	 * packet is heavy, suspending the tcp traffic will
7975574Smx205022 	 * cause the preallocated buffers for rx not to be
7985574Smx205022 	 * released in time by tcp taffic and cause rx's buffer
7995574Smx205022 	 * pointers not to be refilled in time.
8005574Smx205022 	 *
8015574Smx205022 	 * At this point, if we reinitialize the driver, the bufp
8025574Smx205022 	 * pointer for rx's traffic will be NULL.
8035574Smx205022 	 * So the result of the reinitializion fails.
8045574Smx205022 	 */
8055574Smx205022 		if (bsbdp->bufp == NULL)
8065574Smx205022 			return (DDI_FAILURE);
8075574Smx205022 
8085574Smx205022 		ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
8095574Smx205022 		    bsbdp->bufp->alength);
8105574Smx205022 	}
8115574Smx205022 	return (DDI_SUCCESS);
8125574Smx205022 }
8135574Smx205022 
8145574Smx205022 static void
8155574Smx205022 nge_init_ring_param_lock(nge_t *ngep)
8165574Smx205022 {
8175574Smx205022 	buff_ring_t *brp;
8185574Smx205022 	send_ring_t *srp;
8195574Smx205022 
8205574Smx205022 	srp = ngep->send;
8215574Smx205022 	brp = ngep->buff;
8225574Smx205022 
8235574Smx205022 	/* Init the locks for send ring */
8245574Smx205022 	mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
8255574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8265574Smx205022 	mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
8275574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8285574Smx205022 	mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
8295574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8305574Smx205022 
8315574Smx205022 	/* Init parameters of buffer ring */
8325574Smx205022 	brp->free_list = NULL;
8335574Smx205022 	brp->recycle_list = NULL;
8345574Smx205022 	brp->rx_hold = 0;
8355574Smx205022 	brp->buf_sign = 0;
8365574Smx205022 
8375574Smx205022 	/* Init recycle list lock */
8385574Smx205022 	mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
8395574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8405574Smx205022 }
8415574Smx205022 
8425574Smx205022 int
8435574Smx205022 nge_init_rings(nge_t *ngep)
8445574Smx205022 {
8455574Smx205022 	uint32_t err;
8465574Smx205022 
8475574Smx205022 	err = nge_init_send_ring(ngep);
8485574Smx205022 	if (err != DDI_SUCCESS) {
8495574Smx205022 		return (err);
8505574Smx205022 	}
8515574Smx205022 	nge_init_recv_ring(ngep);
8525574Smx205022 
8535574Smx205022 	err = nge_init_buff_ring(ngep);
8545574Smx205022 	if (err != DDI_SUCCESS) {
8555574Smx205022 		nge_fini_send_ring(ngep);
8565574Smx205022 		return (DDI_FAILURE);
8575574Smx205022 	}
8585574Smx205022 
8595574Smx205022 	return (err);
8605574Smx205022 }
8615574Smx205022 
8625574Smx205022 static int
8635574Smx205022 nge_reinit_ring(nge_t *ngep)
8645574Smx205022 {
8655574Smx205022 	int err;
8665574Smx205022 
8675574Smx205022 	nge_reinit_recv_ring(ngep);
8685574Smx205022 	nge_reinit_send_ring(ngep);
8695574Smx205022 	err = nge_reinit_buff_ring(ngep);
8705574Smx205022 	return (err);
8715574Smx205022 }
8725574Smx205022 
8735574Smx205022 
8745574Smx205022 void
8755574Smx205022 nge_fini_rings(nge_t *ngep)
8765574Smx205022 {
8775574Smx205022 	/*
8785574Smx205022 	 * For receive ring, nothing need to be finished.
8795574Smx205022 	 * So only finish buffer ring and send ring here.
8805574Smx205022 	 */
8815574Smx205022 	nge_fini_buff_ring(ngep);
8825574Smx205022 	nge_fini_send_ring(ngep);
8835574Smx205022 }
8845574Smx205022 
8855574Smx205022 /*
8865574Smx205022  * Loopback ioctl code
8875574Smx205022  */
8885574Smx205022 
8895574Smx205022 static lb_property_t loopmodes[] = {
8905574Smx205022 	{ normal,	"normal",	NGE_LOOP_NONE		},
8915574Smx205022 	{ external,	"100Mbps",	NGE_LOOP_EXTERNAL_100	},
8925574Smx205022 	{ external,	"10Mbps",	NGE_LOOP_EXTERNAL_10	},
8935574Smx205022 	{ internal,	"PHY",		NGE_LOOP_INTERNAL_PHY	},
8945574Smx205022 };
8955574Smx205022 
8965574Smx205022 enum ioc_reply
8975574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
8985574Smx205022 {
8995574Smx205022 	int cmd;
9005574Smx205022 	uint32_t *lbmp;
9015574Smx205022 	lb_info_sz_t *lbsp;
9025574Smx205022 	lb_property_t *lbpp;
9035574Smx205022 
9045574Smx205022 	/*
9055574Smx205022 	 * Validate format of ioctl
9065574Smx205022 	 */
9075574Smx205022 	if (mp->b_cont == NULL)
9085574Smx205022 		return (IOC_INVAL);
9095574Smx205022 
9105574Smx205022 	cmd = iocp->ioc_cmd;
9115574Smx205022 
9125574Smx205022 	switch (cmd) {
9135574Smx205022 	default:
9145574Smx205022 		return (IOC_INVAL);
9155574Smx205022 
9165574Smx205022 	case LB_GET_INFO_SIZE:
9175574Smx205022 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
9185574Smx205022 			return (IOC_INVAL);
9195574Smx205022 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
9205574Smx205022 		*lbsp = sizeof (loopmodes);
9215574Smx205022 		return (IOC_REPLY);
9225574Smx205022 
9235574Smx205022 	case LB_GET_INFO:
9245574Smx205022 		if (iocp->ioc_count != sizeof (loopmodes))
9255574Smx205022 			return (IOC_INVAL);
9265574Smx205022 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
9275574Smx205022 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
9285574Smx205022 		return (IOC_REPLY);
9295574Smx205022 
9305574Smx205022 	case LB_GET_MODE:
9315574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9325574Smx205022 			return (IOC_INVAL);
9335574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9345574Smx205022 		*lbmp = ngep->param_loop_mode;
9355574Smx205022 		return (IOC_REPLY);
9365574Smx205022 
9375574Smx205022 	case LB_SET_MODE:
9385574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9395574Smx205022 			return (IOC_INVAL);
9405574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9415574Smx205022 		return (nge_set_loop_mode(ngep, *lbmp));
9425574Smx205022 	}
9435574Smx205022 }
9445574Smx205022 
9455574Smx205022 #undef	NGE_DBG
9465574Smx205022 #define	NGE_DBG	NGE_DBG_NEMO
9475574Smx205022 
9485574Smx205022 
9495574Smx205022 static void
9505574Smx205022 nge_check_desc_prop(nge_t *ngep)
9515574Smx205022 {
9525574Smx205022 	if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
9535574Smx205022 		ngep->desc_mode = DESC_HOT;
9545574Smx205022 
9555574Smx205022 	if (ngep->desc_mode == DESC_OFFLOAD)	{
9565574Smx205022 
9575574Smx205022 		ngep->desc_attr = nge_sum_desc;
9585574Smx205022 
9595574Smx205022 	}	else if (ngep->desc_mode == DESC_HOT)	{
9605574Smx205022 
9615574Smx205022 		ngep->desc_attr = nge_hot_desc;
9625574Smx205022 	}
9635574Smx205022 }
9645574Smx205022 
9655574Smx205022 /*
9665574Smx205022  * nge_get_props -- get the parameters to tune the driver
9675574Smx205022  */
9685574Smx205022 static void
9695574Smx205022 nge_get_props(nge_t *ngep)
9705574Smx205022 {
9715574Smx205022 	chip_info_t *infop;
9725574Smx205022 	dev_info_t *devinfo;
9735574Smx205022 	nge_dev_spec_param_t *dev_param_p;
9745574Smx205022 
9755574Smx205022 	devinfo = ngep->devinfo;
9765574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
9775574Smx205022 	dev_param_p = &ngep->dev_spec_param;
9785574Smx205022 
9795574Smx205022 	infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9805574Smx205022 	    DDI_PROP_DONTPASS, clsize_propname, 32);
9815574Smx205022 
9825574Smx205022 	infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9835574Smx205022 	    DDI_PROP_DONTPASS, latency_propname, 64);
9845659Sjj146644 	ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9855659Sjj146644 	    DDI_PROP_DONTPASS, intr_moderation, NGE_SET);
9865574Smx205022 	ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9875574Smx205022 	    DDI_PROP_DONTPASS, rx_data_hw, 0x20);
9885574Smx205022 	ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9895574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
9905574Smx205022 	ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9915574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
9925574Smx205022 
9935574Smx205022 	ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9945574Smx205022 	    DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
9955574Smx205022 	ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9965574Smx205022 	    DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
9975574Smx205022 	ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9985574Smx205022 	    DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
9995574Smx205022 	ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10005574Smx205022 	    DDI_PROP_DONTPASS, low_memory_mode, 0);
10018218SMin.Xu@Sun.COM 	ngep->mac_addr_reversion = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10028218SMin.Xu@Sun.COM 	    DDI_PROP_DONTPASS, mac_addr_reversion, 0);
10035574Smx205022 
10045574Smx205022 	if (dev_param_p->jumbo) {
10055574Smx205022 		ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10065574Smx205022 		    DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
10075574Smx205022 	} else
10085574Smx205022 		ngep->default_mtu = ETHERMTU;
10095574Smx205022 
10105574Smx205022 	if (ngep->default_mtu > ETHERMTU &&
10115574Smx205022 	    ngep->default_mtu <= NGE_MTU_2500) {
10125574Smx205022 		ngep->buf_size = NGE_JB2500_BUFSZ;
10135574Smx205022 		ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
10145574Smx205022 		ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
10155574Smx205022 		ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
10165574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10175574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_2500 &&
10185574Smx205022 	    ngep->default_mtu <= NGE_MTU_4500) {
10195574Smx205022 		ngep->buf_size = NGE_JB4500_BUFSZ;
10205574Smx205022 		ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
10215574Smx205022 		ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
10225574Smx205022 		ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
10235574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10245574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_4500 &&
10255574Smx205022 	    ngep->default_mtu <= NGE_MAX_MTU) {
10265574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10275574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10285574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10295574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10305574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10315574Smx205022 	} else if (ngep->default_mtu > NGE_MAX_MTU) {
10325574Smx205022 		ngep->default_mtu = NGE_MAX_MTU;
10335574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10345574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10355574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10365574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10375574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10385574Smx205022 	} else if (ngep->lowmem_mode != 0) {
10395574Smx205022 		ngep->default_mtu = ETHERMTU;
10405574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10415574Smx205022 		ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
10425574Smx205022 		ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
10435574Smx205022 		ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
10445574Smx205022 		ngep->nge_split = NGE_SPLIT_32;
10455574Smx205022 	} else {
10465574Smx205022 		ngep->default_mtu = ETHERMTU;
10475574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10485574Smx205022 		ngep->tx_desc = dev_param_p->tx_desc_num;
10495574Smx205022 		ngep->rx_desc = dev_param_p->rx_desc_num;
10505574Smx205022 		ngep->rx_buf = dev_param_p->rx_desc_num * 2;
10515574Smx205022 		ngep->nge_split = dev_param_p->nge_split;
10525574Smx205022 	}
10535574Smx205022 
10545574Smx205022 	nge_check_desc_prop(ngep);
10555574Smx205022 }
10565574Smx205022 
10575574Smx205022 
10585574Smx205022 static int
10597656SSherry.Moore@Sun.COM nge_reset_dev(nge_t *ngep)
10605574Smx205022 {
10615574Smx205022 	int err;
10625869Smx205022 	nge_mul_addr1 maddr1;
10635869Smx205022 	nge_sw_statistics_t *sw_stp;
10645869Smx205022 	sw_stp = &ngep->statistics.sw_statistics;
10655574Smx205022 	send_ring_t *srp = ngep->send;
10665574Smx205022 
10675574Smx205022 	ASSERT(mutex_owned(ngep->genlock));
10685574Smx205022 	mutex_enter(srp->tc_lock);
10695574Smx205022 	mutex_enter(srp->tx_lock);
10705574Smx205022 
10715574Smx205022 	nge_tx_recycle_all(ngep);
10725574Smx205022 	err = nge_reinit_ring(ngep);
10735574Smx205022 	if (err == DDI_FAILURE) {
10745574Smx205022 		mutex_exit(srp->tx_lock);
10755574Smx205022 		mutex_exit(srp->tc_lock);
10765574Smx205022 		return (err);
10775574Smx205022 	}
10785574Smx205022 	err = nge_chip_reset(ngep);
10795869Smx205022 	/*
10805869Smx205022 	 * Clear the Multicast mac address table
10815869Smx205022 	 */
10825869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
10835869Smx205022 	maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
10845869Smx205022 	maddr1.addr_bits.addr = 0;
10855869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
10865869Smx205022 
10875574Smx205022 	mutex_exit(srp->tx_lock);
10885574Smx205022 	mutex_exit(srp->tc_lock);
10895574Smx205022 	if (err == DDI_FAILURE)
10905574Smx205022 		return (err);
10915574Smx205022 	ngep->watchdog = 0;
10925574Smx205022 	ngep->resched_needed = B_FALSE;
10935574Smx205022 	ngep->promisc = B_FALSE;
10945574Smx205022 	ngep->param_loop_mode = NGE_LOOP_NONE;
10955574Smx205022 	ngep->factotum_flag = 0;
10965574Smx205022 	ngep->resched_needed = 0;
10975574Smx205022 	ngep->nge_mac_state = NGE_MAC_RESET;
10985574Smx205022 	ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
10995574Smx205022 	ngep->max_sdu += VTAG_SIZE;
11005574Smx205022 	ngep->rx_def = 0x16;
11015869Smx205022 
11025869Smx205022 	/* Clear the software statistics */
11035869Smx205022 	sw_stp->recv_count = 0;
11045869Smx205022 	sw_stp->xmit_count = 0;
11055869Smx205022 	sw_stp->rbytes = 0;
11065869Smx205022 	sw_stp->obytes = 0;
11075869Smx205022 
11085574Smx205022 	return (DDI_SUCCESS);
11095574Smx205022 }
11105574Smx205022 
11115574Smx205022 static void
11125574Smx205022 nge_m_stop(void *arg)
11135574Smx205022 {
11145574Smx205022 	nge_t *ngep = arg;		/* private device info	*/
11155574Smx205022 
11165574Smx205022 	NGE_TRACE(("nge_m_stop($%p)", arg));
11175574Smx205022 
11185574Smx205022 	/*
11195574Smx205022 	 * Just stop processing, then record new MAC state
11205574Smx205022 	 */
11215574Smx205022 	mutex_enter(ngep->genlock);
11225869Smx205022 	/* If suspended, the adapter is already stopped, just return. */
11235869Smx205022 	if (ngep->suspended) {
11245869Smx205022 		ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
11255869Smx205022 		mutex_exit(ngep->genlock);
11265869Smx205022 		return;
11275869Smx205022 	}
11285574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11295574Smx205022 
11305574Smx205022 	(void) nge_chip_stop(ngep, B_FALSE);
11315574Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
11325574Smx205022 
11335574Smx205022 	/* Recycle all the TX BD */
11345574Smx205022 	nge_tx_recycle_all(ngep);
11355574Smx205022 	nge_fini_rings(ngep);
11365574Smx205022 	nge_free_bufs(ngep);
11375574Smx205022 
11385574Smx205022 	NGE_DEBUG(("nge_m_stop($%p) done", arg));
11395574Smx205022 
11405574Smx205022 	rw_exit(ngep->rwlock);
11415574Smx205022 	mutex_exit(ngep->genlock);
11425574Smx205022 }
11435574Smx205022 
11445574Smx205022 static int
11455574Smx205022 nge_m_start(void *arg)
11465574Smx205022 {
11475574Smx205022 	int err;
11485574Smx205022 	nge_t *ngep = arg;
11495574Smx205022 
11505574Smx205022 	NGE_TRACE(("nge_m_start($%p)", arg));
11515869Smx205022 
11525869Smx205022 	/*
11535869Smx205022 	 * Start processing and record new MAC state
11545869Smx205022 	 */
11555869Smx205022 	mutex_enter(ngep->genlock);
11565574Smx205022 	/*
11575574Smx205022 	 * If suspended, don't start, as the resume processing
11585574Smx205022 	 * will recall this function with the suspended flag off.
11595574Smx205022 	 */
11605869Smx205022 	if (ngep->suspended) {
11615869Smx205022 		mutex_exit(ngep->genlock);
11625988Svb160487 		return (EIO);
11635869Smx205022 	}
11645574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11655574Smx205022 	err = nge_alloc_bufs(ngep);
11665574Smx205022 	if (err != DDI_SUCCESS) {
11675574Smx205022 		nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
11685574Smx205022 		goto finish;
11695574Smx205022 	}
11705574Smx205022 	err = nge_init_rings(ngep);
11715574Smx205022 	if (err != DDI_SUCCESS) {
11725574Smx205022 		nge_free_bufs(ngep);
11735988Svb160487 		nge_problem(ngep, "nge_init_rings() failed,err=%x", err);
11745574Smx205022 		goto finish;
11755574Smx205022 	}
11765574Smx205022 	err = nge_restart(ngep);
11775574Smx205022 
11785574Smx205022 	NGE_DEBUG(("nge_m_start($%p) done", arg));
11795988Svb160487 finish:
11805988Svb160487 	rw_exit(ngep->rwlock);
11815988Svb160487 	mutex_exit(ngep->genlock);
11825574Smx205022 
11835988Svb160487 	return (err == DDI_SUCCESS ? 0 : EIO);
11845574Smx205022 }
11855574Smx205022 
11865574Smx205022 static int
11875574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr)
11885574Smx205022 {
11895574Smx205022 	nge_t *ngep = arg;
11905574Smx205022 
11915574Smx205022 	NGE_TRACE(("nge_m_unicst($%p)", arg));
11925574Smx205022 	/*
11935574Smx205022 	 * Remember the new current address in the driver state
11945574Smx205022 	 * Sync the chip's idea of the address too ...
11955574Smx205022 	 */
11965574Smx205022 	mutex_enter(ngep->genlock);
11975574Smx205022 
11985574Smx205022 	ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
11995574Smx205022 	ngep->cur_uni_addr.set = 1;
12005574Smx205022 
12015574Smx205022 	/*
12025574Smx205022 	 * If we are suspended, we want to quit now, and not update
12035574Smx205022 	 * the chip.  Doing so might put it in a bad state, but the
12045574Smx205022 	 * resume will get the unicast address installed.
12055574Smx205022 	 */
12065869Smx205022 	if (ngep->suspended) {
12075869Smx205022 		mutex_exit(ngep->genlock);
12085574Smx205022 		return (DDI_SUCCESS);
12095869Smx205022 	}
12105574Smx205022 	nge_chip_sync(ngep);
12115574Smx205022 
12125574Smx205022 	NGE_DEBUG(("nge_m_unicst($%p) done", arg));
12135574Smx205022 	mutex_exit(ngep->genlock);
12145574Smx205022 
12155574Smx205022 	return (0);
12165574Smx205022 }
12175574Smx205022 
12185574Smx205022 static int
12195574Smx205022 nge_m_promisc(void *arg, boolean_t on)
12205574Smx205022 {
12215574Smx205022 	nge_t *ngep = arg;
12225574Smx205022 
12235574Smx205022 	NGE_TRACE(("nge_m_promisc($%p)", arg));
12245574Smx205022 
12255574Smx205022 	/*
12265574Smx205022 	 * Store specified mode and pass to chip layer to update h/w
12275574Smx205022 	 */
12285574Smx205022 	mutex_enter(ngep->genlock);
12295869Smx205022 	/*
12305869Smx205022 	 * If suspended, there is no need to do anything, even
12315869Smx205022 	 * recording the promiscuious mode is not neccessary, as
12325869Smx205022 	 * it won't be properly set on resume.  Just return failing.
12335869Smx205022 	 */
12345869Smx205022 	if (ngep->suspended) {
12355869Smx205022 		mutex_exit(ngep->genlock);
12365869Smx205022 		return (DDI_FAILURE);
12375869Smx205022 	}
12385574Smx205022 	if (ngep->promisc == on) {
12395574Smx205022 		mutex_exit(ngep->genlock);
12405574Smx205022 		NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12415574Smx205022 		return (0);
12425574Smx205022 	}
12435574Smx205022 	ngep->promisc = on;
12447155Smx205022 	ngep->record_promisc = ngep->promisc;
12455574Smx205022 	nge_chip_sync(ngep);
12465574Smx205022 	NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12475574Smx205022 	mutex_exit(ngep->genlock);
12485574Smx205022 
12495574Smx205022 	return (0);
12505574Smx205022 }
12515574Smx205022 
12525574Smx205022 static void nge_mulparam(nge_t *ngep)
12535574Smx205022 {
12545574Smx205022 	uint8_t number;
12555574Smx205022 	ether_addr_t pand;
12565574Smx205022 	ether_addr_t por;
12575574Smx205022 	mul_item *plist;
12585574Smx205022 
12595574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12605574Smx205022 		pand[number] = 0x00;
12615574Smx205022 		por[number] = 0x00;
12625574Smx205022 	}
12635574Smx205022 	for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
12645574Smx205022 		for (number = 0; number < ETHERADDRL; number++) {
12655574Smx205022 			pand[number] &= plist->mul_addr[number];
12665574Smx205022 			por[number] |= plist->mul_addr[number];
12675574Smx205022 		}
12685574Smx205022 	}
12695574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12705574Smx205022 		ngep->cur_mul_addr.addr[number]
12715574Smx205022 		    = pand[number] & por[number];
12725574Smx205022 		ngep->cur_mul_mask.addr[number]
12735574Smx205022 		    = pand [number] | (~por[number]);
12745574Smx205022 	}
12755574Smx205022 }
12765574Smx205022 static int
12775574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
12785574Smx205022 {
12795574Smx205022 	boolean_t update;
12805574Smx205022 	boolean_t b_eq;
12815574Smx205022 	nge_t *ngep = arg;
12825574Smx205022 	mul_item *plist;
12835574Smx205022 	mul_item *plist_prev;
12845574Smx205022 	mul_item *pitem;
12855574Smx205022 
12865574Smx205022 	NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
12875574Smx205022 	    (add) ? "add" : "remove", ether_sprintf((void *)mca)));
12885574Smx205022 
12895574Smx205022 	update = B_FALSE;
12905574Smx205022 	plist = plist_prev = NULL;
12915574Smx205022 	mutex_enter(ngep->genlock);
12925574Smx205022 	if (add) {
12935574Smx205022 		if (ngep->pcur_mulist != NULL) {
12945574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
12955574Smx205022 			    plist = plist->next) {
12965574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
12975574Smx205022 				if (b_eq) {
12985574Smx205022 					plist->ref_cnt++;
12995574Smx205022 					break;
13005574Smx205022 				}
13015574Smx205022 				plist_prev = plist;
13025574Smx205022 			}
13035574Smx205022 		}
13045574Smx205022 
13055574Smx205022 		if (plist == NULL) {
13065574Smx205022 			pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
13075574Smx205022 			ether_copy(mca, pitem->mul_addr);
13085574Smx205022 			pitem ->ref_cnt++;
13095574Smx205022 			pitem ->next = NULL;
13105574Smx205022 			if (plist_prev == NULL)
13115574Smx205022 				ngep->pcur_mulist = pitem;
13125574Smx205022 			else
13135574Smx205022 				plist_prev->next = pitem;
13145574Smx205022 			update = B_TRUE;
13155574Smx205022 		}
13165574Smx205022 	} else {
13175574Smx205022 		if (ngep->pcur_mulist != NULL) {
13185574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13195574Smx205022 			    plist = plist->next) {
13205574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13215574Smx205022 				if (b_eq) {
13225574Smx205022 					update = B_TRUE;
13235574Smx205022 					break;
13245574Smx205022 				}
13255574Smx205022 				plist_prev = plist;
13265574Smx205022 			}
13275574Smx205022 
13285574Smx205022 			if (update) {
13295574Smx205022 				if ((plist_prev == NULL) &&
13305574Smx205022 				    (plist->next == NULL))
13315574Smx205022 					ngep->pcur_mulist = NULL;
13325574Smx205022 				else if ((plist_prev == NULL) &&
13335574Smx205022 				    (plist->next != NULL))
13345574Smx205022 					ngep->pcur_mulist = plist->next;
13355574Smx205022 				else
13365574Smx205022 					plist_prev->next = plist->next;
13375574Smx205022 				kmem_free(plist, sizeof (mul_item));
13385574Smx205022 			}
13395574Smx205022 		}
13405574Smx205022 	}
13415574Smx205022 
13425869Smx205022 	if (update && !ngep->suspended) {
13435574Smx205022 		nge_mulparam(ngep);
13445574Smx205022 		nge_chip_sync(ngep);
13455574Smx205022 	}
13465574Smx205022 	NGE_DEBUG(("nge_m_multicst($%p) done", arg));
13475574Smx205022 	mutex_exit(ngep->genlock);
13485574Smx205022 
13495574Smx205022 	return (0);
13505574Smx205022 }
13515574Smx205022 
13525574Smx205022 static void
13535574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
13545574Smx205022 {
13555574Smx205022 	int err;
13565574Smx205022 	int cmd;
13575574Smx205022 	nge_t *ngep = arg;
13585574Smx205022 	struct iocblk *iocp;
13595574Smx205022 	enum ioc_reply status;
13605574Smx205022 	boolean_t need_privilege;
13615574Smx205022 
13625574Smx205022 	/*
13635574Smx205022 	 * If suspended, we might actually be able to do some of
13645574Smx205022 	 * these ioctls, but it is harder to make sure they occur
13655574Smx205022 	 * without actually putting the hardware in an undesireable
13665574Smx205022 	 * state.  So just NAK it.
13675574Smx205022 	 */
13685869Smx205022 	mutex_enter(ngep->genlock);
13695574Smx205022 	if (ngep->suspended) {
13705574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13715869Smx205022 		mutex_exit(ngep->genlock);
13725574Smx205022 		return;
13735574Smx205022 	}
13745869Smx205022 	mutex_exit(ngep->genlock);
13755574Smx205022 
13765574Smx205022 	/*
13775574Smx205022 	 * Validate the command before bothering with the mutex ...
13785574Smx205022 	 */
13795574Smx205022 	iocp = (struct iocblk *)mp->b_rptr;
13805574Smx205022 	iocp->ioc_error = 0;
13815574Smx205022 	need_privilege = B_TRUE;
13825574Smx205022 	cmd = iocp->ioc_cmd;
13835574Smx205022 
13845574Smx205022 	NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
13855574Smx205022 	switch (cmd) {
13865574Smx205022 	default:
13875574Smx205022 		NGE_LDB(NGE_DBG_BADIOC,
13885574Smx205022 		    ("nge_m_ioctl: unknown cmd 0x%x", cmd));
13895574Smx205022 
13905574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13915574Smx205022 		return;
13925574Smx205022 
13935574Smx205022 	case NGE_MII_READ:
13945574Smx205022 	case NGE_MII_WRITE:
13955574Smx205022 	case NGE_SEE_READ:
13965574Smx205022 	case NGE_SEE_WRITE:
13975574Smx205022 	case NGE_DIAG:
13985574Smx205022 	case NGE_PEEK:
13995574Smx205022 	case NGE_POKE:
14005574Smx205022 	case NGE_PHY_RESET:
14015574Smx205022 	case NGE_SOFT_RESET:
14025574Smx205022 	case NGE_HARD_RESET:
14035574Smx205022 		break;
14045574Smx205022 
14055574Smx205022 	case LB_GET_INFO_SIZE:
14065574Smx205022 	case LB_GET_INFO:
14075574Smx205022 	case LB_GET_MODE:
14085574Smx205022 		need_privilege = B_FALSE;
14095574Smx205022 		break;
14105574Smx205022 	case LB_SET_MODE:
14115574Smx205022 		break;
14125574Smx205022 	}
14135574Smx205022 
14145574Smx205022 	if (need_privilege) {
14155574Smx205022 		/*
14165574Smx205022 		 * Check for specific net_config privilege.
14175574Smx205022 		 */
14185574Smx205022 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
14195574Smx205022 		if (err != 0) {
14205574Smx205022 			NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
14215574Smx205022 			    cmd, err));
14225574Smx205022 			miocnak(wq, mp, 0, err);
14235574Smx205022 			return;
14245574Smx205022 		}
14255574Smx205022 	}
14265574Smx205022 
14275574Smx205022 	mutex_enter(ngep->genlock);
14285574Smx205022 
14295574Smx205022 	switch (cmd) {
14305574Smx205022 	default:
14315574Smx205022 		_NOTE(NOTREACHED)
14325574Smx205022 		status = IOC_INVAL;
14335574Smx205022 	break;
14345574Smx205022 
14355574Smx205022 	case NGE_MII_READ:
14365574Smx205022 	case NGE_MII_WRITE:
14375574Smx205022 	case NGE_SEE_READ:
14385574Smx205022 	case NGE_SEE_WRITE:
14395574Smx205022 	case NGE_DIAG:
14405574Smx205022 	case NGE_PEEK:
14415574Smx205022 	case NGE_POKE:
14425574Smx205022 	case NGE_PHY_RESET:
14435574Smx205022 	case NGE_SOFT_RESET:
14445574Smx205022 	case NGE_HARD_RESET:
14455574Smx205022 		status = nge_chip_ioctl(ngep, mp, iocp);
14465574Smx205022 	break;
14475574Smx205022 
14485574Smx205022 	case LB_GET_INFO_SIZE:
14495574Smx205022 	case LB_GET_INFO:
14505574Smx205022 	case LB_GET_MODE:
14515574Smx205022 	case LB_SET_MODE:
14525574Smx205022 		status = nge_loop_ioctl(ngep, mp, iocp);
14535574Smx205022 	break;
14545574Smx205022 
14555574Smx205022 	}
14565574Smx205022 
14575574Smx205022 	/*
14585574Smx205022 	 * Do we need to reprogram the PHY and/or the MAC?
14595574Smx205022 	 * Do it now, while we still have the mutex.
14605574Smx205022 	 *
14615574Smx205022 	 * Note: update the PHY first, 'cos it controls the
14625574Smx205022 	 * speed/duplex parameters that the MAC code uses.
14635574Smx205022 	 */
14645574Smx205022 
14655574Smx205022 	NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
14665574Smx205022 
14675574Smx205022 	switch (status) {
14685574Smx205022 	case IOC_RESTART_REPLY:
14695574Smx205022 	case IOC_RESTART_ACK:
14705574Smx205022 		(*ngep->physops->phys_update)(ngep);
14715574Smx205022 		nge_chip_sync(ngep);
14725574Smx205022 		break;
14735574Smx205022 
14745574Smx205022 	default:
14755574Smx205022 	break;
14765574Smx205022 	}
14775574Smx205022 
14785574Smx205022 	mutex_exit(ngep->genlock);
14795574Smx205022 
14805574Smx205022 	/*
14815574Smx205022 	 * Finally, decide how to reply
14825574Smx205022 	 */
14835574Smx205022 	switch (status) {
14845574Smx205022 
14855574Smx205022 	default:
14865574Smx205022 	case IOC_INVAL:
14875574Smx205022 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
14885574Smx205022 		    EINVAL : iocp->ioc_error);
14895574Smx205022 		break;
14905574Smx205022 
14915574Smx205022 	case IOC_DONE:
14925574Smx205022 		break;
14935574Smx205022 
14945574Smx205022 	case IOC_RESTART_ACK:
14955574Smx205022 	case IOC_ACK:
14965574Smx205022 		miocack(wq, mp, 0, 0);
14975574Smx205022 		break;
14985574Smx205022 
14995574Smx205022 	case IOC_RESTART_REPLY:
15005574Smx205022 	case IOC_REPLY:
15015574Smx205022 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
15025574Smx205022 		    M_IOCACK : M_IOCNAK;
15035574Smx205022 		qreply(wq, mp);
15045574Smx205022 		break;
15055574Smx205022 	}
15065574Smx205022 }
15075574Smx205022 
15086200Smx205022 static boolean_t
15096200Smx205022 nge_param_locked(mac_prop_id_t pr_num)
15106200Smx205022 {
15116200Smx205022 	/*
15126200Smx205022 	 * All adv_* parameters are locked (read-only) while
15136200Smx205022 	 * the device is in any sort of loopback mode ...
15146200Smx205022 	 */
15156200Smx205022 	switch (pr_num) {
15166789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15176789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15186789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15196789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
15206789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15216789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15226789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15236789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15246789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15256789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15266789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15276789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15286789Sam223141 		case MAC_PROP_AUTONEG:
15296789Sam223141 		case MAC_PROP_FLOWCTRL:
15306200Smx205022 			return (B_TRUE);
15316200Smx205022 	}
15326200Smx205022 	return (B_FALSE);
15336200Smx205022 }
15346200Smx205022 
15356200Smx205022 /*
15366200Smx205022  * callback functions for set/get of properties
15376200Smx205022  */
15386200Smx205022 static int
15396200Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
15406200Smx205022     uint_t pr_valsize, const void *pr_val)
15416200Smx205022 {
15426200Smx205022 	nge_t *ngep = barg;
15436200Smx205022 	int err = 0;
15446512Ssowmini 	uint32_t cur_mtu, new_mtu;
15456200Smx205022 	link_flowctrl_t fl;
15466200Smx205022 
15476200Smx205022 	mutex_enter(ngep->genlock);
15486200Smx205022 	if (ngep->param_loop_mode != NGE_LOOP_NONE &&
15496200Smx205022 	    nge_param_locked(pr_num)) {
15506200Smx205022 		/*
15516200Smx205022 		 * All adv_* parameters are locked (read-only)
15526200Smx205022 		 * while the device is in any sort of loopback mode.
15536200Smx205022 		 */
15546200Smx205022 		mutex_exit(ngep->genlock);
15556200Smx205022 		return (EBUSY);
15566200Smx205022 	}
15576200Smx205022 	switch (pr_num) {
15586789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15596200Smx205022 			ngep->param_en_1000fdx = *(uint8_t *)pr_val;
15606200Smx205022 			ngep->param_adv_1000fdx = *(uint8_t *)pr_val;
15616200Smx205022 			goto reprogram;
15626789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15636200Smx205022 			ngep->param_en_100fdx = *(uint8_t *)pr_val;
15646200Smx205022 			ngep->param_adv_100fdx = *(uint8_t *)pr_val;
15656200Smx205022 			goto reprogram;
15666789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15676200Smx205022 			ngep->param_en_100hdx = *(uint8_t *)pr_val;
15686200Smx205022 			ngep->param_adv_100hdx = *(uint8_t *)pr_val;
15696200Smx205022 			goto reprogram;
15706789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15716200Smx205022 			ngep->param_en_10fdx = *(uint8_t *)pr_val;
15726200Smx205022 			ngep->param_adv_10fdx = *(uint8_t *)pr_val;
15736200Smx205022 			goto reprogram;
15746789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15756200Smx205022 			ngep->param_en_10hdx = *(uint8_t *)pr_val;
15766200Smx205022 			ngep->param_adv_10hdx = *(uint8_t *)pr_val;
15776200Smx205022 reprogram:
15786200Smx205022 		(*ngep->physops->phys_update)(ngep);
15796200Smx205022 		nge_chip_sync(ngep);
15806200Smx205022 		break;
15816200Smx205022 
15826789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15836789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15846789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15856789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15866789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15876789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15886789Sam223141 		case MAC_PROP_STATUS:
15896789Sam223141 		case MAC_PROP_SPEED:
15906789Sam223141 		case MAC_PROP_DUPLEX:
15916789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
15926200Smx205022 			err = ENOTSUP; /* read-only prop. Can't set this */
15936200Smx205022 			break;
15946789Sam223141 		case MAC_PROP_AUTONEG:
15956200Smx205022 			ngep->param_adv_autoneg = *(uint8_t *)pr_val;
15966200Smx205022 			(*ngep->physops->phys_update)(ngep);
15976200Smx205022 			nge_chip_sync(ngep);
15986200Smx205022 			break;
15996789Sam223141 		case MAC_PROP_MTU:
16006200Smx205022 			cur_mtu = ngep->default_mtu;
16016200Smx205022 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
16026200Smx205022 			if (new_mtu == cur_mtu) {
16036200Smx205022 				err = 0;
16046200Smx205022 				break;
16056200Smx205022 			}
16066200Smx205022 			if (new_mtu < ETHERMTU ||
16076200Smx205022 			    new_mtu > NGE_MAX_MTU) {
16086200Smx205022 				err = EINVAL;
16096200Smx205022 				break;
16106200Smx205022 			}
16116200Smx205022 			if ((new_mtu > ETHERMTU) &&
16126200Smx205022 			    (!ngep->dev_spec_param.jumbo)) {
16136200Smx205022 				err = EINVAL;
16146200Smx205022 				break;
16156200Smx205022 			}
16166200Smx205022 			if (ngep->nge_mac_state == NGE_MAC_STARTED) {
16176200Smx205022 				err = EBUSY;
16186200Smx205022 				break;
16196200Smx205022 			}
16206200Smx205022 
16216200Smx205022 			ngep->default_mtu = new_mtu;
16226200Smx205022 			if (ngep->default_mtu > ETHERMTU &&
16236200Smx205022 			    ngep->default_mtu <= NGE_MTU_2500) {
16246200Smx205022 				ngep->buf_size = NGE_JB2500_BUFSZ;
16256200Smx205022 				ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
16266200Smx205022 				ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
16276200Smx205022 				ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
16286200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16296200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_2500 &&
16306200Smx205022 			    ngep->default_mtu <= NGE_MTU_4500) {
16316200Smx205022 				ngep->buf_size = NGE_JB4500_BUFSZ;
16326200Smx205022 				ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
16336200Smx205022 				ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
16346200Smx205022 				ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
16356200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16366200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_4500 &&
16376200Smx205022 			    ngep->default_mtu <= NGE_MAX_MTU) {
16386200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16396200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16406200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16416200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16426200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16436200Smx205022 			} else if (ngep->default_mtu > NGE_MAX_MTU) {
16446200Smx205022 				ngep->default_mtu = NGE_MAX_MTU;
16456200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16466200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16476200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16486200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16496200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16506200Smx205022 			} else if (ngep->lowmem_mode != 0) {
16516200Smx205022 				ngep->default_mtu = ETHERMTU;
16526200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16536200Smx205022 				ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
16546200Smx205022 				ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
16556200Smx205022 				ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
16566200Smx205022 				ngep->nge_split = NGE_SPLIT_32;
16576200Smx205022 			} else {
16586200Smx205022 				ngep->default_mtu = ETHERMTU;
16596200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16606200Smx205022 				ngep->tx_desc =
16616200Smx205022 				    ngep->dev_spec_param.tx_desc_num;
16626200Smx205022 				ngep->rx_desc =
16636200Smx205022 				    ngep->dev_spec_param.rx_desc_num;
16646200Smx205022 				ngep->rx_buf =
16656200Smx205022 				    ngep->dev_spec_param.rx_desc_num * 2;
16666200Smx205022 				ngep->nge_split =
16676200Smx205022 				    ngep->dev_spec_param.nge_split;
16686200Smx205022 			}
16696200Smx205022 
16706200Smx205022 			err = mac_maxsdu_update(ngep->mh, ngep->default_mtu);
16716200Smx205022 
16726200Smx205022 			break;
16736789Sam223141 		case MAC_PROP_FLOWCTRL:
16746200Smx205022 			bcopy(pr_val, &fl, sizeof (fl));
16756200Smx205022 			switch (fl) {
16766200Smx205022 			default:
16776200Smx205022 				err = ENOTSUP;
16786200Smx205022 				break;
16796200Smx205022 			case LINK_FLOWCTRL_NONE:
16806200Smx205022 				ngep->param_adv_pause = 0;
16816200Smx205022 				ngep->param_adv_asym_pause = 0;
16826200Smx205022 
16836200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
16846200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
16856200Smx205022 				break;
16866200Smx205022 			case LINK_FLOWCTRL_RX:
16876200Smx205022 				if (!((ngep->param_lp_pause == 0) &&
16886200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
16896200Smx205022 					err = EINVAL;
16906200Smx205022 					break;
16916200Smx205022 				}
16926200Smx205022 				ngep->param_adv_pause = 1;
16936200Smx205022 				ngep->param_adv_asym_pause = 1;
16946200Smx205022 
16956200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
16966200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
16976200Smx205022 				break;
16986200Smx205022 			case LINK_FLOWCTRL_TX:
16996200Smx205022 				if (!((ngep->param_lp_pause == 1) &&
17006200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
17016200Smx205022 					err = EINVAL;
17026200Smx205022 					break;
17036200Smx205022 				}
17046200Smx205022 				ngep->param_adv_pause = 0;
17056200Smx205022 				ngep->param_adv_asym_pause = 1;
17066200Smx205022 
17076200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
17086200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17096200Smx205022 				break;
17106200Smx205022 			case LINK_FLOWCTRL_BI:
17116200Smx205022 				if (ngep->param_lp_pause != 1) {
17126200Smx205022 					err = EINVAL;
17136200Smx205022 					break;
17146200Smx205022 				}
17156200Smx205022 				ngep->param_adv_pause = 1;
17166200Smx205022 
17176200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17186200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17196200Smx205022 				break;
17206200Smx205022 			}
17216200Smx205022 
17226200Smx205022 			if (err == 0) {
17236200Smx205022 				(*ngep->physops->phys_update)(ngep);
17246200Smx205022 				nge_chip_sync(ngep);
17256200Smx205022 			}
17266200Smx205022 
17276200Smx205022 			break;
17286789Sam223141 		case MAC_PROP_PRIVATE:
17296200Smx205022 			err = nge_set_priv_prop(ngep, pr_name, pr_valsize,
17306200Smx205022 			    pr_val);
17316200Smx205022 			if (err == 0) {
17326200Smx205022 				(*ngep->physops->phys_update)(ngep);
17336200Smx205022 				nge_chip_sync(ngep);
17346200Smx205022 			}
17356200Smx205022 			break;
17366200Smx205022 		default:
17376200Smx205022 			err = ENOTSUP;
17386200Smx205022 	}
17396200Smx205022 	mutex_exit(ngep->genlock);
17406200Smx205022 	return (err);
17416200Smx205022 }
17426200Smx205022 
17436200Smx205022 static int
17446200Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
17458118SVasumathi.Sundaram@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
17466200Smx205022 {
17476200Smx205022 	nge_t *ngep = barg;
17486512Ssowmini 	int err = 0;
17496200Smx205022 	link_flowctrl_t fl;
17506512Ssowmini 	uint64_t speed;
17516789Sam223141 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
17526512Ssowmini 
17536512Ssowmini 	if (pr_valsize == 0)
17546512Ssowmini 		return (EINVAL);
17556200Smx205022 
17568118SVasumathi.Sundaram@Sun.COM 	*perm = MAC_PROP_PERM_RW;
17578118SVasumathi.Sundaram@Sun.COM 
17586200Smx205022 	bzero(pr_val, pr_valsize);
17598118SVasumathi.Sundaram@Sun.COM 
17606200Smx205022 	switch (pr_num) {
17616789Sam223141 		case MAC_PROP_DUPLEX:
17628118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
17636512Ssowmini 			if (pr_valsize >= sizeof (link_duplex_t)) {
17646512Ssowmini 				bcopy(&ngep->param_link_duplex, pr_val,
17656512Ssowmini 				    sizeof (link_duplex_t));
17666512Ssowmini 			} else
17676512Ssowmini 				err = EINVAL;
17686200Smx205022 			break;
17696789Sam223141 		case MAC_PROP_SPEED:
17708118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
17716200Smx205022 			if (pr_valsize >= sizeof (uint64_t)) {
17726512Ssowmini 				speed = ngep->param_link_speed * 1000000ull;
17736512Ssowmini 				bcopy(&speed, pr_val, sizeof (speed));
17746512Ssowmini 			} else
17756512Ssowmini 				err = EINVAL;
17766200Smx205022 			break;
17776789Sam223141 		case MAC_PROP_AUTONEG:
17786512Ssowmini 			if (is_default) {
17796512Ssowmini 				*(uint8_t *)pr_val = 1;
17806512Ssowmini 			} else {
17816200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_autoneg;
17826200Smx205022 			}
17836200Smx205022 			break;
17846789Sam223141 		case MAC_PROP_FLOWCTRL:
17856200Smx205022 			if (pr_valsize >= sizeof (link_flowctrl_t)) {
17866789Sam223141 				if (pr_flags & MAC_PROP_DEFAULT) {
17876512Ssowmini 					fl = LINK_FLOWCTRL_BI;
17886512Ssowmini 					bcopy(&fl, pr_val, sizeof (fl));
17896512Ssowmini 					break;
17906512Ssowmini 				}
17916200Smx205022 				if (ngep->param_link_rx_pause &&
17926200Smx205022 				    !ngep->param_link_tx_pause)
17936200Smx205022 					fl = LINK_FLOWCTRL_RX;
17946200Smx205022 
17956200Smx205022 				if (!ngep->param_link_rx_pause &&
17966200Smx205022 				    !ngep->param_link_tx_pause)
17976200Smx205022 					fl = LINK_FLOWCTRL_NONE;
17986200Smx205022 
17996200Smx205022 				if (!ngep->param_link_rx_pause &&
18006200Smx205022 				    ngep->param_link_tx_pause)
18016200Smx205022 					fl = LINK_FLOWCTRL_TX;
18026200Smx205022 
18036200Smx205022 				if (ngep->param_link_rx_pause &&
18046200Smx205022 				    ngep->param_link_tx_pause)
18056200Smx205022 					fl = LINK_FLOWCTRL_BI;
18066200Smx205022 				bcopy(&fl, pr_val, sizeof (fl));
18076512Ssowmini 			} else
18086512Ssowmini 				err = EINVAL;
18096200Smx205022 			break;
18106789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
18118118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18126512Ssowmini 			if (is_default) {
18136512Ssowmini 				*(uint8_t *)pr_val = 1;
18146512Ssowmini 			} else {
18156200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_1000fdx;
18166200Smx205022 			}
18176200Smx205022 			break;
18186789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
18196512Ssowmini 			if (is_default) {
18206512Ssowmini 				*(uint8_t *)pr_val = 1;
18216512Ssowmini 			} else {
18226200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_1000fdx;
18236200Smx205022 			}
18246200Smx205022 			break;
18256789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
18268118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18276512Ssowmini 			if (is_default) {
18286512Ssowmini 				*(uint8_t *)pr_val = 0;
18296512Ssowmini 			} else {
18306200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_1000hdx;
18316200Smx205022 			}
18326200Smx205022 			break;
18336789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
18348118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18356512Ssowmini 			if (is_default) {
18366512Ssowmini 				*(uint8_t *)pr_val = 0;
18376512Ssowmini 			} else {
18386200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_1000hdx;
18396200Smx205022 			}
18406200Smx205022 			break;
18416789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
18428118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18436512Ssowmini 			if (is_default) {
18446512Ssowmini 				*(uint8_t *)pr_val = 1;
18456512Ssowmini 			} else {
18466200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_100fdx;
18476200Smx205022 			}
18486200Smx205022 			break;
18496789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
18506512Ssowmini 			if (is_default) {
18516512Ssowmini 				*(uint8_t *)pr_val = 1;
18526512Ssowmini 			} else {
18536200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_100fdx;
18546200Smx205022 			}
18556200Smx205022 			break;
18566789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
18578118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18586512Ssowmini 			if (is_default) {
18596512Ssowmini 				*(uint8_t *)pr_val = 1;
18606512Ssowmini 			} else {
18616200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_100hdx;
18626200Smx205022 			}
18636200Smx205022 			break;
18646789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
18656512Ssowmini 			if (is_default) {
18666512Ssowmini 				*(uint8_t *)pr_val = 1;
18676512Ssowmini 			} else {
18686200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_100hdx;
18696200Smx205022 			}
18706200Smx205022 			break;
18716789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
18728118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18736512Ssowmini 			if (is_default) {
18746512Ssowmini 				*(uint8_t *)pr_val = 1;
18756512Ssowmini 			} else {
18766200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_10fdx;
18776200Smx205022 			}
18786200Smx205022 			break;
18796789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
18806512Ssowmini 			if (is_default) {
18816512Ssowmini 				*(uint8_t *)pr_val = 1;
18826512Ssowmini 			} else {
18836200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_10fdx;
18846200Smx205022 			}
18856200Smx205022 			break;
18866789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
18878118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18886512Ssowmini 			if (is_default) {
18896512Ssowmini 				*(uint8_t *)pr_val = 1;
18906512Ssowmini 			} else {
18916200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_10hdx;
18926200Smx205022 			}
18936200Smx205022 			break;
18946789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
18956512Ssowmini 			if (is_default) {
18966512Ssowmini 				*(uint8_t *)pr_val = 1;
18976512Ssowmini 			} else {
18986200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_10hdx;
18996200Smx205022 			}
19006200Smx205022 			break;
19016789Sam223141 		case MAC_PROP_ADV_100T4_CAP:
19026789Sam223141 		case MAC_PROP_EN_100T4_CAP:
19038118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
19046512Ssowmini 			*(uint8_t *)pr_val = 0;
19056512Ssowmini 			break;
19066789Sam223141 		case MAC_PROP_PRIVATE:
19076512Ssowmini 			err = nge_get_priv_prop(ngep, pr_name, pr_flags,
19086512Ssowmini 			    pr_valsize, pr_val);
19096200Smx205022 			break;
19109514SGirish.Moodalbail@Sun.COM 		case MAC_PROP_MTU: {
19119514SGirish.Moodalbail@Sun.COM 			mac_propval_range_t range;
19129514SGirish.Moodalbail@Sun.COM 
19139514SGirish.Moodalbail@Sun.COM 			if (!(pr_flags & MAC_PROP_POSSIBLE))
19149514SGirish.Moodalbail@Sun.COM 				return (ENOTSUP);
19159514SGirish.Moodalbail@Sun.COM 			if (pr_valsize < sizeof (mac_propval_range_t))
19169514SGirish.Moodalbail@Sun.COM 				return (EINVAL);
19179514SGirish.Moodalbail@Sun.COM 			range.mpr_count = 1;
19189514SGirish.Moodalbail@Sun.COM 			range.mpr_type = MAC_PROPVAL_UINT32;
19199514SGirish.Moodalbail@Sun.COM 			range.range_uint32[0].mpur_min =
19209514SGirish.Moodalbail@Sun.COM 			    range.range_uint32[0].mpur_max = ETHERMTU;
19219514SGirish.Moodalbail@Sun.COM 			if (ngep->dev_spec_param.jumbo)
19229514SGirish.Moodalbail@Sun.COM 				range.range_uint32[0].mpur_max = NGE_MAX_MTU;
19239514SGirish.Moodalbail@Sun.COM 			bcopy(&range, pr_val, sizeof (range));
19249514SGirish.Moodalbail@Sun.COM 			break;
19259514SGirish.Moodalbail@Sun.COM 		}
19266200Smx205022 		default:
19276200Smx205022 			err = ENOTSUP;
19286200Smx205022 	}
19296200Smx205022 	return (err);
19306200Smx205022 }
19316200Smx205022 
19326200Smx205022 /* ARGSUSED */
19336200Smx205022 static int
19346200Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
19356200Smx205022     const void *pr_val)
19366200Smx205022 {
19376200Smx205022 	int err = 0;
19386200Smx205022 	long result;
19396200Smx205022 
19406200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
19416200Smx205022 		if (pr_val == NULL) {
19426200Smx205022 			err = EINVAL;
19436200Smx205022 			return (err);
19446200Smx205022 		}
19456200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19466200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19476200Smx205022 			err = EINVAL;
19486200Smx205022 		} else {
19496200Smx205022 			ngep->param_txbcopy_threshold = (uint32_t)result;
19506200Smx205022 			goto reprogram;
19516200Smx205022 		}
19526200Smx205022 		return (err);
19536200Smx205022 	}
19546200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
19556200Smx205022 		if (pr_val == NULL) {
19566200Smx205022 			err = EINVAL;
19576200Smx205022 			return (err);
19586200Smx205022 		}
19596200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19606200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19616200Smx205022 			err = EINVAL;
19626200Smx205022 		} else {
19636200Smx205022 			ngep->param_rxbcopy_threshold = (uint32_t)result;
19646200Smx205022 			goto reprogram;
19656200Smx205022 		}
19666200Smx205022 		return (err);
19676200Smx205022 	}
19686200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
19696200Smx205022 		if (pr_val == NULL) {
19706200Smx205022 			err = EINVAL;
19716200Smx205022 			return (err);
19726200Smx205022 		}
19736200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19746200Smx205022 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
19756200Smx205022 			err = EINVAL;
19766200Smx205022 		} else {
19776200Smx205022 			ngep->param_recv_max_packet = (uint32_t)result;
19786200Smx205022 			goto reprogram;
19796200Smx205022 		}
19806200Smx205022 		return (err);
19816200Smx205022 	}
19826200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
19836200Smx205022 		if (pr_val == NULL) {
19846200Smx205022 			err = EINVAL;
19856200Smx205022 			return (err);
19866200Smx205022 		}
19876200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19886200Smx205022 		if (result < 0 || result > 10000) {
19896200Smx205022 			err = EINVAL;
19906200Smx205022 		} else {
19916200Smx205022 			ngep->param_poll_quiet_time = (uint32_t)result;
19926200Smx205022 			goto reprogram;
19936200Smx205022 		}
19946200Smx205022 		return (err);
19956200Smx205022 	}
19966200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
19976200Smx205022 		if (pr_val == NULL) {
19986200Smx205022 			err = EINVAL;
19996200Smx205022 			return (err);
20006200Smx205022 		}
20016200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20026200Smx205022 		if (result < 0 || result > 10000) {
20036200Smx205022 			err = EINVAL;
20046200Smx205022 		} else {
20056200Smx205022 			ngep->param_poll_busy_time = (uint32_t)result;
20066200Smx205022 			goto reprogram;
20076200Smx205022 		}
20086200Smx205022 		return (err);
20096200Smx205022 	}
20106200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
20116200Smx205022 		if (pr_val == NULL) {
20126200Smx205022 			err = EINVAL;
20136200Smx205022 			return (err);
20146200Smx205022 		}
20156200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20166512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20176200Smx205022 			err = EINVAL;
20186200Smx205022 		} else {
20196200Smx205022 			ngep->param_rx_intr_hwater = (uint32_t)result;
20206200Smx205022 			goto reprogram;
20216200Smx205022 		}
20226200Smx205022 		return (err);
20236200Smx205022 	}
20246200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
20256200Smx205022 		if (pr_val == NULL) {
20266200Smx205022 			err = EINVAL;
20276200Smx205022 			return (err);
20286200Smx205022 		}
20296200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20306512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20316200Smx205022 			err = EINVAL;
20326200Smx205022 		} else {
20336200Smx205022 			ngep->param_rx_intr_lwater = (uint32_t)result;
20346200Smx205022 			goto reprogram;
20356200Smx205022 		}
20366200Smx205022 		return (err);
20376200Smx205022 	}
20386200Smx205022 	if (strcmp(pr_name, "_tx_n_intr") == 0) {
20396200Smx205022 		if (pr_val == NULL) {
20406200Smx205022 			err = EINVAL;
20416200Smx205022 			return (err);
20426200Smx205022 		}
20436200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20446200Smx205022 		if (result < 1 || result > 10000) {
20456200Smx205022 			err = EINVAL;
20466200Smx205022 		} else {
20476200Smx205022 			ngep->param_tx_n_intr = (uint32_t)result;
20486200Smx205022 			goto reprogram;
20496200Smx205022 		}
20506200Smx205022 		return (err);
20516200Smx205022 	}
20526200Smx205022 
20536200Smx205022 	err = ENOTSUP;
20546200Smx205022 	return (err);
20556200Smx205022 
20566200Smx205022 reprogram:
20576200Smx205022 	if (err == 0) {
20586200Smx205022 		(*ngep->physops->phys_update)(ngep);
20596200Smx205022 		nge_chip_sync(ngep);
20606200Smx205022 	}
20616200Smx205022 
20626200Smx205022 	return (err);
20636200Smx205022 }
20646200Smx205022 
20656200Smx205022 static int
20666512Ssowmini nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_flags,
20676512Ssowmini     uint_t pr_valsize, void *pr_val)
20686200Smx205022 {
20696200Smx205022 	int err = ENOTSUP;
20706789Sam223141 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
20716512Ssowmini 	int value;
20726512Ssowmini 
20736512Ssowmini 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
20746512Ssowmini 		value = (is_default ? 1 : ngep->param_adv_pause);
20756512Ssowmini 		err = 0;
20766512Ssowmini 		goto done;
20776512Ssowmini 	}
20786512Ssowmini 	if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
20796512Ssowmini 		value = (is_default ? 1 : ngep->param_adv_asym_pause);
20806512Ssowmini 		err = 0;
20816512Ssowmini 		goto done;
20826512Ssowmini 	}
20836200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
20846512Ssowmini 		value = (is_default ? NGE_TX_COPY_SIZE :
20856512Ssowmini 		    ngep->param_txbcopy_threshold);
20866200Smx205022 		err = 0;
20876200Smx205022 		goto done;
20886200Smx205022 	}
20896200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
20906512Ssowmini 		value = (is_default ? NGE_RX_COPY_SIZE :
20916512Ssowmini 		    ngep->param_rxbcopy_threshold);
20926200Smx205022 		err = 0;
20936200Smx205022 		goto done;
20946200Smx205022 	}
20956200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
20966512Ssowmini 		value = (is_default ? 128 : ngep->param_recv_max_packet);
20976200Smx205022 		err = 0;
20986200Smx205022 		goto done;
20996200Smx205022 	}
21006200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
21016512Ssowmini 		value = (is_default ? NGE_POLL_QUIET_TIME :
21026512Ssowmini 		    ngep->param_poll_quiet_time);
21036200Smx205022 		err = 0;
21046200Smx205022 		goto done;
21056200Smx205022 	}
21066200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
21076512Ssowmini 		value = (is_default ? NGE_POLL_BUSY_TIME :
21086512Ssowmini 		    ngep->param_poll_busy_time);
21096200Smx205022 		err = 0;
21106200Smx205022 		goto done;
21116200Smx205022 	}
21126200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
21136512Ssowmini 		value = (is_default ? 1 : ngep->param_rx_intr_hwater);
21146200Smx205022 		err = 0;
21156200Smx205022 		goto done;
21166200Smx205022 	}
21176200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
21186512Ssowmini 		value = (is_default ? 8 : ngep->param_rx_intr_lwater);
21196200Smx205022 		err = 0;
21206200Smx205022 		goto done;
21216200Smx205022 	}
21226200Smx205022 	if (strcmp(pr_name, "_tx_n_intr") == 0) {
21236512Ssowmini 		value = (is_default ? NGE_TX_N_INTR :
21246512Ssowmini 		    ngep->param_tx_n_intr);
21256200Smx205022 		err = 0;
21266200Smx205022 		goto done;
21276200Smx205022 	}
21286200Smx205022 
21296200Smx205022 done:
21306200Smx205022 	if (err == 0) {
21316512Ssowmini 		(void) snprintf(pr_val, pr_valsize, "%d", value);
21326200Smx205022 	}
21336200Smx205022 	return (err);
21346200Smx205022 }
21356200Smx205022 
21365574Smx205022 /* ARGSUSED */
21375574Smx205022 static boolean_t
21385574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
21395574Smx205022 {
21405574Smx205022 	nge_t	*ngep = arg;
21415574Smx205022 	nge_dev_spec_param_t *dev_param_p;
21425574Smx205022 
21435574Smx205022 	dev_param_p = &ngep->dev_spec_param;
21445574Smx205022 
21455574Smx205022 	switch (cap) {
21465574Smx205022 	case MAC_CAPAB_HCKSUM: {
21475574Smx205022 		uint32_t *hcksum_txflags = cap_data;
21485574Smx205022 
21495574Smx205022 		if (dev_param_p->tx_hw_checksum) {
21505574Smx205022 			*hcksum_txflags = dev_param_p->tx_hw_checksum;
21515574Smx205022 		} else
21525574Smx205022 			return (B_FALSE);
21535574Smx205022 		break;
21545574Smx205022 	}
21555574Smx205022 	default:
21565574Smx205022 		return (B_FALSE);
21575574Smx205022 	}
21585574Smx205022 	return (B_TRUE);
21595574Smx205022 }
21605574Smx205022 
21615574Smx205022 #undef	NGE_DBG
21625574Smx205022 #define	NGE_DBG	NGE_DBG_INIT	/* debug flag for this code	*/
21635574Smx205022 int
21645574Smx205022 nge_restart(nge_t *ngep)
21655574Smx205022 {
21665574Smx205022 	int err = 0;
21677656SSherry.Moore@Sun.COM 	err = nge_reset_dev(ngep);
21687155Smx205022 	/* write back the promisc setting */
21697155Smx205022 	ngep->promisc = ngep->record_promisc;
21706366Smx205022 	nge_chip_sync(ngep);
21715869Smx205022 	if (!err)
21725869Smx205022 		err = nge_chip_start(ngep);
21735574Smx205022 
21745574Smx205022 	if (err) {
21755574Smx205022 		ngep->nge_mac_state = NGE_MAC_STOPPED;
21765574Smx205022 		return (DDI_FAILURE);
21775574Smx205022 	} else {
21785574Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
21795574Smx205022 		return (DDI_SUCCESS);
21805574Smx205022 	}
21815574Smx205022 }
21825574Smx205022 
21835574Smx205022 void
21845574Smx205022 nge_wake_factotum(nge_t *ngep)
21855574Smx205022 {
21865574Smx205022 	mutex_enter(ngep->softlock);
21875574Smx205022 	if (ngep->factotum_flag == 0) {
21885574Smx205022 		ngep->factotum_flag = 1;
21895574Smx205022 		(void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
21905574Smx205022 	}
21915574Smx205022 	mutex_exit(ngep->softlock);
21925574Smx205022 }
21935574Smx205022 
21945574Smx205022 /*
21955574Smx205022  * High-level cyclic handler
21965574Smx205022  *
21975574Smx205022  * This routine schedules a (low-level) softint callback to the
21985574Smx205022  * factotum.
21995574Smx205022  */
22005574Smx205022 
22015574Smx205022 static void
22025574Smx205022 nge_chip_cyclic(void *arg)
22035574Smx205022 {
22045574Smx205022 	nge_t *ngep;
22055574Smx205022 
22065574Smx205022 	ngep = (nge_t *)arg;
22075574Smx205022 
22085574Smx205022 	switch (ngep->nge_chip_state) {
22095574Smx205022 	default:
22105574Smx205022 		return;
22115574Smx205022 
22125574Smx205022 	case NGE_CHIP_RUNNING:
22135574Smx205022 		break;
22145574Smx205022 
22155574Smx205022 	case NGE_CHIP_FAULT:
22165574Smx205022 	case NGE_CHIP_ERROR:
22175574Smx205022 		break;
22185574Smx205022 	}
22195574Smx205022 
22205574Smx205022 	nge_wake_factotum(ngep);
22215574Smx205022 }
22225574Smx205022 
2223*9604SZhen.W@Sun.COM /*
2224*9604SZhen.W@Sun.COM  * Get/Release semaphore of SMU
2225*9604SZhen.W@Sun.COM  * For SMU enabled chipset
2226*9604SZhen.W@Sun.COM  * When nge driver is attached, driver should acquire
2227*9604SZhen.W@Sun.COM  * semaphore before PHY init and accessing MAC registers.
2228*9604SZhen.W@Sun.COM  * When nge driver is unattached, driver should release
2229*9604SZhen.W@Sun.COM  * semaphore.
2230*9604SZhen.W@Sun.COM  */
2231*9604SZhen.W@Sun.COM 
2232*9604SZhen.W@Sun.COM static int
2233*9604SZhen.W@Sun.COM nge_smu_sema(nge_t *ngep, boolean_t acquire)
2234*9604SZhen.W@Sun.COM {
2235*9604SZhen.W@Sun.COM 	nge_tx_en tx_en;
2236*9604SZhen.W@Sun.COM 	uint32_t tries;
2237*9604SZhen.W@Sun.COM 
2238*9604SZhen.W@Sun.COM 	if (acquire) {
2239*9604SZhen.W@Sun.COM 		for (tries = 0; tries < 5; tries++) {
2240*9604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2241*9604SZhen.W@Sun.COM 			if (tx_en.bits.smu2mac == NGE_SMU_FREE)
2242*9604SZhen.W@Sun.COM 				break;
2243*9604SZhen.W@Sun.COM 			delay(drv_usectohz(1000000));
2244*9604SZhen.W@Sun.COM 		}
2245*9604SZhen.W@Sun.COM 		if (tx_en.bits.smu2mac != NGE_SMU_FREE)
2246*9604SZhen.W@Sun.COM 			return (DDI_FAILURE);
2247*9604SZhen.W@Sun.COM 		for (tries = 0; tries < 5; tries++) {
2248*9604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2249*9604SZhen.W@Sun.COM 			tx_en.bits.mac2smu = NGE_SMU_GET;
2250*9604SZhen.W@Sun.COM 			nge_reg_put32(ngep, NGE_TX_EN, tx_en.val);
2251*9604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
2252*9604SZhen.W@Sun.COM 
2253*9604SZhen.W@Sun.COM 			if (tx_en.bits.mac2smu == NGE_SMU_GET &&
2254*9604SZhen.W@Sun.COM 			    tx_en.bits.smu2mac == NGE_SMU_FREE)
2255*9604SZhen.W@Sun.COM 				return (DDI_SUCCESS);
2256*9604SZhen.W@Sun.COM 			drv_usecwait(10);
2257*9604SZhen.W@Sun.COM 		}
2258*9604SZhen.W@Sun.COM 		return (DDI_FAILURE);
2259*9604SZhen.W@Sun.COM 	} else
2260*9604SZhen.W@Sun.COM 		nge_reg_put32(ngep, NGE_TX_EN, 0x0);
2261*9604SZhen.W@Sun.COM 
2262*9604SZhen.W@Sun.COM 	return (DDI_SUCCESS);
2263*9604SZhen.W@Sun.COM 
2264*9604SZhen.W@Sun.COM }
22655574Smx205022 static void
22665574Smx205022 nge_unattach(nge_t *ngep)
22675574Smx205022 {
22685574Smx205022 	send_ring_t *srp;
22695574Smx205022 	buff_ring_t *brp;
22705574Smx205022 
22715574Smx205022 	srp = ngep->send;
22725574Smx205022 	brp = ngep->buff;
22735574Smx205022 	NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
22745574Smx205022 
22755574Smx205022 	/*
22765574Smx205022 	 * Flag that no more activity may be initiated
22775574Smx205022 	 */
22785574Smx205022 	ngep->progress &= ~PROGRESS_READY;
22795574Smx205022 	ngep->nge_mac_state = NGE_MAC_UNATTACH;
22805574Smx205022 
22815574Smx205022 	/*
22825574Smx205022 	 * Quiesce the PHY and MAC (leave it reset but still powered).
22835574Smx205022 	 * Clean up and free all NGE data structures
22845574Smx205022 	 */
22855574Smx205022 	if (ngep->periodic_id != NULL) {
22865574Smx205022 		ddi_periodic_delete(ngep->periodic_id);
22875574Smx205022 		ngep->periodic_id = NULL;
22885574Smx205022 	}
22895574Smx205022 
22905574Smx205022 	if (ngep->progress & PROGRESS_KSTATS)
22915574Smx205022 		nge_fini_kstats(ngep);
22925574Smx205022 
22935574Smx205022 	if (ngep->progress & PROGRESS_HWINT) {
22945574Smx205022 		mutex_enter(ngep->genlock);
22955574Smx205022 		nge_restore_mac_addr(ngep);
22965574Smx205022 		(void) nge_chip_stop(ngep, B_FALSE);
2297*9604SZhen.W@Sun.COM 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2298*9604SZhen.W@Sun.COM 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2299*9604SZhen.W@Sun.COM 			(void) nge_smu_sema(ngep, B_FALSE);
2300*9604SZhen.W@Sun.COM 		}
23015574Smx205022 		mutex_exit(ngep->genlock);
23025574Smx205022 	}
23035574Smx205022 
23045574Smx205022 	if (ngep->progress & PROGRESS_SWINT)
23055574Smx205022 		nge_rem_intrs(ngep);
23065574Smx205022 
23075574Smx205022 	if (ngep->progress & PROGRESS_FACTOTUM)
23085574Smx205022 		(void) ddi_intr_remove_softint(ngep->factotum_hdl);
23095574Smx205022 
23105574Smx205022 	if (ngep->progress & PROGRESS_RESCHED)
23115574Smx205022 		(void) ddi_intr_remove_softint(ngep->resched_hdl);
23125574Smx205022 
23135574Smx205022 	if (ngep->progress & PROGRESS_INTR) {
23145574Smx205022 		mutex_destroy(srp->tx_lock);
23155574Smx205022 		mutex_destroy(srp->tc_lock);
23165574Smx205022 		mutex_destroy(&srp->dmah_lock);
23175574Smx205022 		mutex_destroy(brp->recycle_lock);
23185574Smx205022 
23195574Smx205022 		mutex_destroy(ngep->genlock);
23205574Smx205022 		mutex_destroy(ngep->softlock);
23215574Smx205022 		rw_destroy(ngep->rwlock);
23225574Smx205022 	}
23235574Smx205022 
23245574Smx205022 	if (ngep->progress & PROGRESS_REGS)
23255574Smx205022 		ddi_regs_map_free(&ngep->io_handle);
23265574Smx205022 
23275574Smx205022 	if (ngep->progress & PROGRESS_CFG)
23285574Smx205022 		pci_config_teardown(&ngep->cfg_handle);
23295574Smx205022 
23305574Smx205022 	ddi_remove_minor_node(ngep->devinfo, NULL);
23315574Smx205022 
23325574Smx205022 	kmem_free(ngep, sizeof (*ngep));
23335574Smx205022 }
23345574Smx205022 
23355574Smx205022 static int
23365574Smx205022 nge_resume(dev_info_t *devinfo)
23375574Smx205022 {
23385574Smx205022 	nge_t		*ngep;
23395574Smx205022 	chip_info_t	*infop;
23405869Smx205022 	int 		err;
23415574Smx205022 
23425574Smx205022 	ASSERT(devinfo != NULL);
23435574Smx205022 
23445574Smx205022 	ngep = ddi_get_driver_private(devinfo);
23455869Smx205022 	err = 0;
23465869Smx205022 
23475574Smx205022 	/*
23485574Smx205022 	 * If there are state inconsistancies, this is bad.  Returning
23495574Smx205022 	 * DDI_FAILURE here will eventually cause the machine to panic,
23505574Smx205022 	 * so it is best done here so that there is a possibility of
23515574Smx205022 	 * debugging the problem.
23525574Smx205022 	 */
23535574Smx205022 	if (ngep == NULL)
23545574Smx205022 		cmn_err(CE_PANIC,
23555574Smx205022 		    "nge: ngep returned from ddi_get_driver_private was NULL");
23565574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
23575574Smx205022 
23585574Smx205022 	if (ngep->devinfo != devinfo)
23595574Smx205022 		cmn_err(CE_PANIC,
23605869Smx205022 		    "nge: passed devinfo not the same as saved devinfo");
23615574Smx205022 
23625869Smx205022 	mutex_enter(ngep->genlock);
23635869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
23645574Smx205022 
23655574Smx205022 	/*
23665574Smx205022 	 * Fetch the config space.  Even though we have most of it cached,
23675574Smx205022 	 * some values *might* change across a suspend/resume.
23685574Smx205022 	 */
23695574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
23705574Smx205022 
23715574Smx205022 	/*
23725869Smx205022 	 * Only in one case, this conditional branch can be executed: the port
23735869Smx205022 	 * hasn't been plumbed.
23745574Smx205022 	 */
23755869Smx205022 	if (ngep->suspended == B_FALSE) {
23765869Smx205022 		rw_exit(ngep->rwlock);
23775869Smx205022 		mutex_exit(ngep->genlock);
23785869Smx205022 		return (DDI_SUCCESS);
23795869Smx205022 	}
23805869Smx205022 
23815869Smx205022 	nge_tx_recycle_all(ngep);
23825869Smx205022 	err = nge_reinit_ring(ngep);
23835869Smx205022 	if (!err) {
23845869Smx205022 		err = nge_chip_reset(ngep);
23855869Smx205022 		if (!err)
23865869Smx205022 			err = nge_chip_start(ngep);
23875869Smx205022 	}
23885869Smx205022 
23895869Smx205022 	if (err) {
23905574Smx205022 		/*
23915574Smx205022 		 * We note the failure, but return success, as the
23925574Smx205022 		 * system is still usable without this controller.
23935574Smx205022 		 */
23945574Smx205022 		cmn_err(CE_WARN, "nge: resume: failed to restart controller");
23955869Smx205022 	} else {
23965869Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
23975574Smx205022 	}
23985869Smx205022 	ngep->suspended = B_FALSE;
23995869Smx205022 
24005869Smx205022 	rw_exit(ngep->rwlock);
24015869Smx205022 	mutex_exit(ngep->genlock);
24025869Smx205022 
24035574Smx205022 	return (DDI_SUCCESS);
24045574Smx205022 }
24055574Smx205022 
24065574Smx205022 /*
24075574Smx205022  * attach(9E) -- Attach a device to the system
24085574Smx205022  *
24095574Smx205022  * Called once for each board successfully probed.
24105574Smx205022  */
24115574Smx205022 static int
24125574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
24135574Smx205022 {
24145574Smx205022 	int		err;
24155574Smx205022 	int		i;
24165574Smx205022 	int		instance;
24175574Smx205022 	caddr_t		regs;
24185574Smx205022 	nge_t		*ngep;
24195574Smx205022 	chip_info_t	*infop;
24205574Smx205022 	mac_register_t	*macp;
24215574Smx205022 
24225574Smx205022 	switch (cmd) {
24235574Smx205022 	default:
24245574Smx205022 		return (DDI_FAILURE);
24255574Smx205022 
24265574Smx205022 	case DDI_RESUME:
24275574Smx205022 		return (nge_resume(devinfo));
24285574Smx205022 
24295574Smx205022 	case DDI_ATTACH:
24305574Smx205022 		break;
24315574Smx205022 	}
24325574Smx205022 
24335574Smx205022 	ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
24345574Smx205022 	instance = ddi_get_instance(devinfo);
24355574Smx205022 	ddi_set_driver_private(devinfo, ngep);
24365574Smx205022 	ngep->devinfo = devinfo;
24375574Smx205022 
24385574Smx205022 	(void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
24395574Smx205022 	    NGE_DRIVER_NAME, instance);
24405574Smx205022 	err = pci_config_setup(devinfo, &ngep->cfg_handle);
24415574Smx205022 	if (err != DDI_SUCCESS) {
24425574Smx205022 		nge_problem(ngep, "nge_attach: pci_config_setup() failed");
24435574Smx205022 		goto attach_fail;
24445574Smx205022 	}
24456512Ssowmini 	/*
24466512Ssowmini 	 * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy
24476512Ssowmini 	 * thresholds. Bounds: min 0, max NGE_MAX_SDU
24486512Ssowmini 	 */
24496512Ssowmini 	ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE;
24506512Ssowmini 	ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE;
24516512Ssowmini 
24526512Ssowmini 	/*
24536512Ssowmini 	 * param_recv_max_packet is max packet received per interupt.
24546512Ssowmini 	 * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024
24556512Ssowmini 	 */
24566512Ssowmini 	ngep->param_recv_max_packet = 128;
24576512Ssowmini 
24586512Ssowmini 	/*
24596512Ssowmini 	 * param_poll_quiet_time and param_poll_busy_time are quiet/busy time
24606512Ssowmini 	 * switch from per packet interrupt to polling interrupt.
24616512Ssowmini 	 * Bounds: min 0, max 10000
24626512Ssowmini 	 */
24636512Ssowmini 	ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
24646512Ssowmini 	ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
24656512Ssowmini 
24666512Ssowmini 	/*
24676512Ssowmini 	 * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
24686512Ssowmini 	 * to trigger the poll_quiet_time/poll_busy_time counter.
24696512Ssowmini 	 * Bounds: min 0, max  NGE_RECV_SLOTS_DESC_1024.
24706512Ssowmini 	 */
24716512Ssowmini 	ngep->param_rx_intr_hwater = 1;
24726512Ssowmini 	ngep->param_rx_intr_lwater = 8;
24736512Ssowmini 
24746512Ssowmini 	/*
24756512Ssowmini 	 * param_tx_n_intr: Per N tx packets to do tx recycle in poll mode.
24766512Ssowmini 	 * Bounds: min 1, max 10000.
24776512Ssowmini 	 */
24786512Ssowmini 	ngep->param_tx_n_intr = NGE_TX_N_INTR;
24796512Ssowmini 
24805574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
24815574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
24825574Smx205022 	nge_init_dev_spec_param(ngep);
24835574Smx205022 	nge_get_props(ngep);
24845574Smx205022 	ngep->progress |= PROGRESS_CFG;
24855574Smx205022 
24865574Smx205022 	err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
24875574Smx205022 	    &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
24885574Smx205022 	if (err != DDI_SUCCESS) {
24895574Smx205022 		nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
24905574Smx205022 		goto attach_fail;
24915574Smx205022 	}
24925574Smx205022 	ngep->io_regs = regs;
24935574Smx205022 	ngep->progress |= PROGRESS_REGS;
24945574Smx205022 
24955574Smx205022 	err = nge_register_intrs_and_init_locks(ngep);
24965574Smx205022 	if (err != DDI_SUCCESS) {
24975574Smx205022 		nge_problem(ngep, "nge_attach:"
24985574Smx205022 		    " register intrs and init locks failed");
24995574Smx205022 		goto attach_fail;
25005574Smx205022 	}
25015574Smx205022 	nge_init_ring_param_lock(ngep);
25025574Smx205022 	ngep->progress |= PROGRESS_INTR;
25035574Smx205022 
25045574Smx205022 	mutex_enter(ngep->genlock);
25055574Smx205022 
2506*9604SZhen.W@Sun.COM 	if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
2507*9604SZhen.W@Sun.COM 	    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
2508*9604SZhen.W@Sun.COM 		err = nge_smu_sema(ngep, B_TRUE);
2509*9604SZhen.W@Sun.COM 		if (err != DDI_SUCCESS) {
2510*9604SZhen.W@Sun.COM 			nge_problem(ngep, "nge_attach: nge_smu_sema() failed");
2511*9604SZhen.W@Sun.COM 			goto attach_fail;
2512*9604SZhen.W@Sun.COM 		}
2513*9604SZhen.W@Sun.COM 	}
25145574Smx205022 	/*
25155574Smx205022 	 * Initialise link state variables
25165574Smx205022 	 * Stop, reset & reinitialise the chip.
25175574Smx205022 	 * Initialise the (internal) PHY.
25185574Smx205022 	 */
25195574Smx205022 	nge_phys_init(ngep);
25208218SMin.Xu@Sun.COM 	ngep->nge_chip_state = NGE_CHIP_INITIAL;
25215574Smx205022 	err = nge_chip_reset(ngep);
25225574Smx205022 	if (err != DDI_SUCCESS) {
25235574Smx205022 		nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
25245574Smx205022 		mutex_exit(ngep->genlock);
25255574Smx205022 		goto attach_fail;
25265574Smx205022 	}
25275574Smx205022 	nge_chip_sync(ngep);
25285574Smx205022 
25295574Smx205022 	/*
25305574Smx205022 	 * Now that mutex locks are initialized, enable interrupts.
25315574Smx205022 	 */
25325574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
25335574Smx205022 		/* Call ddi_intr_block_enable() for MSI interrupts */
25345574Smx205022 		(void) ddi_intr_block_enable(ngep->htable,
25355574Smx205022 		    ngep->intr_actual_cnt);
25365574Smx205022 	} else {
25375574Smx205022 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
25385574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
25395574Smx205022 			(void) ddi_intr_enable(ngep->htable[i]);
25405574Smx205022 		}
25415574Smx205022 	}
25425574Smx205022 
25435574Smx205022 	ngep->link_state = LINK_STATE_UNKNOWN;
25445574Smx205022 	ngep->progress |= PROGRESS_HWINT;
25455574Smx205022 
25465574Smx205022 	/*
25475574Smx205022 	 * Register NDD-tweakable parameters
25485574Smx205022 	 */
25495574Smx205022 	if (nge_nd_init(ngep)) {
25505574Smx205022 		nge_problem(ngep, "nge_attach: nge_nd_init() failed");
25515574Smx205022 		mutex_exit(ngep->genlock);
25525574Smx205022 		goto attach_fail;
25535574Smx205022 	}
25545574Smx205022 	ngep->progress |= PROGRESS_NDD;
25555574Smx205022 
25565574Smx205022 	/*
25575574Smx205022 	 * Create & initialise named kstats
25585574Smx205022 	 */
25595574Smx205022 	nge_init_kstats(ngep, instance);
25605574Smx205022 	ngep->progress |= PROGRESS_KSTATS;
25615574Smx205022 
25625574Smx205022 	mutex_exit(ngep->genlock);
25635574Smx205022 
25645574Smx205022 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
25655574Smx205022 		goto attach_fail;
25665574Smx205022 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
25675574Smx205022 	macp->m_driver = ngep;
25685574Smx205022 	macp->m_dip = devinfo;
25695574Smx205022 	macp->m_src_addr = infop->vendor_addr.addr;
25705574Smx205022 	macp->m_callbacks = &nge_m_callbacks;
25715574Smx205022 	macp->m_min_sdu = 0;
25725574Smx205022 	macp->m_max_sdu = ngep->default_mtu;
25735895Syz147064 	macp->m_margin = VTAG_SIZE;
25746512Ssowmini 	macp->m_priv_props = nge_priv_props;
25756512Ssowmini 	macp->m_priv_prop_count = NGE_MAX_PRIV_PROPS;
25765574Smx205022 	/*
25775574Smx205022 	 * Finally, we're ready to register ourselves with the mac
25785574Smx205022 	 * interface; if this succeeds, we're all ready to start()
25795574Smx205022 	 */
25805574Smx205022 	err = mac_register(macp, &ngep->mh);
25815574Smx205022 	mac_free(macp);
25825574Smx205022 	if (err != 0)
25835574Smx205022 		goto attach_fail;
25845574Smx205022 
25855574Smx205022 	/*
25865574Smx205022 	 * Register a periodical handler.
25875574Smx205022 	 * nge_chip_cyclic() is invoked in kernel context.
25885574Smx205022 	 */
25895574Smx205022 	ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
25905574Smx205022 	    NGE_CYCLIC_PERIOD, DDI_IPL_0);
25915574Smx205022 
25925574Smx205022 	ngep->progress |= PROGRESS_READY;
25935574Smx205022 	return (DDI_SUCCESS);
25945574Smx205022 
25955574Smx205022 attach_fail:
25965574Smx205022 	nge_unattach(ngep);
25975574Smx205022 	return (DDI_FAILURE);
25985574Smx205022 }
25995574Smx205022 
26005869Smx205022 static int
26015869Smx205022 nge_suspend(nge_t *ngep)
26025869Smx205022 {
26035869Smx205022 	mutex_enter(ngep->genlock);
26045869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
26055869Smx205022 
26065869Smx205022 	/* if the port hasn't been plumbed, just return */
26075869Smx205022 	if (ngep->nge_mac_state != NGE_MAC_STARTED) {
26085869Smx205022 		rw_exit(ngep->rwlock);
26095869Smx205022 		mutex_exit(ngep->genlock);
26105869Smx205022 		return (DDI_SUCCESS);
26115869Smx205022 	}
26125869Smx205022 	ngep->suspended = B_TRUE;
26135869Smx205022 	(void) nge_chip_stop(ngep, B_FALSE);
26145869Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
26155869Smx205022 
26165869Smx205022 	rw_exit(ngep->rwlock);
26175869Smx205022 	mutex_exit(ngep->genlock);
26185869Smx205022 	return (DDI_SUCCESS);
26195869Smx205022 }
26205869Smx205022 
26215574Smx205022 /*
26225574Smx205022  * detach(9E) -- Detach a device from the system
26235574Smx205022  */
26245574Smx205022 static int
26255574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
26265574Smx205022 {
26275574Smx205022 	int i;
26285574Smx205022 	nge_t *ngep;
26295574Smx205022 	mul_item *p, *nextp;
26305574Smx205022 	buff_ring_t *brp;
26315574Smx205022 
26325574Smx205022 	NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
26335574Smx205022 
26345574Smx205022 	ngep = ddi_get_driver_private(devinfo);
26355574Smx205022 	brp = ngep->buff;
26365574Smx205022 
26375574Smx205022 	switch (cmd) {
26385574Smx205022 	default:
26395574Smx205022 		return (DDI_FAILURE);
26405574Smx205022 
26415574Smx205022 	case DDI_SUSPEND:
26425574Smx205022 		/*
26435574Smx205022 		 * Stop the NIC
26445574Smx205022 		 * Note: This driver doesn't currently support WOL, but
26455574Smx205022 		 *	should it in the future, it is important to
26465574Smx205022 		 *	make sure the PHY remains powered so that the
26475574Smx205022 		 *	wakeup packet can actually be recieved.
26485574Smx205022 		 */
26495869Smx205022 		return (nge_suspend(ngep));
26505574Smx205022 
26515574Smx205022 	case DDI_DETACH:
26525574Smx205022 		break;
26535574Smx205022 	}
26545574Smx205022 
26555574Smx205022 	/* Try to wait all the buffer post to upper layer be released */
26565574Smx205022 	for (i = 0; i < 1000; i++) {
26575574Smx205022 		if (brp->rx_hold == 0)
26585574Smx205022 			break;
26595574Smx205022 		drv_usecwait(1000);
26605574Smx205022 	}
26615574Smx205022 
26625574Smx205022 	/* If there is any posted buffer, reject to detach */
26635574Smx205022 	if (brp->rx_hold != 0)
26645574Smx205022 		return (DDI_FAILURE);
26655574Smx205022 
26665574Smx205022 	/*
26675574Smx205022 	 * Unregister from the GLD subsystem.  This can fail, in
26685574Smx205022 	 * particular if there are DLPI style-2 streams still open -
26695574Smx205022 	 * in which case we just return failure without shutting
26705574Smx205022 	 * down chip operations.
26715574Smx205022 	 */
26725574Smx205022 	if (mac_unregister(ngep->mh) != DDI_SUCCESS)
26735574Smx205022 		return (DDI_FAILURE);
26745574Smx205022 
26755574Smx205022 	/*
26766366Smx205022 	 * Recycle the multicast table. mac_unregister() should be called
26776366Smx205022 	 * before it to ensure the multicast table can be used even if
26786366Smx205022 	 * mac_unregister() fails.
26796366Smx205022 	 */
26806366Smx205022 	for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
26816366Smx205022 		nextp = p->next;
26826366Smx205022 		kmem_free(p, sizeof (mul_item));
26836366Smx205022 	}
26846366Smx205022 	ngep->pcur_mulist = NULL;
26856366Smx205022 
26866366Smx205022 	/*
26875574Smx205022 	 * All activity stopped, so we can clean up & exit
26885574Smx205022 	 */
26895574Smx205022 	nge_unattach(ngep);
26905574Smx205022 	return (DDI_SUCCESS);
26915574Smx205022 }
26925574Smx205022 
26937656SSherry.Moore@Sun.COM /*
26947656SSherry.Moore@Sun.COM  * quiesce(9E) entry point.
26957656SSherry.Moore@Sun.COM  *
26967656SSherry.Moore@Sun.COM  * This function is called when the system is single-threaded at high
26977656SSherry.Moore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
26987656SSherry.Moore@Sun.COM  * blocked.
26997656SSherry.Moore@Sun.COM  *
27007656SSherry.Moore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
27017656SSherry.Moore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
27027656SSherry.Moore@Sun.COM  */
27037656SSherry.Moore@Sun.COM static int
27047656SSherry.Moore@Sun.COM nge_quiesce(dev_info_t *devinfo)
27057656SSherry.Moore@Sun.COM {
27067656SSherry.Moore@Sun.COM 	nge_t *ngep;
27077656SSherry.Moore@Sun.COM 
27087656SSherry.Moore@Sun.COM 	ngep = ddi_get_driver_private(devinfo);
27097656SSherry.Moore@Sun.COM 
27107656SSherry.Moore@Sun.COM 	if (ngep == NULL)
27117656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
27127656SSherry.Moore@Sun.COM 
27137656SSherry.Moore@Sun.COM 	/*
27147656SSherry.Moore@Sun.COM 	 * Turn off debug tracing
27157656SSherry.Moore@Sun.COM 	 */
27167656SSherry.Moore@Sun.COM 	nge_debug = 0;
27177656SSherry.Moore@Sun.COM 	ngep->debug = 0;
27187656SSherry.Moore@Sun.COM 
27197656SSherry.Moore@Sun.COM 	nge_restore_mac_addr(ngep);
27207656SSherry.Moore@Sun.COM 	(void) nge_chip_stop(ngep, B_FALSE);
27217656SSherry.Moore@Sun.COM 
27227656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
27237656SSherry.Moore@Sun.COM }
27247656SSherry.Moore@Sun.COM 
27257656SSherry.Moore@Sun.COM 
27265574Smx205022 
27275574Smx205022 /*
27285574Smx205022  * ========== Module Loading Data & Entry Points ==========
27295574Smx205022  */
27305574Smx205022 
27315574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
27327656SSherry.Moore@Sun.COM     NULL, NULL, D_MP, NULL, nge_quiesce);
27335574Smx205022 
27345574Smx205022 
27355574Smx205022 static struct modldrv nge_modldrv = {
27365574Smx205022 	&mod_driverops,		/* Type of module.  This one is a driver */
27375574Smx205022 	nge_ident,		/* short description */
27385574Smx205022 	&nge_dev_ops		/* driver specific ops */
27395574Smx205022 };
27405574Smx205022 
27415574Smx205022 static struct modlinkage modlinkage = {
27425574Smx205022 	MODREV_1, (void *)&nge_modldrv, NULL
27435574Smx205022 };
27445574Smx205022 
27455574Smx205022 
27465574Smx205022 int
27475574Smx205022 _info(struct modinfo *modinfop)
27485574Smx205022 {
27495574Smx205022 	return (mod_info(&modlinkage, modinfop));
27505574Smx205022 }
27515574Smx205022 
27525574Smx205022 int
27535574Smx205022 _init(void)
27545574Smx205022 {
27555574Smx205022 	int status;
27565574Smx205022 
27575574Smx205022 	mac_init_ops(&nge_dev_ops, "nge");
27585574Smx205022 	status = mod_install(&modlinkage);
27595574Smx205022 	if (status != DDI_SUCCESS)
27605574Smx205022 		mac_fini_ops(&nge_dev_ops);
27615574Smx205022 	else
27625574Smx205022 		mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
27635574Smx205022 
27645574Smx205022 	return (status);
27655574Smx205022 }
27665574Smx205022 
27675574Smx205022 int
27685574Smx205022 _fini(void)
27695574Smx205022 {
27705574Smx205022 	int status;
27715574Smx205022 
27725574Smx205022 	status = mod_remove(&modlinkage);
27735574Smx205022 	if (status == DDI_SUCCESS) {
27745574Smx205022 		mac_fini_ops(&nge_dev_ops);
27755574Smx205022 		mutex_destroy(nge_log_mutex);
27765574Smx205022 	}
27775574Smx205022 
27785574Smx205022 	return (status);
27795574Smx205022 }
27805574Smx205022 
27815574Smx205022 /*
27825574Smx205022  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
27835574Smx205022  */
27845574Smx205022 
27855574Smx205022 /*
27865574Smx205022  * Register interrupts and initialize each mutex and condition variables
27875574Smx205022  */
27885574Smx205022 
27895574Smx205022 static int
27905574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep)
27915574Smx205022 {
27925574Smx205022 	int		err;
27935574Smx205022 	int		intr_types;
27945574Smx205022 	uint_t		soft_prip;
27955574Smx205022 	nge_msi_mask	msi_mask;
27965574Smx205022 	nge_msi_map0_vec map0_vec;
27975574Smx205022 	nge_msi_map1_vec map1_vec;
27985574Smx205022 
27995574Smx205022 	/*
28005574Smx205022 	 * Add the softint handlers:
28015574Smx205022 	 *
28025574Smx205022 	 * Both of these handlers are used to avoid restrictions on the
28035574Smx205022 	 * context and/or mutexes required for some operations.  In
28045574Smx205022 	 * particular, the hardware interrupt handler and its subfunctions
28055574Smx205022 	 * can detect a number of conditions that we don't want to handle
28065574Smx205022 	 * in that context or with that set of mutexes held.  So, these
28075574Smx205022 	 * softints are triggered instead:
28085574Smx205022 	 *
28095574Smx205022 	 * the <resched> softint is triggered if if we have previously
28105574Smx205022 	 * had to refuse to send a packet because of resource shortage
28115574Smx205022 	 * (we've run out of transmit buffers), but the send completion
28125574Smx205022 	 * interrupt handler has now detected that more buffers have
28135574Smx205022 	 * become available.  Its only purpose is to call gld_sched()
28145574Smx205022 	 * to retry the pending transmits (we're not allowed to hold
28155574Smx205022 	 * driver-defined mutexes across gld_sched()).
28165574Smx205022 	 *
28175574Smx205022 	 * the <factotum> is triggered if the h/w interrupt handler
28185574Smx205022 	 * sees the <link state changed> or <error> bits in the status
28195574Smx205022 	 * block.  It's also triggered periodically to poll the link
28205574Smx205022 	 * state, just in case we aren't getting link status change
28215574Smx205022 	 * interrupts ...
28225574Smx205022 	 */
28235574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
28245574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
28255574Smx205022 	if (err != DDI_SUCCESS) {
28265574Smx205022 		nge_problem(ngep,
28275574Smx205022 		    "nge_attach: add nge_reschedule softintr failed");
28285574Smx205022 
28295574Smx205022 		return (DDI_FAILURE);
28305574Smx205022 	}
28315574Smx205022 	ngep->progress |= PROGRESS_RESCHED;
28325574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
28335574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
28345574Smx205022 	if (err != DDI_SUCCESS) {
28355574Smx205022 		nge_problem(ngep,
28365574Smx205022 		    "nge_attach: add nge_chip_factotum softintr failed!");
28375574Smx205022 
28385574Smx205022 		return (DDI_FAILURE);
28395574Smx205022 	}
28405574Smx205022 	if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
28415574Smx205022 	    != DDI_SUCCESS) {
28425574Smx205022 		nge_problem(ngep, "nge_attach: get softintr priority failed\n");
28435574Smx205022 
28445574Smx205022 		return (DDI_FAILURE);
28455574Smx205022 	}
28465574Smx205022 	ngep->soft_pri = soft_prip;
28475574Smx205022 
28485574Smx205022 	ngep->progress |= PROGRESS_FACTOTUM;
28495574Smx205022 	/* Get supported interrupt types */
28505574Smx205022 	if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
28515574Smx205022 	    != DDI_SUCCESS) {
28525574Smx205022 		nge_error(ngep, "ddi_intr_get_supported_types failed\n");
28535574Smx205022 
28545574Smx205022 		return (DDI_FAILURE);
28555574Smx205022 	}
28565574Smx205022 
28575574Smx205022 	NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
28585574Smx205022 	    intr_types));
28595574Smx205022 
28605574Smx205022 	if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
28615574Smx205022 
28625574Smx205022 		/* MSI Configurations for mcp55 chipset */
28635574Smx205022 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
28645574Smx205022 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
28655574Smx205022 
28665574Smx205022 
28675574Smx205022 			/* Enable the 8 vectors */
28685574Smx205022 			msi_mask.msi_mask_val =
28695574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MASK);
28705574Smx205022 			msi_mask.msi_msk_bits.vec0 = NGE_SET;
28715574Smx205022 			msi_mask.msi_msk_bits.vec1 = NGE_SET;
28725574Smx205022 			msi_mask.msi_msk_bits.vec2 = NGE_SET;
28735574Smx205022 			msi_mask.msi_msk_bits.vec3 = NGE_SET;
28745574Smx205022 			msi_mask.msi_msk_bits.vec4 = NGE_SET;
28755574Smx205022 			msi_mask.msi_msk_bits.vec5 = NGE_SET;
28765574Smx205022 			msi_mask.msi_msk_bits.vec6 = NGE_SET;
28775574Smx205022 			msi_mask.msi_msk_bits.vec7 = NGE_SET;
28785574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MASK,
28795574Smx205022 			    msi_mask.msi_mask_val);
28805574Smx205022 
28815574Smx205022 			/*
28825574Smx205022 			 * Remapping the MSI MAP0 and MAP1. MCP55
28835574Smx205022 			 * is default mapping all the interrupt to 0 vector.
28845574Smx205022 			 * Software needs to remapping this.
28855574Smx205022 			 * This mapping is same as CK804.
28865574Smx205022 			 */
28875574Smx205022 			map0_vec.msi_map0_val =
28885574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP0);
28895574Smx205022 			map1_vec.msi_map1_val =
28905574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP1);
28915574Smx205022 			map0_vec.vecs_bits.reint_vec = 0;
28925574Smx205022 			map0_vec.vecs_bits.rcint_vec = 0;
28935574Smx205022 			map0_vec.vecs_bits.miss_vec = 3;
28945574Smx205022 			map0_vec.vecs_bits.teint_vec = 5;
28955574Smx205022 			map0_vec.vecs_bits.tcint_vec = 5;
28965574Smx205022 			map0_vec.vecs_bits.stint_vec = 2;
28975574Smx205022 			map0_vec.vecs_bits.mint_vec = 6;
28985574Smx205022 			map0_vec.vecs_bits.rfint_vec = 0;
28995574Smx205022 			map1_vec.vecs_bits.tfint_vec = 5;
29005574Smx205022 			map1_vec.vecs_bits.feint_vec = 6;
29015574Smx205022 			map1_vec.vecs_bits.resv8_11 = 3;
29025574Smx205022 			map1_vec.vecs_bits.resv12_15 = 1;
29035574Smx205022 			map1_vec.vecs_bits.resv16_19 = 0;
29045574Smx205022 			map1_vec.vecs_bits.resv20_23 = 7;
29055574Smx205022 			map1_vec.vecs_bits.resv24_31 = 0xff;
29065574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP0,
29075574Smx205022 			    map0_vec.msi_map0_val);
29085574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP1,
29095574Smx205022 			    map1_vec.msi_map1_val);
29105574Smx205022 		}
29115574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
29125574Smx205022 			NGE_DEBUG(("MSI registration failed, "
29135574Smx205022 			    "trying FIXED interrupt type\n"));
29145574Smx205022 		} else {
29155574Smx205022 			nge_log(ngep, "Using MSI interrupt type\n");
29165574Smx205022 
29175574Smx205022 			ngep->intr_type = DDI_INTR_TYPE_MSI;
29185574Smx205022 			ngep->progress |= PROGRESS_SWINT;
29195574Smx205022 		}
29205574Smx205022 	}
29215574Smx205022 
29225574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT) &&
29235574Smx205022 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
29245574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
29255574Smx205022 			nge_error(ngep, "FIXED interrupt "
29265574Smx205022 			    "registration failed\n");
29275574Smx205022 
29285574Smx205022 			return (DDI_FAILURE);
29295574Smx205022 		}
29305574Smx205022 
29315574Smx205022 		nge_log(ngep, "Using FIXED interrupt type\n");
29325574Smx205022 
29335574Smx205022 		ngep->intr_type = DDI_INTR_TYPE_FIXED;
29345574Smx205022 		ngep->progress |= PROGRESS_SWINT;
29355574Smx205022 	}
29365574Smx205022 
29375574Smx205022 
29385574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT)) {
29395574Smx205022 		nge_error(ngep, "No interrupts registered\n");
29405574Smx205022 
29415574Smx205022 		return (DDI_FAILURE);
29425574Smx205022 	}
29435574Smx205022 	mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
29445574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29455574Smx205022 	mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
29465574Smx205022 	    DDI_INTR_PRI(ngep->soft_pri));
29475574Smx205022 	rw_init(ngep->rwlock, NULL, RW_DRIVER,
29485574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29495574Smx205022 
29505574Smx205022 	return (DDI_SUCCESS);
29515574Smx205022 }
29525574Smx205022 
29535574Smx205022 /*
29545574Smx205022  * nge_add_intrs:
29555574Smx205022  *
29565574Smx205022  * Register FIXED or MSI interrupts.
29575574Smx205022  */
29585574Smx205022 static int
29595574Smx205022 nge_add_intrs(nge_t *ngep, int	intr_type)
29605574Smx205022 {
29615574Smx205022 	dev_info_t	*dip = ngep->devinfo;
29625574Smx205022 	int		avail, actual, intr_size, count = 0;
29635574Smx205022 	int		i, flag, ret;
29645574Smx205022 
29655574Smx205022 	NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
29665574Smx205022 
29675574Smx205022 	/* Get number of interrupts */
29685574Smx205022 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
29695574Smx205022 	if ((ret != DDI_SUCCESS) || (count == 0)) {
29705574Smx205022 		nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
29715574Smx205022 		    "count: %d", ret, count);
29725574Smx205022 
29735574Smx205022 		return (DDI_FAILURE);
29745574Smx205022 	}
29755574Smx205022 
29765574Smx205022 	/* Get number of available interrupts */
29775574Smx205022 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
29785574Smx205022 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
29795574Smx205022 		nge_error(ngep, "ddi_intr_get_navail() failure, "
29805574Smx205022 		    "ret: %d, avail: %d\n", ret, avail);
29815574Smx205022 
29825574Smx205022 		return (DDI_FAILURE);
29835574Smx205022 	}
29845574Smx205022 
29855574Smx205022 	if (avail < count) {
29865574Smx205022 		NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
29875574Smx205022 		    count, avail));
29885574Smx205022 	}
29895574Smx205022 	flag = DDI_INTR_ALLOC_NORMAL;
29905574Smx205022 
29915574Smx205022 	/* Allocate an array of interrupt handles */
29925574Smx205022 	intr_size = count * sizeof (ddi_intr_handle_t);
29935574Smx205022 	ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
29945574Smx205022 
29955574Smx205022 	/* Call ddi_intr_alloc() */
29965574Smx205022 	ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
29975574Smx205022 	    count, &actual, flag);
29985574Smx205022 
29995574Smx205022 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
30005574Smx205022 		nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
30015574Smx205022 
30025574Smx205022 		kmem_free(ngep->htable, intr_size);
30035574Smx205022 		return (DDI_FAILURE);
30045574Smx205022 	}
30055574Smx205022 
30065574Smx205022 	if (actual < count) {
30075574Smx205022 		NGE_DEBUG(("Requested: %d, Received: %d\n",
30085574Smx205022 		    count, actual));
30095574Smx205022 	}
30105574Smx205022 
30115574Smx205022 	ngep->intr_actual_cnt = actual;
30125574Smx205022 	ngep->intr_req_cnt = count;
30135574Smx205022 
30145574Smx205022 	/*
30155574Smx205022 	 * Get priority for first msi, assume remaining are all the same
30165574Smx205022 	 */
30175574Smx205022 	if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
30185574Smx205022 	    DDI_SUCCESS) {
30195574Smx205022 		nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
30205574Smx205022 
30215574Smx205022 		/* Free already allocated intr */
30225574Smx205022 		for (i = 0; i < actual; i++) {
30235574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
30245574Smx205022 		}
30255574Smx205022 
30265574Smx205022 		kmem_free(ngep->htable, intr_size);
30275574Smx205022 
30285574Smx205022 		return (DDI_FAILURE);
30295574Smx205022 	}
30305574Smx205022 	/* Test for high level mutex */
30315574Smx205022 	if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
30325574Smx205022 		nge_error(ngep, "nge_add_intrs:"
30335574Smx205022 		    "Hi level interrupt not supported");
30345574Smx205022 
30355574Smx205022 		for (i = 0; i < actual; i++)
30365574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
30375574Smx205022 
30385574Smx205022 		kmem_free(ngep->htable, intr_size);
30395574Smx205022 
30405574Smx205022 		return (DDI_FAILURE);
30415574Smx205022 	}
30425574Smx205022 
30435574Smx205022 
30445574Smx205022 	/* Call ddi_intr_add_handler() */
30455574Smx205022 	for (i = 0; i < actual; i++) {
30465574Smx205022 		if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
30475574Smx205022 		    (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
30485574Smx205022 			nge_error(ngep, "ddi_intr_add_handler() "
30495574Smx205022 			    "failed %d\n", ret);
30505574Smx205022 
30515574Smx205022 			/* Free already allocated intr */
30525574Smx205022 			for (i = 0; i < actual; i++) {
30535574Smx205022 				(void) ddi_intr_free(ngep->htable[i]);
30545574Smx205022 			}
30555574Smx205022 
30565574Smx205022 			kmem_free(ngep->htable, intr_size);
30575574Smx205022 
30585574Smx205022 			return (DDI_FAILURE);
30595574Smx205022 		}
30605574Smx205022 	}
30615574Smx205022 
30625574Smx205022 	if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
30635574Smx205022 	    != DDI_SUCCESS) {
30645574Smx205022 		nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
30655574Smx205022 
30665574Smx205022 		for (i = 0; i < actual; i++) {
30675574Smx205022 			(void) ddi_intr_remove_handler(ngep->htable[i]);
30685574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
30695574Smx205022 		}
30705574Smx205022 
30715574Smx205022 		kmem_free(ngep->htable, intr_size);
30725574Smx205022 
30735574Smx205022 		return (DDI_FAILURE);
30745574Smx205022 	}
30755574Smx205022 
30765574Smx205022 	return (DDI_SUCCESS);
30775574Smx205022 }
30785574Smx205022 
30795574Smx205022 /*
30805574Smx205022  * nge_rem_intrs:
30815574Smx205022  *
30825574Smx205022  * Unregister FIXED or MSI interrupts
30835574Smx205022  */
30845574Smx205022 static void
30855574Smx205022 nge_rem_intrs(nge_t *ngep)
30865574Smx205022 {
30875574Smx205022 	int	i;
30885574Smx205022 
30895574Smx205022 	NGE_DEBUG(("nge_rem_intrs\n"));
30905574Smx205022 
30915574Smx205022 	/* Disable all interrupts */
30925574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
30935574Smx205022 		/* Call ddi_intr_block_disable() */
30945574Smx205022 		(void) ddi_intr_block_disable(ngep->htable,
30955574Smx205022 		    ngep->intr_actual_cnt);
30965574Smx205022 	} else {
30975574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
30985574Smx205022 			(void) ddi_intr_disable(ngep->htable[i]);
30995574Smx205022 		}
31005574Smx205022 	}
31015574Smx205022 
31025574Smx205022 	/* Call ddi_intr_remove_handler() */
31035574Smx205022 	for (i = 0; i < ngep->intr_actual_cnt; i++) {
31045574Smx205022 		(void) ddi_intr_remove_handler(ngep->htable[i]);
31055574Smx205022 		(void) ddi_intr_free(ngep->htable[i]);
31065574Smx205022 	}
31075574Smx205022 
31085574Smx205022 	kmem_free(ngep->htable,
31095574Smx205022 	    ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
31105574Smx205022 }
3111