xref: /onnv-gate/usr/src/uts/common/io/nge/nge_main.c (revision 10615:4bb212e117c7)
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";
1685574Smx205022 extern kmutex_t nge_log_mutex[1];
1695574Smx205022 
1705574Smx205022 static int		nge_m_start(void *);
1715574Smx205022 static void		nge_m_stop(void *);
1725574Smx205022 static int		nge_m_promisc(void *, boolean_t);
1735574Smx205022 static int		nge_m_multicst(void *, boolean_t, const uint8_t *);
1745574Smx205022 static int		nge_m_unicst(void *, const uint8_t *);
1755574Smx205022 static void		nge_m_ioctl(void *, queue_t *, mblk_t *);
1765574Smx205022 static boolean_t	nge_m_getcapab(void *, mac_capab_t, void *);
1776200Smx205022 static int		nge_m_setprop(void *, const char *, mac_prop_id_t,
1786200Smx205022 	uint_t, const void *);
1796200Smx205022 static int		nge_m_getprop(void *, const char *, mac_prop_id_t,
1808118SVasumathi.Sundaram@Sun.COM 	uint_t, uint_t, void *, uint_t *);
1816200Smx205022 static int		nge_set_priv_prop(nge_t *, const char *, uint_t,
1826200Smx205022 	const void *);
1836200Smx205022 static int		nge_get_priv_prop(nge_t *, const char *, uint_t,
1846512Ssowmini 	uint_t, void *);
1856200Smx205022 
1866200Smx205022 #define		NGE_M_CALLBACK_FLAGS\
1876200Smx205022 		(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
1885574Smx205022 
1895574Smx205022 static mac_callbacks_t nge_m_callbacks = {
1905574Smx205022 	NGE_M_CALLBACK_FLAGS,
1915574Smx205022 	nge_m_stat,
1925574Smx205022 	nge_m_start,
1935574Smx205022 	nge_m_stop,
1945574Smx205022 	nge_m_promisc,
1955574Smx205022 	nge_m_multicst,
1965574Smx205022 	nge_m_unicst,
1975574Smx205022 	nge_m_tx,
1985574Smx205022 	nge_m_ioctl,
1996200Smx205022 	nge_m_getcapab,
2006200Smx205022 	NULL,
2016200Smx205022 	NULL,
2026200Smx205022 	nge_m_setprop,
2036200Smx205022 	nge_m_getprop
2045574Smx205022 };
2055574Smx205022 
2066512Ssowmini mac_priv_prop_t nge_priv_props[] = {
2076512Ssowmini 	{"_tx_bcopy_threshold", MAC_PROP_PERM_RW},
2086512Ssowmini 	{"_rx_bcopy_threshold", MAC_PROP_PERM_RW},
2096512Ssowmini 	{"_recv_max_packet", MAC_PROP_PERM_RW},
2106512Ssowmini 	{"_poll_quiet_time", MAC_PROP_PERM_RW},
2116512Ssowmini 	{"_poll_busy_time", MAC_PROP_PERM_RW},
2126512Ssowmini 	{"_rx_intr_hwater", MAC_PROP_PERM_RW},
2136512Ssowmini 	{"_rx_intr_lwater", MAC_PROP_PERM_RW},
2146512Ssowmini };
2156512Ssowmini 
2166512Ssowmini #define	NGE_MAX_PRIV_PROPS \
2176512Ssowmini 	(sizeof (nge_priv_props)/sizeof (mac_priv_prop_t))
2186512Ssowmini 
2195574Smx205022 static int nge_add_intrs(nge_t *, int);
2205574Smx205022 static void nge_rem_intrs(nge_t *);
2215574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *);
2225574Smx205022 
2235574Smx205022 /*
2245574Smx205022  * NGE MSI tunable:
2255574Smx205022  */
2265574Smx205022 boolean_t nge_enable_msi = B_FALSE;
2275574Smx205022 
2285574Smx205022 static enum ioc_reply
2295574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
2305574Smx205022 {
2315574Smx205022 	/*
2325574Smx205022 	 * If the mode isn't being changed, there's nothing to do ...
2335574Smx205022 	 */
2345574Smx205022 	if (mode == ngep->param_loop_mode)
2355574Smx205022 		return (IOC_ACK);
2365574Smx205022 
2375574Smx205022 	/*
2385574Smx205022 	 * Validate the requested mode and prepare a suitable message
2395574Smx205022 	 * to explain the link down/up cycle that the change will
2405574Smx205022 	 * probably induce ...
2415574Smx205022 	 */
2425574Smx205022 	switch (mode) {
2435574Smx205022 	default:
2445574Smx205022 		return (IOC_INVAL);
2455574Smx205022 
2465574Smx205022 	case NGE_LOOP_NONE:
2475574Smx205022 	case NGE_LOOP_EXTERNAL_100:
2485574Smx205022 	case NGE_LOOP_EXTERNAL_10:
2495574Smx205022 	case NGE_LOOP_INTERNAL_PHY:
2505574Smx205022 		break;
2515574Smx205022 	}
2525574Smx205022 
2535574Smx205022 	/*
2545574Smx205022 	 * All OK; tell the caller to reprogram
2555574Smx205022 	 * the PHY and/or MAC for the new mode ...
2565574Smx205022 	 */
2575574Smx205022 	ngep->param_loop_mode = mode;
2585574Smx205022 	return (IOC_RESTART_ACK);
2595574Smx205022 }
2605574Smx205022 
2615574Smx205022 #undef	NGE_DBG
2625574Smx205022 #define	NGE_DBG		NGE_DBG_INIT
2635574Smx205022 
2645574Smx205022 /*
2655574Smx205022  * Utility routine to carve a slice off a chunk of allocated memory,
2665574Smx205022  * updating the chunk descriptor accordingly.  The size of the slice
2675574Smx205022  * is given by the product of the <qty> and <size> parameters.
2685574Smx205022  */
2695574Smx205022 void
2705574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
2715574Smx205022     uint32_t qty, uint32_t size)
2725574Smx205022 {
2735574Smx205022 	size_t totsize;
2745574Smx205022 
2755574Smx205022 	totsize = qty*size;
2765574Smx205022 	ASSERT(size > 0);
2775574Smx205022 	ASSERT(totsize <= chunk->alength);
2785574Smx205022 
2795574Smx205022 	*slice = *chunk;
2805574Smx205022 	slice->nslots = qty;
2815574Smx205022 	slice->size = size;
2825574Smx205022 	slice->alength = totsize;
2835574Smx205022 
2845574Smx205022 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
2855574Smx205022 	chunk->alength -= totsize;
2865574Smx205022 	chunk->offset += totsize;
2875574Smx205022 	chunk->cookie.dmac_laddress += totsize;
2885574Smx205022 	chunk->cookie.dmac_size -= totsize;
2895574Smx205022 }
2905574Smx205022 
2915574Smx205022 /*
2925574Smx205022  * Allocate an area of memory and a DMA handle for accessing it
2935574Smx205022  */
2945574Smx205022 int
2955574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
2965574Smx205022     uint_t dma_flags, dma_area_t *dma_p)
2975574Smx205022 {
2985574Smx205022 	int err;
2995574Smx205022 	caddr_t va;
3005574Smx205022 
3015574Smx205022 	NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
3025574Smx205022 	    (void *)ngep, memsize, attr_p, dma_flags, dma_p));
3035574Smx205022 	/*
3045574Smx205022 	 * Allocate handle
3055574Smx205022 	 */
3065574Smx205022 	err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
3075574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
3085574Smx205022 	if (err != DDI_SUCCESS)
3095574Smx205022 		goto fail;
3105574Smx205022 
3115574Smx205022 	/*
3125574Smx205022 	 * Allocate memory
3135574Smx205022 	 */
3145574Smx205022 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
3155574Smx205022 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
3165574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
3175574Smx205022 	if (err != DDI_SUCCESS)
3185574Smx205022 		goto fail;
3195574Smx205022 
3205574Smx205022 	/*
3215574Smx205022 	 * Bind the two together
3225574Smx205022 	 */
3235574Smx205022 	dma_p->mem_va = va;
3245574Smx205022 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
3255574Smx205022 	    va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
3265574Smx205022 	    &dma_p->cookie, &dma_p->ncookies);
3275574Smx205022 
3285574Smx205022 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
3295574Smx205022 		goto fail;
3305574Smx205022 
3315574Smx205022 	dma_p->nslots = ~0U;
3325574Smx205022 	dma_p->size = ~0U;
3335574Smx205022 	dma_p->offset = 0;
3345574Smx205022 
3355574Smx205022 	return (DDI_SUCCESS);
3365574Smx205022 
3375574Smx205022 fail:
3385574Smx205022 	nge_free_dma_mem(dma_p);
3395574Smx205022 	NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
3405574Smx205022 
3415574Smx205022 	return (DDI_FAILURE);
3425574Smx205022 }
3435574Smx205022 
3445574Smx205022 /*
3455574Smx205022  * Free one allocated area of DMAable memory
3465574Smx205022  */
3475574Smx205022 void
3485574Smx205022 nge_free_dma_mem(dma_area_t *dma_p)
3495574Smx205022 {
3505574Smx205022 	if (dma_p->dma_hdl != NULL) {
3515574Smx205022 		if (dma_p->ncookies) {
3525574Smx205022 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
3535574Smx205022 			dma_p->ncookies = 0;
3545574Smx205022 		}
3555574Smx205022 	}
3565574Smx205022 	if (dma_p->acc_hdl != NULL) {
3575574Smx205022 		ddi_dma_mem_free(&dma_p->acc_hdl);
3585574Smx205022 		dma_p->acc_hdl = NULL;
3595574Smx205022 	}
3605574Smx205022 	if (dma_p->dma_hdl != NULL) {
3615574Smx205022 		ddi_dma_free_handle(&dma_p->dma_hdl);
3625574Smx205022 		dma_p->dma_hdl = NULL;
3635574Smx205022 	}
3645574Smx205022 }
3655574Smx205022 
3665574Smx205022 #define	ALLOC_TX_BUF	0x1
3675574Smx205022 #define	ALLOC_TX_DESC	0x2
3685574Smx205022 #define	ALLOC_RX_DESC	0x4
3695574Smx205022 
3705574Smx205022 int
3715574Smx205022 nge_alloc_bufs(nge_t *ngep)
3725574Smx205022 {
3735574Smx205022 	int err;
3745574Smx205022 	int split;
3755574Smx205022 	int progress;
3765574Smx205022 	size_t txbuffsize;
3775574Smx205022 	size_t rxdescsize;
3785574Smx205022 	size_t txdescsize;
3795574Smx205022 
3805574Smx205022 	txbuffsize = ngep->tx_desc * ngep->buf_size;
3815574Smx205022 	rxdescsize = ngep->rx_desc;
3825574Smx205022 	txdescsize = ngep->tx_desc;
3835574Smx205022 	rxdescsize *= ngep->desc_attr.rxd_size;
3845574Smx205022 	txdescsize *= ngep->desc_attr.txd_size;
3855574Smx205022 	progress = 0;
3865574Smx205022 
3875574Smx205022 	NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
3885574Smx205022 	/*
3895574Smx205022 	 * Allocate memory & handles for TX buffers
3905574Smx205022 	 */
3915574Smx205022 	ASSERT((txbuffsize % ngep->nge_split) == 0);
3925574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
3935574Smx205022 		err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
3945574Smx205022 		    &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
3955574Smx205022 		    &ngep->send->buf[split]);
3965574Smx205022 		if (err != DDI_SUCCESS)
3975574Smx205022 			goto fail;
3985574Smx205022 	}
3995574Smx205022 
4005574Smx205022 	progress |= ALLOC_TX_BUF;
4015574Smx205022 
4025574Smx205022 	/*
4035574Smx205022 	 * Allocate memory & handles for receive return rings and
4045574Smx205022 	 * buffer (producer) descriptor rings
4055574Smx205022 	 */
4065574Smx205022 	err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
4075574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
4085574Smx205022 	if (err != DDI_SUCCESS)
4095574Smx205022 		goto fail;
4105574Smx205022 	progress |= ALLOC_RX_DESC;
4115574Smx205022 
4125574Smx205022 	/*
4135574Smx205022 	 * Allocate memory & handles for TX descriptor rings,
4145574Smx205022 	 */
4155574Smx205022 	err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
4165574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
4175574Smx205022 	if (err != DDI_SUCCESS)
4185574Smx205022 		goto fail;
4195574Smx205022 	return (DDI_SUCCESS);
4205574Smx205022 
4215574Smx205022 fail:
4225574Smx205022 	if (progress & ALLOC_RX_DESC)
4235574Smx205022 		nge_free_dma_mem(&ngep->recv->desc);
4245574Smx205022 	if (progress & ALLOC_TX_BUF) {
4255574Smx205022 		for (split = 0; split < ngep->nge_split; ++split)
4265574Smx205022 			nge_free_dma_mem(&ngep->send->buf[split]);
4275574Smx205022 	}
4285574Smx205022 
4295574Smx205022 	return (DDI_FAILURE);
4305574Smx205022 }
4315574Smx205022 
4325574Smx205022 /*
4335574Smx205022  * This routine frees the transmit and receive buffers and descriptors.
4345574Smx205022  * Make sure the chip is stopped before calling it!
4355574Smx205022  */
4365574Smx205022 void
4375574Smx205022 nge_free_bufs(nge_t *ngep)
4385574Smx205022 {
4395574Smx205022 	int split;
4405574Smx205022 
4415574Smx205022 	NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
4425574Smx205022 
4435574Smx205022 	nge_free_dma_mem(&ngep->recv->desc);
4445574Smx205022 	nge_free_dma_mem(&ngep->send->desc);
4455574Smx205022 
4465574Smx205022 	for (split = 0; split < ngep->nge_split; ++split)
4475574Smx205022 		nge_free_dma_mem(&ngep->send->buf[split]);
4485574Smx205022 }
4495574Smx205022 
4505574Smx205022 /*
4515574Smx205022  * Clean up initialisation done above before the memory is freed
4525574Smx205022  */
4535574Smx205022 static void
4545574Smx205022 nge_fini_send_ring(nge_t *ngep)
4555574Smx205022 {
4565574Smx205022 	uint32_t slot;
4575574Smx205022 	size_t dmah_num;
4585574Smx205022 	send_ring_t *srp;
4595574Smx205022 	sw_tx_sbd_t *ssbdp;
4605574Smx205022 
4615574Smx205022 	srp = ngep->send;
4625574Smx205022 	ssbdp = srp->sw_sbds;
4635574Smx205022 
4645574Smx205022 	NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
4655574Smx205022 
4665574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
4675574Smx205022 
4685574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
4695574Smx205022 		if (srp->dmahndl[slot].hndl) {
4705574Smx205022 			(void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
4715574Smx205022 			ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
4725574Smx205022 			srp->dmahndl[slot].hndl = NULL;
4735574Smx205022 			srp->dmahndl[slot].next = NULL;
4745574Smx205022 		}
4755574Smx205022 	}
4765574Smx205022 
4775574Smx205022 	srp->dmah_free.head = NULL;
4785574Smx205022 	srp->dmah_free.tail = NULL;
4795574Smx205022 
4805574Smx205022 	kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
4815574Smx205022 
4825574Smx205022 }
4835574Smx205022 
4845574Smx205022 /*
4855574Smx205022  * Initialise the specified Send Ring, using the information in the
4865574Smx205022  * <dma_area> descriptors that it contains to set up all the other
4875574Smx205022  * fields. This routine should be called only once for each ring.
4885574Smx205022  */
4895574Smx205022 static int
4905574Smx205022 nge_init_send_ring(nge_t *ngep)
4915574Smx205022 {
4925574Smx205022 	size_t dmah_num;
4935574Smx205022 	uint32_t nslots;
4945574Smx205022 	uint32_t err;
4955574Smx205022 	uint32_t slot;
4965574Smx205022 	uint32_t split;
4975574Smx205022 	send_ring_t *srp;
4985574Smx205022 	sw_tx_sbd_t *ssbdp;
4995574Smx205022 	dma_area_t desc;
5005574Smx205022 	dma_area_t pbuf;
5015574Smx205022 
5025574Smx205022 	srp = ngep->send;
5035574Smx205022 	srp->desc.nslots = ngep->tx_desc;
5045574Smx205022 	nslots = srp->desc.nslots;
5055574Smx205022 
5065574Smx205022 	NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
5075574Smx205022 	/*
5085574Smx205022 	 * Other one-off initialisation of per-ring data
5095574Smx205022 	 */
5105574Smx205022 	srp->ngep = ngep;
5115574Smx205022 
5125574Smx205022 	/*
5135574Smx205022 	 * Allocate the array of s/w Send Buffer Descriptors
5145574Smx205022 	 */
5155574Smx205022 	ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
5165574Smx205022 	srp->sw_sbds = ssbdp;
5175574Smx205022 
5185574Smx205022 	/*
5195574Smx205022 	 * Now initialise each array element once and for all
5205574Smx205022 	 */
5215574Smx205022 	desc = srp->desc;
5225574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
5235574Smx205022 		pbuf = srp->buf[split];
5245574Smx205022 		for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
5255574Smx205022 			nge_slice_chunk(&ssbdp->desc, &desc, 1,
5265574Smx205022 			    ngep->desc_attr.txd_size);
5275574Smx205022 			nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
5285574Smx205022 			    ngep->buf_size);
5295574Smx205022 		}
5305574Smx205022 		ASSERT(pbuf.alength == 0);
5315574Smx205022 	}
5325574Smx205022 	ASSERT(desc.alength == 0);
5335574Smx205022 
5345574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5355574Smx205022 
5365574Smx205022 	/* preallocate dma handles for tx buffer */
5375574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
5385574Smx205022 
5395574Smx205022 		err = ddi_dma_alloc_handle(ngep->devinfo,
5405574Smx205022 		    ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
5415574Smx205022 		    NULL, &srp->dmahndl[slot].hndl);
5425574Smx205022 
5435574Smx205022 		if (err != DDI_SUCCESS) {
5445574Smx205022 			nge_fini_send_ring(ngep);
5455574Smx205022 			nge_error(ngep,
5465574Smx205022 			    "nge_init_send_ring: alloc dma handle fails");
5475574Smx205022 			return (DDI_FAILURE);
5485574Smx205022 		}
5495574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5505574Smx205022 	}
5515574Smx205022 
5525574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5535574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5545574Smx205022 	srp->dmah_free.tail->next = NULL;
5555574Smx205022 
5565574Smx205022 	return (DDI_SUCCESS);
5575574Smx205022 }
5585574Smx205022 
5595574Smx205022 /*
5605574Smx205022  * Intialize the tx recycle pointer and tx sending pointer of tx ring
5615574Smx205022  * and set the type of tx's data descriptor by default.
5625574Smx205022  */
5635574Smx205022 static void
5645574Smx205022 nge_reinit_send_ring(nge_t *ngep)
5655574Smx205022 {
5665574Smx205022 	size_t dmah_num;
5675574Smx205022 	uint32_t slot;
5685574Smx205022 	send_ring_t *srp;
5695574Smx205022 	sw_tx_sbd_t *ssbdp;
5705574Smx205022 
5715574Smx205022 	srp = ngep->send;
5725574Smx205022 
5735574Smx205022 	/*
5745574Smx205022 	 * Reinitialise control variables ...
5755574Smx205022 	 */
5765574Smx205022 
5775574Smx205022 	srp->tx_hwmark = NGE_DESC_MIN;
5785574Smx205022 	srp->tx_lwmark = NGE_DESC_MIN;
5795574Smx205022 
5805574Smx205022 	srp->tx_next = 0;
5815574Smx205022 	srp->tx_free = srp->desc.nslots;
5825574Smx205022 	srp->tc_next = 0;
5835574Smx205022 
5845574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5855574Smx205022 
5865574Smx205022 	for (slot = 0; slot - dmah_num != 0; ++slot)
5875574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5885574Smx205022 
5895574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5905574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5915574Smx205022 	srp->dmah_free.tail->next = NULL;
5925574Smx205022 
5935574Smx205022 	/*
5945574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
5955574Smx205022 	 */
5965574Smx205022 	for (slot = 0; slot < srp->desc.nslots; ++slot) {
5975574Smx205022 		ssbdp = &srp->sw_sbds[slot];
5985574Smx205022 		ssbdp->flags = HOST_OWN;
5995574Smx205022 	}
6005574Smx205022 
6015574Smx205022 	DMA_ZERO(srp->desc);
6025574Smx205022 	DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
6035574Smx205022 }
6045574Smx205022 
6055574Smx205022 /*
6065574Smx205022  * Initialize the slot number of rx's ring
6075574Smx205022  */
6085574Smx205022 static void
6095574Smx205022 nge_init_recv_ring(nge_t *ngep)
6105574Smx205022 {
6115574Smx205022 	recv_ring_t *rrp;
6125574Smx205022 
6135574Smx205022 	rrp = ngep->recv;
6145574Smx205022 	rrp->desc.nslots = ngep->rx_desc;
6155574Smx205022 	rrp->ngep = ngep;
6165574Smx205022 }
6175574Smx205022 
6185574Smx205022 /*
6195574Smx205022  * Intialize the rx recycle pointer and rx sending pointer of rx ring
6205574Smx205022  */
6215574Smx205022 static void
6225574Smx205022 nge_reinit_recv_ring(nge_t *ngep)
6235574Smx205022 {
6245574Smx205022 	recv_ring_t *rrp;
6255574Smx205022 
6265574Smx205022 	rrp = ngep->recv;
6275574Smx205022 
6285574Smx205022 	/*
6295574Smx205022 	 * Reinitialise control variables ...
6305574Smx205022 	 */
6315574Smx205022 	rrp->prod_index = 0;
6325574Smx205022 	/*
6335574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
6345574Smx205022 	 */
6355574Smx205022 	DMA_ZERO(rrp->desc);
6365574Smx205022 	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
6375574Smx205022 }
6385574Smx205022 
6395574Smx205022 /*
6405574Smx205022  * Clean up initialisation done above before the memory is freed
6415574Smx205022  */
6425574Smx205022 static void
6435574Smx205022 nge_fini_buff_ring(nge_t *ngep)
6445574Smx205022 {
6455574Smx205022 	uint32_t i;
6465574Smx205022 	buff_ring_t *brp;
6475574Smx205022 	dma_area_t *bufp;
6485574Smx205022 	sw_rx_sbd_t *bsbdp;
6495574Smx205022 
6505574Smx205022 	brp = ngep->buff;
6515574Smx205022 	bsbdp = brp->sw_rbds;
6525574Smx205022 
6535574Smx205022 	NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
6545574Smx205022 
6555574Smx205022 	mutex_enter(brp->recycle_lock);
6565574Smx205022 	brp->buf_sign++;
6575574Smx205022 	mutex_exit(brp->recycle_lock);
6585574Smx205022 	for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
6595574Smx205022 		if (bsbdp->bufp) {
6605574Smx205022 			if (bsbdp->bufp->mp)
6615574Smx205022 				freemsg(bsbdp->bufp->mp);
6625574Smx205022 			nge_free_dma_mem(bsbdp->bufp);
6635574Smx205022 			kmem_free(bsbdp->bufp, sizeof (dma_area_t));
6645574Smx205022 			bsbdp->bufp = NULL;
6655574Smx205022 		}
6665574Smx205022 	}
6675574Smx205022 	while (brp->free_list != NULL) {
6685574Smx205022 		bufp = brp->free_list;
6695574Smx205022 		brp->free_list = bufp->next;
6705574Smx205022 		bufp->next = NULL;
6715574Smx205022 		if (bufp->mp)
6725574Smx205022 			freemsg(bufp->mp);
6735574Smx205022 		nge_free_dma_mem(bufp);
6745574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6755574Smx205022 	}
6765574Smx205022 	while (brp->recycle_list != NULL) {
6775574Smx205022 		bufp = brp->recycle_list;
6785574Smx205022 		brp->recycle_list = bufp->next;
6795574Smx205022 		bufp->next = NULL;
6805574Smx205022 		if (bufp->mp)
6815574Smx205022 			freemsg(bufp->mp);
6825574Smx205022 		nge_free_dma_mem(bufp);
6835574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6845574Smx205022 	}
6855574Smx205022 
6865574Smx205022 
6875574Smx205022 	kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
6885574Smx205022 	brp->sw_rbds = NULL;
6895574Smx205022 }
6905574Smx205022 
6915574Smx205022 /*
6925574Smx205022  * Intialize the Rx's data ring and free ring
6935574Smx205022  */
6945574Smx205022 static int
6955574Smx205022 nge_init_buff_ring(nge_t *ngep)
6965574Smx205022 {
6975574Smx205022 	uint32_t err;
6985574Smx205022 	uint32_t slot;
6995574Smx205022 	uint32_t nslots_buff;
7005574Smx205022 	uint32_t nslots_recv;
7015574Smx205022 	buff_ring_t *brp;
7025574Smx205022 	recv_ring_t *rrp;
7035574Smx205022 	dma_area_t desc;
7045574Smx205022 	dma_area_t *bufp;
7055574Smx205022 	sw_rx_sbd_t *bsbdp;
7065574Smx205022 
7075574Smx205022 	rrp = ngep->recv;
7085574Smx205022 	brp = ngep->buff;
7095574Smx205022 	brp->nslots = ngep->rx_buf;
7105574Smx205022 	brp->rx_bcopy = B_FALSE;
7115574Smx205022 	nslots_recv = rrp->desc.nslots;
7125574Smx205022 	nslots_buff = brp->nslots;
7135574Smx205022 	brp->ngep = ngep;
7145574Smx205022 
7155574Smx205022 	NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
7165574Smx205022 
7175574Smx205022 	/*
7185574Smx205022 	 * Allocate the array of s/w Recv Buffer Descriptors
7195574Smx205022 	 */
7205574Smx205022 	bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
7215574Smx205022 	brp->sw_rbds = bsbdp;
7225574Smx205022 	brp->free_list = NULL;
7235574Smx205022 	brp->recycle_list = NULL;
7245574Smx205022 	for (slot = 0; slot < nslots_buff; ++slot) {
7255574Smx205022 		bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
7265574Smx205022 		err = nge_alloc_dma_mem(ngep, (ngep->buf_size
7275574Smx205022 		    + NGE_HEADROOM),
7285574Smx205022 		    &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
7295574Smx205022 		if (err != DDI_SUCCESS) {
7305574Smx205022 			kmem_free(bufp, sizeof (dma_area_t));
7315574Smx205022 			return (DDI_FAILURE);
7325574Smx205022 		}
7335574Smx205022 
7345574Smx205022 		bufp->alength -= NGE_HEADROOM;
7355574Smx205022 		bufp->offset += NGE_HEADROOM;
7365574Smx205022 		bufp->private = (caddr_t)ngep;
7375574Smx205022 		bufp->rx_recycle.free_func = nge_recv_recycle;
7385574Smx205022 		bufp->rx_recycle.free_arg = (caddr_t)bufp;
7395574Smx205022 		bufp->signature = brp->buf_sign;
7405574Smx205022 		bufp->rx_delivered = B_FALSE;
7415574Smx205022 		bufp->mp = desballoc(DMA_VPTR(*bufp),
7425574Smx205022 		    ngep->buf_size + NGE_HEADROOM,
7435574Smx205022 		    0, &bufp->rx_recycle);
7445574Smx205022 
7455574Smx205022 		if (bufp->mp == NULL) {
7465574Smx205022 			return (DDI_FAILURE);
7475574Smx205022 		}
7485574Smx205022 		bufp->next = brp->free_list;
7495574Smx205022 		brp->free_list = bufp;
7505574Smx205022 	}
7515574Smx205022 
7525574Smx205022 	/*
7535574Smx205022 	 * Now initialise each array element once and for all
7545574Smx205022 	 */
7555574Smx205022 	desc = rrp->desc;
7565574Smx205022 	for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
7575574Smx205022 		nge_slice_chunk(&bsbdp->desc, &desc, 1,
7585574Smx205022 		    ngep->desc_attr.rxd_size);
7595574Smx205022 		bufp = brp->free_list;
7605574Smx205022 		brp->free_list = bufp->next;
7615574Smx205022 		bsbdp->bufp = bufp;
7625574Smx205022 		bsbdp->flags = CONTROLER_OWN;
7635574Smx205022 		bufp->next = NULL;
7645574Smx205022 	}
7655574Smx205022 
7665574Smx205022 	ASSERT(desc.alength == 0);
7675574Smx205022 	return (DDI_SUCCESS);
7685574Smx205022 }
7695574Smx205022 
7705574Smx205022 /*
7715574Smx205022  * Fill the host address of data in rx' descriptor
7725574Smx205022  * and initialize free pointers of rx free ring
7735574Smx205022  */
7745574Smx205022 static int
7755574Smx205022 nge_reinit_buff_ring(nge_t *ngep)
7765574Smx205022 {
7775574Smx205022 	uint32_t slot;
7785574Smx205022 	uint32_t nslots_recv;
7795574Smx205022 	buff_ring_t *brp;
7805574Smx205022 	recv_ring_t *rrp;
7815574Smx205022 	sw_rx_sbd_t *bsbdp;
7825574Smx205022 	void *hw_bd_p;
7835574Smx205022 
7845574Smx205022 	brp = ngep->buff;
7855574Smx205022 	rrp = ngep->recv;
7865574Smx205022 	bsbdp = brp->sw_rbds;
7875574Smx205022 	nslots_recv = rrp->desc.nslots;
7885574Smx205022 	for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
7895574Smx205022 		hw_bd_p = DMA_VPTR(bsbdp->desc);
7905574Smx205022 	/*
7915574Smx205022 	 * There is a scenario: When the traffic of small tcp
7925574Smx205022 	 * packet is heavy, suspending the tcp traffic will
7935574Smx205022 	 * cause the preallocated buffers for rx not to be
7945574Smx205022 	 * released in time by tcp taffic and cause rx's buffer
7955574Smx205022 	 * pointers not to be refilled in time.
7965574Smx205022 	 *
7975574Smx205022 	 * At this point, if we reinitialize the driver, the bufp
7985574Smx205022 	 * pointer for rx's traffic will be NULL.
7995574Smx205022 	 * So the result of the reinitializion fails.
8005574Smx205022 	 */
8015574Smx205022 		if (bsbdp->bufp == NULL)
8025574Smx205022 			return (DDI_FAILURE);
8035574Smx205022 
8045574Smx205022 		ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
8055574Smx205022 		    bsbdp->bufp->alength);
8065574Smx205022 	}
8075574Smx205022 	return (DDI_SUCCESS);
8085574Smx205022 }
8095574Smx205022 
8105574Smx205022 static void
8115574Smx205022 nge_init_ring_param_lock(nge_t *ngep)
8125574Smx205022 {
8135574Smx205022 	buff_ring_t *brp;
8145574Smx205022 	send_ring_t *srp;
8155574Smx205022 
8165574Smx205022 	srp = ngep->send;
8175574Smx205022 	brp = ngep->buff;
8185574Smx205022 
8195574Smx205022 	/* Init the locks for send ring */
8205574Smx205022 	mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
8215574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8225574Smx205022 	mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
8235574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8245574Smx205022 	mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
8255574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8265574Smx205022 
8275574Smx205022 	/* Init parameters of buffer ring */
8285574Smx205022 	brp->free_list = NULL;
8295574Smx205022 	brp->recycle_list = NULL;
8305574Smx205022 	brp->rx_hold = 0;
8315574Smx205022 	brp->buf_sign = 0;
8325574Smx205022 
8335574Smx205022 	/* Init recycle list lock */
8345574Smx205022 	mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
8355574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8365574Smx205022 }
8375574Smx205022 
8385574Smx205022 int
8395574Smx205022 nge_init_rings(nge_t *ngep)
8405574Smx205022 {
8415574Smx205022 	uint32_t err;
8425574Smx205022 
8435574Smx205022 	err = nge_init_send_ring(ngep);
8445574Smx205022 	if (err != DDI_SUCCESS) {
8455574Smx205022 		return (err);
8465574Smx205022 	}
8475574Smx205022 	nge_init_recv_ring(ngep);
8485574Smx205022 
8495574Smx205022 	err = nge_init_buff_ring(ngep);
8505574Smx205022 	if (err != DDI_SUCCESS) {
8515574Smx205022 		nge_fini_send_ring(ngep);
8525574Smx205022 		return (DDI_FAILURE);
8535574Smx205022 	}
8545574Smx205022 
8555574Smx205022 	return (err);
8565574Smx205022 }
8575574Smx205022 
8585574Smx205022 static int
8595574Smx205022 nge_reinit_ring(nge_t *ngep)
8605574Smx205022 {
8615574Smx205022 	int err;
8625574Smx205022 
8635574Smx205022 	nge_reinit_recv_ring(ngep);
8645574Smx205022 	nge_reinit_send_ring(ngep);
8655574Smx205022 	err = nge_reinit_buff_ring(ngep);
8665574Smx205022 	return (err);
8675574Smx205022 }
8685574Smx205022 
8695574Smx205022 
8705574Smx205022 void
8715574Smx205022 nge_fini_rings(nge_t *ngep)
8725574Smx205022 {
8735574Smx205022 	/*
8745574Smx205022 	 * For receive ring, nothing need to be finished.
8755574Smx205022 	 * So only finish buffer ring and send ring here.
8765574Smx205022 	 */
8775574Smx205022 	nge_fini_buff_ring(ngep);
8785574Smx205022 	nge_fini_send_ring(ngep);
8795574Smx205022 }
8805574Smx205022 
8815574Smx205022 /*
8825574Smx205022  * Loopback ioctl code
8835574Smx205022  */
8845574Smx205022 
8855574Smx205022 static lb_property_t loopmodes[] = {
8865574Smx205022 	{ normal,	"normal",	NGE_LOOP_NONE		},
8875574Smx205022 	{ external,	"100Mbps",	NGE_LOOP_EXTERNAL_100	},
8885574Smx205022 	{ external,	"10Mbps",	NGE_LOOP_EXTERNAL_10	},
8895574Smx205022 	{ internal,	"PHY",		NGE_LOOP_INTERNAL_PHY	},
8905574Smx205022 };
8915574Smx205022 
8925574Smx205022 enum ioc_reply
8935574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
8945574Smx205022 {
8955574Smx205022 	int cmd;
8965574Smx205022 	uint32_t *lbmp;
8975574Smx205022 	lb_info_sz_t *lbsp;
8985574Smx205022 	lb_property_t *lbpp;
8995574Smx205022 
9005574Smx205022 	/*
9015574Smx205022 	 * Validate format of ioctl
9025574Smx205022 	 */
9035574Smx205022 	if (mp->b_cont == NULL)
9045574Smx205022 		return (IOC_INVAL);
9055574Smx205022 
9065574Smx205022 	cmd = iocp->ioc_cmd;
9075574Smx205022 
9085574Smx205022 	switch (cmd) {
9095574Smx205022 	default:
9105574Smx205022 		return (IOC_INVAL);
9115574Smx205022 
9125574Smx205022 	case LB_GET_INFO_SIZE:
9135574Smx205022 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
9145574Smx205022 			return (IOC_INVAL);
9155574Smx205022 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
9165574Smx205022 		*lbsp = sizeof (loopmodes);
9175574Smx205022 		return (IOC_REPLY);
9185574Smx205022 
9195574Smx205022 	case LB_GET_INFO:
9205574Smx205022 		if (iocp->ioc_count != sizeof (loopmodes))
9215574Smx205022 			return (IOC_INVAL);
9225574Smx205022 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
9235574Smx205022 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
9245574Smx205022 		return (IOC_REPLY);
9255574Smx205022 
9265574Smx205022 	case LB_GET_MODE:
9275574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9285574Smx205022 			return (IOC_INVAL);
9295574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9305574Smx205022 		*lbmp = ngep->param_loop_mode;
9315574Smx205022 		return (IOC_REPLY);
9325574Smx205022 
9335574Smx205022 	case LB_SET_MODE:
9345574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9355574Smx205022 			return (IOC_INVAL);
9365574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9375574Smx205022 		return (nge_set_loop_mode(ngep, *lbmp));
9385574Smx205022 	}
9395574Smx205022 }
9405574Smx205022 
9415574Smx205022 #undef	NGE_DBG
9425574Smx205022 #define	NGE_DBG	NGE_DBG_NEMO
9435574Smx205022 
9445574Smx205022 
9455574Smx205022 static void
9465574Smx205022 nge_check_desc_prop(nge_t *ngep)
9475574Smx205022 {
9485574Smx205022 	if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
9495574Smx205022 		ngep->desc_mode = DESC_HOT;
9505574Smx205022 
9515574Smx205022 	if (ngep->desc_mode == DESC_OFFLOAD)	{
9525574Smx205022 
9535574Smx205022 		ngep->desc_attr = nge_sum_desc;
9545574Smx205022 
9555574Smx205022 	}	else if (ngep->desc_mode == DESC_HOT)	{
9565574Smx205022 
9575574Smx205022 		ngep->desc_attr = nge_hot_desc;
9585574Smx205022 	}
9595574Smx205022 }
9605574Smx205022 
9615574Smx205022 /*
9625574Smx205022  * nge_get_props -- get the parameters to tune the driver
9635574Smx205022  */
9645574Smx205022 static void
9655574Smx205022 nge_get_props(nge_t *ngep)
9665574Smx205022 {
9675574Smx205022 	chip_info_t *infop;
9685574Smx205022 	dev_info_t *devinfo;
9695574Smx205022 	nge_dev_spec_param_t *dev_param_p;
9705574Smx205022 
9715574Smx205022 	devinfo = ngep->devinfo;
9725574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
9735574Smx205022 	dev_param_p = &ngep->dev_spec_param;
9745574Smx205022 
9755574Smx205022 	infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9765574Smx205022 	    DDI_PROP_DONTPASS, clsize_propname, 32);
9775574Smx205022 
9785574Smx205022 	infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9795574Smx205022 	    DDI_PROP_DONTPASS, latency_propname, 64);
9805659Sjj146644 	ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9815659Sjj146644 	    DDI_PROP_DONTPASS, intr_moderation, NGE_SET);
9825574Smx205022 	ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9835574Smx205022 	    DDI_PROP_DONTPASS, rx_data_hw, 0x20);
9845574Smx205022 	ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9855574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
9865574Smx205022 	ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9875574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
9885574Smx205022 
9895574Smx205022 	ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9905574Smx205022 	    DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
9915574Smx205022 	ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9925574Smx205022 	    DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
9935574Smx205022 	ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9945574Smx205022 	    DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
9955574Smx205022 	ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9965574Smx205022 	    DDI_PROP_DONTPASS, low_memory_mode, 0);
9975574Smx205022 
9985574Smx205022 	if (dev_param_p->jumbo) {
9995574Smx205022 		ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10005574Smx205022 		    DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
10015574Smx205022 	} else
10025574Smx205022 		ngep->default_mtu = ETHERMTU;
100310496SLi-Zhen.You@Sun.COM 	if (dev_param_p->tx_pause_frame)
100410496SLi-Zhen.You@Sun.COM 			ngep->param_link_tx_pause = B_TRUE;
100510496SLi-Zhen.You@Sun.COM 	else
100610496SLi-Zhen.You@Sun.COM 			ngep->param_link_tx_pause = B_FALSE;
100710496SLi-Zhen.You@Sun.COM 
100810496SLi-Zhen.You@Sun.COM 	if (dev_param_p->rx_pause_frame)
100910496SLi-Zhen.You@Sun.COM 			ngep->param_link_rx_pause = B_TRUE;
101010496SLi-Zhen.You@Sun.COM 	else
101110496SLi-Zhen.You@Sun.COM 			ngep->param_link_rx_pause = B_FALSE;
10125574Smx205022 
10135574Smx205022 	if (ngep->default_mtu > ETHERMTU &&
10145574Smx205022 	    ngep->default_mtu <= NGE_MTU_2500) {
10155574Smx205022 		ngep->buf_size = NGE_JB2500_BUFSZ;
10165574Smx205022 		ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
10175574Smx205022 		ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
10185574Smx205022 		ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
10195574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10205574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_2500 &&
10215574Smx205022 	    ngep->default_mtu <= NGE_MTU_4500) {
10225574Smx205022 		ngep->buf_size = NGE_JB4500_BUFSZ;
10235574Smx205022 		ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
10245574Smx205022 		ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
10255574Smx205022 		ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
10265574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10275574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_4500 &&
10285574Smx205022 	    ngep->default_mtu <= NGE_MAX_MTU) {
10295574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10305574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10315574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10325574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10335574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10345574Smx205022 	} else if (ngep->default_mtu > NGE_MAX_MTU) {
10355574Smx205022 		ngep->default_mtu = NGE_MAX_MTU;
10365574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10375574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10385574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10395574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10405574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10415574Smx205022 	} else if (ngep->lowmem_mode != 0) {
10425574Smx205022 		ngep->default_mtu = ETHERMTU;
10435574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10445574Smx205022 		ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
10455574Smx205022 		ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
10465574Smx205022 		ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
10475574Smx205022 		ngep->nge_split = NGE_SPLIT_32;
10485574Smx205022 	} else {
10495574Smx205022 		ngep->default_mtu = ETHERMTU;
10505574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10515574Smx205022 		ngep->tx_desc = dev_param_p->tx_desc_num;
10525574Smx205022 		ngep->rx_desc = dev_param_p->rx_desc_num;
10535574Smx205022 		ngep->rx_buf = dev_param_p->rx_desc_num * 2;
10545574Smx205022 		ngep->nge_split = dev_param_p->nge_split;
10555574Smx205022 	}
10565574Smx205022 
10575574Smx205022 	nge_check_desc_prop(ngep);
10585574Smx205022 }
10595574Smx205022 
10605574Smx205022 
10615574Smx205022 static int
10627656SSherry.Moore@Sun.COM nge_reset_dev(nge_t *ngep)
10635574Smx205022 {
10645574Smx205022 	int err;
10655869Smx205022 	nge_mul_addr1 maddr1;
10665869Smx205022 	nge_sw_statistics_t *sw_stp;
10675869Smx205022 	sw_stp = &ngep->statistics.sw_statistics;
10685574Smx205022 	send_ring_t *srp = ngep->send;
10695574Smx205022 
10705574Smx205022 	ASSERT(mutex_owned(ngep->genlock));
10715574Smx205022 	mutex_enter(srp->tc_lock);
10725574Smx205022 	mutex_enter(srp->tx_lock);
10735574Smx205022 
10745574Smx205022 	nge_tx_recycle_all(ngep);
10755574Smx205022 	err = nge_reinit_ring(ngep);
10765574Smx205022 	if (err == DDI_FAILURE) {
10775574Smx205022 		mutex_exit(srp->tx_lock);
10785574Smx205022 		mutex_exit(srp->tc_lock);
10795574Smx205022 		return (err);
10805574Smx205022 	}
10815574Smx205022 	err = nge_chip_reset(ngep);
10825869Smx205022 	/*
10835869Smx205022 	 * Clear the Multicast mac address table
10845869Smx205022 	 */
10855869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
10865869Smx205022 	maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
10875869Smx205022 	maddr1.addr_bits.addr = 0;
10885869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
10895869Smx205022 
10905574Smx205022 	mutex_exit(srp->tx_lock);
10915574Smx205022 	mutex_exit(srp->tc_lock);
10925574Smx205022 	if (err == DDI_FAILURE)
10935574Smx205022 		return (err);
10945574Smx205022 	ngep->watchdog = 0;
10955574Smx205022 	ngep->resched_needed = B_FALSE;
10965574Smx205022 	ngep->promisc = B_FALSE;
10975574Smx205022 	ngep->param_loop_mode = NGE_LOOP_NONE;
10985574Smx205022 	ngep->factotum_flag = 0;
10995574Smx205022 	ngep->resched_needed = 0;
11005574Smx205022 	ngep->nge_mac_state = NGE_MAC_RESET;
11015574Smx205022 	ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
11025574Smx205022 	ngep->max_sdu += VTAG_SIZE;
11035574Smx205022 	ngep->rx_def = 0x16;
11045869Smx205022 
11055869Smx205022 	/* Clear the software statistics */
11065869Smx205022 	sw_stp->recv_count = 0;
11075869Smx205022 	sw_stp->xmit_count = 0;
11085869Smx205022 	sw_stp->rbytes = 0;
11095869Smx205022 	sw_stp->obytes = 0;
11105869Smx205022 
11115574Smx205022 	return (DDI_SUCCESS);
11125574Smx205022 }
11135574Smx205022 
11145574Smx205022 static void
11155574Smx205022 nge_m_stop(void *arg)
11165574Smx205022 {
11175574Smx205022 	nge_t *ngep = arg;		/* private device info	*/
11189708SZhen.W@Sun.COM 	int err;
11195574Smx205022 
11205574Smx205022 	NGE_TRACE(("nge_m_stop($%p)", arg));
11215574Smx205022 
11225574Smx205022 	/*
11235574Smx205022 	 * Just stop processing, then record new MAC state
11245574Smx205022 	 */
11255574Smx205022 	mutex_enter(ngep->genlock);
11265869Smx205022 	/* If suspended, the adapter is already stopped, just return. */
11275869Smx205022 	if (ngep->suspended) {
11285869Smx205022 		ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
11295869Smx205022 		mutex_exit(ngep->genlock);
11305869Smx205022 		return;
11315869Smx205022 	}
11325574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11335574Smx205022 
11349708SZhen.W@Sun.COM 	err = nge_chip_stop(ngep, B_FALSE);
11359708SZhen.W@Sun.COM 	if (err == DDI_FAILURE)
11369708SZhen.W@Sun.COM 		err = nge_chip_reset(ngep);
11379708SZhen.W@Sun.COM 	if (err == DDI_FAILURE)
11389708SZhen.W@Sun.COM 		nge_problem(ngep, "nge_m_stop: stop chip failed");
11395574Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
11405574Smx205022 
11415574Smx205022 	/* Recycle all the TX BD */
11425574Smx205022 	nge_tx_recycle_all(ngep);
11435574Smx205022 	nge_fini_rings(ngep);
11445574Smx205022 	nge_free_bufs(ngep);
11455574Smx205022 
11465574Smx205022 	NGE_DEBUG(("nge_m_stop($%p) done", arg));
11475574Smx205022 
11485574Smx205022 	rw_exit(ngep->rwlock);
11495574Smx205022 	mutex_exit(ngep->genlock);
11505574Smx205022 }
11515574Smx205022 
11525574Smx205022 static int
11535574Smx205022 nge_m_start(void *arg)
11545574Smx205022 {
11555574Smx205022 	int err;
11565574Smx205022 	nge_t *ngep = arg;
11575574Smx205022 
11585574Smx205022 	NGE_TRACE(("nge_m_start($%p)", arg));
11595869Smx205022 
11605869Smx205022 	/*
11615869Smx205022 	 * Start processing and record new MAC state
11625869Smx205022 	 */
11635869Smx205022 	mutex_enter(ngep->genlock);
11645574Smx205022 	/*
11655574Smx205022 	 * If suspended, don't start, as the resume processing
11665574Smx205022 	 * will recall this function with the suspended flag off.
11675574Smx205022 	 */
11685869Smx205022 	if (ngep->suspended) {
11695869Smx205022 		mutex_exit(ngep->genlock);
11705988Svb160487 		return (EIO);
11715869Smx205022 	}
11725574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11735574Smx205022 	err = nge_alloc_bufs(ngep);
11745574Smx205022 	if (err != DDI_SUCCESS) {
11755574Smx205022 		nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
11765574Smx205022 		goto finish;
11775574Smx205022 	}
11785574Smx205022 	err = nge_init_rings(ngep);
11795574Smx205022 	if (err != DDI_SUCCESS) {
11805574Smx205022 		nge_free_bufs(ngep);
11815988Svb160487 		nge_problem(ngep, "nge_init_rings() failed,err=%x", err);
11825574Smx205022 		goto finish;
11835574Smx205022 	}
11845574Smx205022 	err = nge_restart(ngep);
11855574Smx205022 
11865574Smx205022 	NGE_DEBUG(("nge_m_start($%p) done", arg));
11875988Svb160487 finish:
11885988Svb160487 	rw_exit(ngep->rwlock);
11895988Svb160487 	mutex_exit(ngep->genlock);
11905574Smx205022 
11915988Svb160487 	return (err == DDI_SUCCESS ? 0 : EIO);
11925574Smx205022 }
11935574Smx205022 
11945574Smx205022 static int
11955574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr)
11965574Smx205022 {
11975574Smx205022 	nge_t *ngep = arg;
11985574Smx205022 
11995574Smx205022 	NGE_TRACE(("nge_m_unicst($%p)", arg));
12005574Smx205022 	/*
12015574Smx205022 	 * Remember the new current address in the driver state
12025574Smx205022 	 * Sync the chip's idea of the address too ...
12035574Smx205022 	 */
12045574Smx205022 	mutex_enter(ngep->genlock);
12055574Smx205022 
12065574Smx205022 	ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
12075574Smx205022 	ngep->cur_uni_addr.set = 1;
12085574Smx205022 
12095574Smx205022 	/*
12105574Smx205022 	 * If we are suspended, we want to quit now, and not update
12115574Smx205022 	 * the chip.  Doing so might put it in a bad state, but the
12125574Smx205022 	 * resume will get the unicast address installed.
12135574Smx205022 	 */
12145869Smx205022 	if (ngep->suspended) {
12155869Smx205022 		mutex_exit(ngep->genlock);
12165574Smx205022 		return (DDI_SUCCESS);
12175869Smx205022 	}
12185574Smx205022 	nge_chip_sync(ngep);
12195574Smx205022 
12205574Smx205022 	NGE_DEBUG(("nge_m_unicst($%p) done", arg));
12215574Smx205022 	mutex_exit(ngep->genlock);
12225574Smx205022 
12235574Smx205022 	return (0);
12245574Smx205022 }
12255574Smx205022 
12265574Smx205022 static int
12275574Smx205022 nge_m_promisc(void *arg, boolean_t on)
12285574Smx205022 {
12295574Smx205022 	nge_t *ngep = arg;
12305574Smx205022 
12315574Smx205022 	NGE_TRACE(("nge_m_promisc($%p)", arg));
12325574Smx205022 
12335574Smx205022 	/*
12345574Smx205022 	 * Store specified mode and pass to chip layer to update h/w
12355574Smx205022 	 */
12365574Smx205022 	mutex_enter(ngep->genlock);
12375869Smx205022 	/*
12385869Smx205022 	 * If suspended, there is no need to do anything, even
12395869Smx205022 	 * recording the promiscuious mode is not neccessary, as
12405869Smx205022 	 * it won't be properly set on resume.  Just return failing.
12415869Smx205022 	 */
12425869Smx205022 	if (ngep->suspended) {
12435869Smx205022 		mutex_exit(ngep->genlock);
12445869Smx205022 		return (DDI_FAILURE);
12455869Smx205022 	}
12465574Smx205022 	if (ngep->promisc == on) {
12475574Smx205022 		mutex_exit(ngep->genlock);
12485574Smx205022 		NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12495574Smx205022 		return (0);
12505574Smx205022 	}
12515574Smx205022 	ngep->promisc = on;
12527155Smx205022 	ngep->record_promisc = ngep->promisc;
12535574Smx205022 	nge_chip_sync(ngep);
12545574Smx205022 	NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12555574Smx205022 	mutex_exit(ngep->genlock);
12565574Smx205022 
12575574Smx205022 	return (0);
12585574Smx205022 }
12595574Smx205022 
12605574Smx205022 static void nge_mulparam(nge_t *ngep)
12615574Smx205022 {
12625574Smx205022 	uint8_t number;
12635574Smx205022 	ether_addr_t pand;
12645574Smx205022 	ether_addr_t por;
12655574Smx205022 	mul_item *plist;
12665574Smx205022 
12675574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12685574Smx205022 		pand[number] = 0x00;
12695574Smx205022 		por[number] = 0x00;
12705574Smx205022 	}
12715574Smx205022 	for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
12725574Smx205022 		for (number = 0; number < ETHERADDRL; number++) {
12735574Smx205022 			pand[number] &= plist->mul_addr[number];
12745574Smx205022 			por[number] |= plist->mul_addr[number];
12755574Smx205022 		}
12765574Smx205022 	}
12775574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12785574Smx205022 		ngep->cur_mul_addr.addr[number]
12795574Smx205022 		    = pand[number] & por[number];
12805574Smx205022 		ngep->cur_mul_mask.addr[number]
12815574Smx205022 		    = pand [number] | (~por[number]);
12825574Smx205022 	}
12835574Smx205022 }
12845574Smx205022 static int
12855574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
12865574Smx205022 {
12875574Smx205022 	boolean_t update;
12885574Smx205022 	boolean_t b_eq;
12895574Smx205022 	nge_t *ngep = arg;
12905574Smx205022 	mul_item *plist;
12915574Smx205022 	mul_item *plist_prev;
12925574Smx205022 	mul_item *pitem;
12935574Smx205022 
12945574Smx205022 	NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
12955574Smx205022 	    (add) ? "add" : "remove", ether_sprintf((void *)mca)));
12965574Smx205022 
12975574Smx205022 	update = B_FALSE;
12985574Smx205022 	plist = plist_prev = NULL;
12995574Smx205022 	mutex_enter(ngep->genlock);
13005574Smx205022 	if (add) {
13015574Smx205022 		if (ngep->pcur_mulist != NULL) {
13025574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13035574Smx205022 			    plist = plist->next) {
13045574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13055574Smx205022 				if (b_eq) {
13065574Smx205022 					plist->ref_cnt++;
13075574Smx205022 					break;
13085574Smx205022 				}
13095574Smx205022 				plist_prev = plist;
13105574Smx205022 			}
13115574Smx205022 		}
13125574Smx205022 
13135574Smx205022 		if (plist == NULL) {
13145574Smx205022 			pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
13155574Smx205022 			ether_copy(mca, pitem->mul_addr);
13165574Smx205022 			pitem ->ref_cnt++;
13175574Smx205022 			pitem ->next = NULL;
13185574Smx205022 			if (plist_prev == NULL)
13195574Smx205022 				ngep->pcur_mulist = pitem;
13205574Smx205022 			else
13215574Smx205022 				plist_prev->next = pitem;
13225574Smx205022 			update = B_TRUE;
13235574Smx205022 		}
13245574Smx205022 	} else {
13255574Smx205022 		if (ngep->pcur_mulist != NULL) {
13265574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13275574Smx205022 			    plist = plist->next) {
13285574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13295574Smx205022 				if (b_eq) {
13305574Smx205022 					update = B_TRUE;
13315574Smx205022 					break;
13325574Smx205022 				}
13335574Smx205022 				plist_prev = plist;
13345574Smx205022 			}
13355574Smx205022 
13365574Smx205022 			if (update) {
13375574Smx205022 				if ((plist_prev == NULL) &&
13385574Smx205022 				    (plist->next == NULL))
13395574Smx205022 					ngep->pcur_mulist = NULL;
13405574Smx205022 				else if ((plist_prev == NULL) &&
13415574Smx205022 				    (plist->next != NULL))
13425574Smx205022 					ngep->pcur_mulist = plist->next;
13435574Smx205022 				else
13445574Smx205022 					plist_prev->next = plist->next;
13455574Smx205022 				kmem_free(plist, sizeof (mul_item));
13465574Smx205022 			}
13475574Smx205022 		}
13485574Smx205022 	}
13495574Smx205022 
13505869Smx205022 	if (update && !ngep->suspended) {
13515574Smx205022 		nge_mulparam(ngep);
13525574Smx205022 		nge_chip_sync(ngep);
13535574Smx205022 	}
13545574Smx205022 	NGE_DEBUG(("nge_m_multicst($%p) done", arg));
13555574Smx205022 	mutex_exit(ngep->genlock);
13565574Smx205022 
13575574Smx205022 	return (0);
13585574Smx205022 }
13595574Smx205022 
13605574Smx205022 static void
13615574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
13625574Smx205022 {
13635574Smx205022 	int err;
13645574Smx205022 	int cmd;
13655574Smx205022 	nge_t *ngep = arg;
13665574Smx205022 	struct iocblk *iocp;
13675574Smx205022 	enum ioc_reply status;
13685574Smx205022 	boolean_t need_privilege;
13695574Smx205022 
13705574Smx205022 	/*
13715574Smx205022 	 * If suspended, we might actually be able to do some of
13725574Smx205022 	 * these ioctls, but it is harder to make sure they occur
13735574Smx205022 	 * without actually putting the hardware in an undesireable
13745574Smx205022 	 * state.  So just NAK it.
13755574Smx205022 	 */
13765869Smx205022 	mutex_enter(ngep->genlock);
13775574Smx205022 	if (ngep->suspended) {
13785574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13795869Smx205022 		mutex_exit(ngep->genlock);
13805574Smx205022 		return;
13815574Smx205022 	}
13825869Smx205022 	mutex_exit(ngep->genlock);
13835574Smx205022 
13845574Smx205022 	/*
13855574Smx205022 	 * Validate the command before bothering with the mutex ...
13865574Smx205022 	 */
13875574Smx205022 	iocp = (struct iocblk *)mp->b_rptr;
13885574Smx205022 	iocp->ioc_error = 0;
13895574Smx205022 	need_privilege = B_TRUE;
13905574Smx205022 	cmd = iocp->ioc_cmd;
13915574Smx205022 
13925574Smx205022 	NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
13935574Smx205022 	switch (cmd) {
13945574Smx205022 	default:
13955574Smx205022 		NGE_LDB(NGE_DBG_BADIOC,
13965574Smx205022 		    ("nge_m_ioctl: unknown cmd 0x%x", cmd));
13975574Smx205022 
13985574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13995574Smx205022 		return;
14005574Smx205022 
14015574Smx205022 	case NGE_MII_READ:
14025574Smx205022 	case NGE_MII_WRITE:
14035574Smx205022 	case NGE_SEE_READ:
14045574Smx205022 	case NGE_SEE_WRITE:
14055574Smx205022 	case NGE_DIAG:
14065574Smx205022 	case NGE_PEEK:
14075574Smx205022 	case NGE_POKE:
14085574Smx205022 	case NGE_PHY_RESET:
14095574Smx205022 	case NGE_SOFT_RESET:
14105574Smx205022 	case NGE_HARD_RESET:
14115574Smx205022 		break;
14125574Smx205022 
14135574Smx205022 	case LB_GET_INFO_SIZE:
14145574Smx205022 	case LB_GET_INFO:
14155574Smx205022 	case LB_GET_MODE:
14165574Smx205022 		need_privilege = B_FALSE;
14175574Smx205022 		break;
14185574Smx205022 	case LB_SET_MODE:
14195574Smx205022 		break;
14205574Smx205022 	}
14215574Smx205022 
14225574Smx205022 	if (need_privilege) {
14235574Smx205022 		/*
14245574Smx205022 		 * Check for specific net_config privilege.
14255574Smx205022 		 */
14265574Smx205022 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
14275574Smx205022 		if (err != 0) {
14285574Smx205022 			NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
14295574Smx205022 			    cmd, err));
14305574Smx205022 			miocnak(wq, mp, 0, err);
14315574Smx205022 			return;
14325574Smx205022 		}
14335574Smx205022 	}
14345574Smx205022 
14355574Smx205022 	mutex_enter(ngep->genlock);
14365574Smx205022 
14375574Smx205022 	switch (cmd) {
14385574Smx205022 	default:
14395574Smx205022 		_NOTE(NOTREACHED)
14405574Smx205022 		status = IOC_INVAL;
14415574Smx205022 	break;
14425574Smx205022 
14435574Smx205022 	case NGE_MII_READ:
14445574Smx205022 	case NGE_MII_WRITE:
14455574Smx205022 	case NGE_SEE_READ:
14465574Smx205022 	case NGE_SEE_WRITE:
14475574Smx205022 	case NGE_DIAG:
14485574Smx205022 	case NGE_PEEK:
14495574Smx205022 	case NGE_POKE:
14505574Smx205022 	case NGE_PHY_RESET:
14515574Smx205022 	case NGE_SOFT_RESET:
14525574Smx205022 	case NGE_HARD_RESET:
14535574Smx205022 		status = nge_chip_ioctl(ngep, mp, iocp);
14545574Smx205022 	break;
14555574Smx205022 
14565574Smx205022 	case LB_GET_INFO_SIZE:
14575574Smx205022 	case LB_GET_INFO:
14585574Smx205022 	case LB_GET_MODE:
14595574Smx205022 	case LB_SET_MODE:
14605574Smx205022 		status = nge_loop_ioctl(ngep, mp, iocp);
14615574Smx205022 	break;
14625574Smx205022 
14635574Smx205022 	}
14645574Smx205022 
14655574Smx205022 	/*
14665574Smx205022 	 * Do we need to reprogram the PHY and/or the MAC?
14675574Smx205022 	 * Do it now, while we still have the mutex.
14685574Smx205022 	 *
14695574Smx205022 	 * Note: update the PHY first, 'cos it controls the
14705574Smx205022 	 * speed/duplex parameters that the MAC code uses.
14715574Smx205022 	 */
14725574Smx205022 
14735574Smx205022 	NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
14745574Smx205022 
14755574Smx205022 	switch (status) {
14765574Smx205022 	case IOC_RESTART_REPLY:
14775574Smx205022 	case IOC_RESTART_ACK:
14785574Smx205022 		(*ngep->physops->phys_update)(ngep);
14795574Smx205022 		nge_chip_sync(ngep);
14805574Smx205022 		break;
14815574Smx205022 
14825574Smx205022 	default:
14835574Smx205022 	break;
14845574Smx205022 	}
14855574Smx205022 
14865574Smx205022 	mutex_exit(ngep->genlock);
14875574Smx205022 
14885574Smx205022 	/*
14895574Smx205022 	 * Finally, decide how to reply
14905574Smx205022 	 */
14915574Smx205022 	switch (status) {
14925574Smx205022 
14935574Smx205022 	default:
14945574Smx205022 	case IOC_INVAL:
14955574Smx205022 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
14965574Smx205022 		    EINVAL : iocp->ioc_error);
14975574Smx205022 		break;
14985574Smx205022 
14995574Smx205022 	case IOC_DONE:
15005574Smx205022 		break;
15015574Smx205022 
15025574Smx205022 	case IOC_RESTART_ACK:
15035574Smx205022 	case IOC_ACK:
15045574Smx205022 		miocack(wq, mp, 0, 0);
15055574Smx205022 		break;
15065574Smx205022 
15075574Smx205022 	case IOC_RESTART_REPLY:
15085574Smx205022 	case IOC_REPLY:
15095574Smx205022 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
15105574Smx205022 		    M_IOCACK : M_IOCNAK;
15115574Smx205022 		qreply(wq, mp);
15125574Smx205022 		break;
15135574Smx205022 	}
15145574Smx205022 }
15155574Smx205022 
15166200Smx205022 static boolean_t
15176200Smx205022 nge_param_locked(mac_prop_id_t pr_num)
15186200Smx205022 {
15196200Smx205022 	/*
15206200Smx205022 	 * All adv_* parameters are locked (read-only) while
15216200Smx205022 	 * the device is in any sort of loopback mode ...
15226200Smx205022 	 */
15236200Smx205022 	switch (pr_num) {
15246789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15256789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15266789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15276789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
15286789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15296789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15306789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15316789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15326789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15336789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15346789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15356789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15366789Sam223141 		case MAC_PROP_AUTONEG:
15376789Sam223141 		case MAC_PROP_FLOWCTRL:
15386200Smx205022 			return (B_TRUE);
15396200Smx205022 	}
15406200Smx205022 	return (B_FALSE);
15416200Smx205022 }
15426200Smx205022 
15436200Smx205022 /*
15446200Smx205022  * callback functions for set/get of properties
15456200Smx205022  */
15466200Smx205022 static int
15476200Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
15486200Smx205022     uint_t pr_valsize, const void *pr_val)
15496200Smx205022 {
15506200Smx205022 	nge_t *ngep = barg;
15516200Smx205022 	int err = 0;
15526512Ssowmini 	uint32_t cur_mtu, new_mtu;
15536200Smx205022 	link_flowctrl_t fl;
15546200Smx205022 
15556200Smx205022 	mutex_enter(ngep->genlock);
15566200Smx205022 	if (ngep->param_loop_mode != NGE_LOOP_NONE &&
15576200Smx205022 	    nge_param_locked(pr_num)) {
15586200Smx205022 		/*
15596200Smx205022 		 * All adv_* parameters are locked (read-only)
15606200Smx205022 		 * while the device is in any sort of loopback mode.
15616200Smx205022 		 */
15626200Smx205022 		mutex_exit(ngep->genlock);
15636200Smx205022 		return (EBUSY);
15646200Smx205022 	}
15656200Smx205022 	switch (pr_num) {
15666789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15676200Smx205022 			ngep->param_en_1000fdx = *(uint8_t *)pr_val;
15686200Smx205022 			ngep->param_adv_1000fdx = *(uint8_t *)pr_val;
15696200Smx205022 			goto reprogram;
15706789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15716200Smx205022 			ngep->param_en_100fdx = *(uint8_t *)pr_val;
15726200Smx205022 			ngep->param_adv_100fdx = *(uint8_t *)pr_val;
15736200Smx205022 			goto reprogram;
15746789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15756200Smx205022 			ngep->param_en_100hdx = *(uint8_t *)pr_val;
15766200Smx205022 			ngep->param_adv_100hdx = *(uint8_t *)pr_val;
15776200Smx205022 			goto reprogram;
15786789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15796200Smx205022 			ngep->param_en_10fdx = *(uint8_t *)pr_val;
15806200Smx205022 			ngep->param_adv_10fdx = *(uint8_t *)pr_val;
15816200Smx205022 			goto reprogram;
15826789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15836200Smx205022 			ngep->param_en_10hdx = *(uint8_t *)pr_val;
15846200Smx205022 			ngep->param_adv_10hdx = *(uint8_t *)pr_val;
15856200Smx205022 reprogram:
15866200Smx205022 		(*ngep->physops->phys_update)(ngep);
15876200Smx205022 		nge_chip_sync(ngep);
15886200Smx205022 		break;
15896200Smx205022 
15906789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15916789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15926789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15936789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15946789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15956789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15966789Sam223141 		case MAC_PROP_STATUS:
15976789Sam223141 		case MAC_PROP_SPEED:
15986789Sam223141 		case MAC_PROP_DUPLEX:
15996789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
16006200Smx205022 			err = ENOTSUP; /* read-only prop. Can't set this */
16016200Smx205022 			break;
16026789Sam223141 		case MAC_PROP_AUTONEG:
16036200Smx205022 			ngep->param_adv_autoneg = *(uint8_t *)pr_val;
16046200Smx205022 			(*ngep->physops->phys_update)(ngep);
16056200Smx205022 			nge_chip_sync(ngep);
16066200Smx205022 			break;
16076789Sam223141 		case MAC_PROP_MTU:
16086200Smx205022 			cur_mtu = ngep->default_mtu;
16096200Smx205022 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
16106200Smx205022 			if (new_mtu == cur_mtu) {
16116200Smx205022 				err = 0;
16126200Smx205022 				break;
16136200Smx205022 			}
16146200Smx205022 			if (new_mtu < ETHERMTU ||
16156200Smx205022 			    new_mtu > NGE_MAX_MTU) {
16166200Smx205022 				err = EINVAL;
16176200Smx205022 				break;
16186200Smx205022 			}
16196200Smx205022 			if ((new_mtu > ETHERMTU) &&
16206200Smx205022 			    (!ngep->dev_spec_param.jumbo)) {
16216200Smx205022 				err = EINVAL;
16226200Smx205022 				break;
16236200Smx205022 			}
16246200Smx205022 			if (ngep->nge_mac_state == NGE_MAC_STARTED) {
16256200Smx205022 				err = EBUSY;
16266200Smx205022 				break;
16276200Smx205022 			}
16286200Smx205022 
16296200Smx205022 			ngep->default_mtu = new_mtu;
16306200Smx205022 			if (ngep->default_mtu > ETHERMTU &&
16316200Smx205022 			    ngep->default_mtu <= NGE_MTU_2500) {
16326200Smx205022 				ngep->buf_size = NGE_JB2500_BUFSZ;
16336200Smx205022 				ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
16346200Smx205022 				ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
16356200Smx205022 				ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
16366200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16376200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_2500 &&
16386200Smx205022 			    ngep->default_mtu <= NGE_MTU_4500) {
16396200Smx205022 				ngep->buf_size = NGE_JB4500_BUFSZ;
16406200Smx205022 				ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
16416200Smx205022 				ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
16426200Smx205022 				ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
16436200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16446200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_4500 &&
16456200Smx205022 			    ngep->default_mtu <= NGE_MAX_MTU) {
16466200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16476200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16486200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16496200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16506200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16516200Smx205022 			} else if (ngep->default_mtu > NGE_MAX_MTU) {
16526200Smx205022 				ngep->default_mtu = NGE_MAX_MTU;
16536200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16546200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16556200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16566200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16576200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16586200Smx205022 			} else if (ngep->lowmem_mode != 0) {
16596200Smx205022 				ngep->default_mtu = ETHERMTU;
16606200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16616200Smx205022 				ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
16626200Smx205022 				ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
16636200Smx205022 				ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
16646200Smx205022 				ngep->nge_split = NGE_SPLIT_32;
16656200Smx205022 			} else {
16666200Smx205022 				ngep->default_mtu = ETHERMTU;
16676200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16686200Smx205022 				ngep->tx_desc =
16696200Smx205022 				    ngep->dev_spec_param.tx_desc_num;
16706200Smx205022 				ngep->rx_desc =
16716200Smx205022 				    ngep->dev_spec_param.rx_desc_num;
16726200Smx205022 				ngep->rx_buf =
16736200Smx205022 				    ngep->dev_spec_param.rx_desc_num * 2;
16746200Smx205022 				ngep->nge_split =
16756200Smx205022 				    ngep->dev_spec_param.nge_split;
16766200Smx205022 			}
16776200Smx205022 
16786200Smx205022 			err = mac_maxsdu_update(ngep->mh, ngep->default_mtu);
16796200Smx205022 
16806200Smx205022 			break;
16816789Sam223141 		case MAC_PROP_FLOWCTRL:
16826200Smx205022 			bcopy(pr_val, &fl, sizeof (fl));
16836200Smx205022 			switch (fl) {
16846200Smx205022 			default:
16856200Smx205022 				err = ENOTSUP;
16866200Smx205022 				break;
16876200Smx205022 			case LINK_FLOWCTRL_NONE:
16886200Smx205022 				ngep->param_adv_pause = 0;
16896200Smx205022 				ngep->param_adv_asym_pause = 0;
16906200Smx205022 
16916200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
16926200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
16936200Smx205022 				break;
16946200Smx205022 			case LINK_FLOWCTRL_RX:
16956200Smx205022 				if (!((ngep->param_lp_pause == 0) &&
16966200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
16976200Smx205022 					err = EINVAL;
16986200Smx205022 					break;
16996200Smx205022 				}
17006200Smx205022 				ngep->param_adv_pause = 1;
17016200Smx205022 				ngep->param_adv_asym_pause = 1;
17026200Smx205022 
17036200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17046200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
17056200Smx205022 				break;
17066200Smx205022 			case LINK_FLOWCTRL_TX:
17076200Smx205022 				if (!((ngep->param_lp_pause == 1) &&
17086200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
17096200Smx205022 					err = EINVAL;
17106200Smx205022 					break;
17116200Smx205022 				}
17126200Smx205022 				ngep->param_adv_pause = 0;
17136200Smx205022 				ngep->param_adv_asym_pause = 1;
17146200Smx205022 
17156200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
17166200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17176200Smx205022 				break;
17186200Smx205022 			case LINK_FLOWCTRL_BI:
17196200Smx205022 				if (ngep->param_lp_pause != 1) {
17206200Smx205022 					err = EINVAL;
17216200Smx205022 					break;
17226200Smx205022 				}
17236200Smx205022 				ngep->param_adv_pause = 1;
17246200Smx205022 
17256200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17266200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17276200Smx205022 				break;
17286200Smx205022 			}
17296200Smx205022 
17306200Smx205022 			if (err == 0) {
17316200Smx205022 				(*ngep->physops->phys_update)(ngep);
17326200Smx205022 				nge_chip_sync(ngep);
17336200Smx205022 			}
17346200Smx205022 
17356200Smx205022 			break;
17366789Sam223141 		case MAC_PROP_PRIVATE:
17376200Smx205022 			err = nge_set_priv_prop(ngep, pr_name, pr_valsize,
17386200Smx205022 			    pr_val);
17396200Smx205022 			if (err == 0) {
17406200Smx205022 				(*ngep->physops->phys_update)(ngep);
17416200Smx205022 				nge_chip_sync(ngep);
17426200Smx205022 			}
17436200Smx205022 			break;
17446200Smx205022 		default:
17456200Smx205022 			err = ENOTSUP;
17466200Smx205022 	}
17476200Smx205022 	mutex_exit(ngep->genlock);
17486200Smx205022 	return (err);
17496200Smx205022 }
17506200Smx205022 
17516200Smx205022 static int
17526200Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
17538118SVasumathi.Sundaram@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
17546200Smx205022 {
17556200Smx205022 	nge_t *ngep = barg;
17566512Ssowmini 	int err = 0;
17576200Smx205022 	link_flowctrl_t fl;
17586512Ssowmini 	uint64_t speed;
17596789Sam223141 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
17606512Ssowmini 
17616512Ssowmini 	if (pr_valsize == 0)
17626512Ssowmini 		return (EINVAL);
17636200Smx205022 
17648118SVasumathi.Sundaram@Sun.COM 	*perm = MAC_PROP_PERM_RW;
17658118SVasumathi.Sundaram@Sun.COM 
17666200Smx205022 	bzero(pr_val, pr_valsize);
17678118SVasumathi.Sundaram@Sun.COM 
17686200Smx205022 	switch (pr_num) {
17696789Sam223141 		case MAC_PROP_DUPLEX:
17708118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
17716512Ssowmini 			if (pr_valsize >= sizeof (link_duplex_t)) {
17726512Ssowmini 				bcopy(&ngep->param_link_duplex, pr_val,
17736512Ssowmini 				    sizeof (link_duplex_t));
17746512Ssowmini 			} else
17756512Ssowmini 				err = EINVAL;
17766200Smx205022 			break;
17776789Sam223141 		case MAC_PROP_SPEED:
17788118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
17796200Smx205022 			if (pr_valsize >= sizeof (uint64_t)) {
17806512Ssowmini 				speed = ngep->param_link_speed * 1000000ull;
17816512Ssowmini 				bcopy(&speed, pr_val, sizeof (speed));
17826512Ssowmini 			} else
17836512Ssowmini 				err = EINVAL;
17846200Smx205022 			break;
17856789Sam223141 		case MAC_PROP_AUTONEG:
17866512Ssowmini 			if (is_default) {
17876512Ssowmini 				*(uint8_t *)pr_val = 1;
17886512Ssowmini 			} else {
17896200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_autoneg;
17906200Smx205022 			}
17916200Smx205022 			break;
17926789Sam223141 		case MAC_PROP_FLOWCTRL:
17936200Smx205022 			if (pr_valsize >= sizeof (link_flowctrl_t)) {
17946789Sam223141 				if (pr_flags & MAC_PROP_DEFAULT) {
17956512Ssowmini 					fl = LINK_FLOWCTRL_BI;
17966512Ssowmini 					bcopy(&fl, pr_val, sizeof (fl));
17976512Ssowmini 					break;
17986512Ssowmini 				}
17996200Smx205022 				if (ngep->param_link_rx_pause &&
18006200Smx205022 				    !ngep->param_link_tx_pause)
18016200Smx205022 					fl = LINK_FLOWCTRL_RX;
18026200Smx205022 
18036200Smx205022 				if (!ngep->param_link_rx_pause &&
18046200Smx205022 				    !ngep->param_link_tx_pause)
18056200Smx205022 					fl = LINK_FLOWCTRL_NONE;
18066200Smx205022 
18076200Smx205022 				if (!ngep->param_link_rx_pause &&
18086200Smx205022 				    ngep->param_link_tx_pause)
18096200Smx205022 					fl = LINK_FLOWCTRL_TX;
18106200Smx205022 
18116200Smx205022 				if (ngep->param_link_rx_pause &&
18126200Smx205022 				    ngep->param_link_tx_pause)
18136200Smx205022 					fl = LINK_FLOWCTRL_BI;
18146200Smx205022 				bcopy(&fl, pr_val, sizeof (fl));
18156512Ssowmini 			} else
18166512Ssowmini 				err = EINVAL;
18176200Smx205022 			break;
18186789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
18198118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18206512Ssowmini 			if (is_default) {
18216512Ssowmini 				*(uint8_t *)pr_val = 1;
18226512Ssowmini 			} else {
18236200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_1000fdx;
18246200Smx205022 			}
18256200Smx205022 			break;
18266789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
18276512Ssowmini 			if (is_default) {
18286512Ssowmini 				*(uint8_t *)pr_val = 1;
18296512Ssowmini 			} else {
18306200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_1000fdx;
18316200Smx205022 			}
18326200Smx205022 			break;
18336789Sam223141 		case MAC_PROP_ADV_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_adv_1000hdx;
18396200Smx205022 			}
18406200Smx205022 			break;
18416789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
18428118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18436512Ssowmini 			if (is_default) {
18446512Ssowmini 				*(uint8_t *)pr_val = 0;
18456512Ssowmini 			} else {
18466200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_1000hdx;
18476200Smx205022 			}
18486200Smx205022 			break;
18496789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
18508118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18516512Ssowmini 			if (is_default) {
18526512Ssowmini 				*(uint8_t *)pr_val = 1;
18536512Ssowmini 			} else {
18546200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_100fdx;
18556200Smx205022 			}
18566200Smx205022 			break;
18576789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
18586512Ssowmini 			if (is_default) {
18596512Ssowmini 				*(uint8_t *)pr_val = 1;
18606512Ssowmini 			} else {
18616200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_100fdx;
18626200Smx205022 			}
18636200Smx205022 			break;
18646789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
18658118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18666512Ssowmini 			if (is_default) {
18676512Ssowmini 				*(uint8_t *)pr_val = 1;
18686512Ssowmini 			} else {
18696200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_100hdx;
18706200Smx205022 			}
18716200Smx205022 			break;
18726789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
18736512Ssowmini 			if (is_default) {
18746512Ssowmini 				*(uint8_t *)pr_val = 1;
18756512Ssowmini 			} else {
18766200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_100hdx;
18776200Smx205022 			}
18786200Smx205022 			break;
18796789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
18808118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18816512Ssowmini 			if (is_default) {
18826512Ssowmini 				*(uint8_t *)pr_val = 1;
18836512Ssowmini 			} else {
18846200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_10fdx;
18856200Smx205022 			}
18866200Smx205022 			break;
18876789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
18886512Ssowmini 			if (is_default) {
18896512Ssowmini 				*(uint8_t *)pr_val = 1;
18906512Ssowmini 			} else {
18916200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_10fdx;
18926200Smx205022 			}
18936200Smx205022 			break;
18946789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
18958118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
18966512Ssowmini 			if (is_default) {
18976512Ssowmini 				*(uint8_t *)pr_val = 1;
18986512Ssowmini 			} else {
18996200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_10hdx;
19006200Smx205022 			}
19016200Smx205022 			break;
19026789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
19036512Ssowmini 			if (is_default) {
19046512Ssowmini 				*(uint8_t *)pr_val = 1;
19056512Ssowmini 			} else {
19066200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_10hdx;
19076200Smx205022 			}
19086200Smx205022 			break;
19096789Sam223141 		case MAC_PROP_ADV_100T4_CAP:
19106789Sam223141 		case MAC_PROP_EN_100T4_CAP:
19118118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
19126512Ssowmini 			*(uint8_t *)pr_val = 0;
19136512Ssowmini 			break;
19146789Sam223141 		case MAC_PROP_PRIVATE:
19156512Ssowmini 			err = nge_get_priv_prop(ngep, pr_name, pr_flags,
19166512Ssowmini 			    pr_valsize, pr_val);
19176200Smx205022 			break;
19189514SGirish.Moodalbail@Sun.COM 		case MAC_PROP_MTU: {
19199514SGirish.Moodalbail@Sun.COM 			mac_propval_range_t range;
19209514SGirish.Moodalbail@Sun.COM 
19219514SGirish.Moodalbail@Sun.COM 			if (!(pr_flags & MAC_PROP_POSSIBLE))
19229514SGirish.Moodalbail@Sun.COM 				return (ENOTSUP);
19239514SGirish.Moodalbail@Sun.COM 			if (pr_valsize < sizeof (mac_propval_range_t))
19249514SGirish.Moodalbail@Sun.COM 				return (EINVAL);
19259514SGirish.Moodalbail@Sun.COM 			range.mpr_count = 1;
19269514SGirish.Moodalbail@Sun.COM 			range.mpr_type = MAC_PROPVAL_UINT32;
19279514SGirish.Moodalbail@Sun.COM 			range.range_uint32[0].mpur_min =
19289514SGirish.Moodalbail@Sun.COM 			    range.range_uint32[0].mpur_max = ETHERMTU;
19299514SGirish.Moodalbail@Sun.COM 			if (ngep->dev_spec_param.jumbo)
19309514SGirish.Moodalbail@Sun.COM 				range.range_uint32[0].mpur_max = NGE_MAX_MTU;
19319514SGirish.Moodalbail@Sun.COM 			bcopy(&range, pr_val, sizeof (range));
19329514SGirish.Moodalbail@Sun.COM 			break;
19339514SGirish.Moodalbail@Sun.COM 		}
19346200Smx205022 		default:
19356200Smx205022 			err = ENOTSUP;
19366200Smx205022 	}
19376200Smx205022 	return (err);
19386200Smx205022 }
19396200Smx205022 
19406200Smx205022 /* ARGSUSED */
19416200Smx205022 static int
19426200Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
19436200Smx205022     const void *pr_val)
19446200Smx205022 {
19456200Smx205022 	int err = 0;
19466200Smx205022 	long result;
19476200Smx205022 
19486200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
19496200Smx205022 		if (pr_val == NULL) {
19506200Smx205022 			err = EINVAL;
19516200Smx205022 			return (err);
19526200Smx205022 		}
19536200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19546200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19556200Smx205022 			err = EINVAL;
19566200Smx205022 		} else {
19576200Smx205022 			ngep->param_txbcopy_threshold = (uint32_t)result;
19586200Smx205022 			goto reprogram;
19596200Smx205022 		}
19606200Smx205022 		return (err);
19616200Smx205022 	}
19626200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
19636200Smx205022 		if (pr_val == NULL) {
19646200Smx205022 			err = EINVAL;
19656200Smx205022 			return (err);
19666200Smx205022 		}
19676200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19686200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19696200Smx205022 			err = EINVAL;
19706200Smx205022 		} else {
19716200Smx205022 			ngep->param_rxbcopy_threshold = (uint32_t)result;
19726200Smx205022 			goto reprogram;
19736200Smx205022 		}
19746200Smx205022 		return (err);
19756200Smx205022 	}
19766200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
19776200Smx205022 		if (pr_val == NULL) {
19786200Smx205022 			err = EINVAL;
19796200Smx205022 			return (err);
19806200Smx205022 		}
19816200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19826200Smx205022 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
19836200Smx205022 			err = EINVAL;
19846200Smx205022 		} else {
19856200Smx205022 			ngep->param_recv_max_packet = (uint32_t)result;
19866200Smx205022 			goto reprogram;
19876200Smx205022 		}
19886200Smx205022 		return (err);
19896200Smx205022 	}
19906200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
19916200Smx205022 		if (pr_val == NULL) {
19926200Smx205022 			err = EINVAL;
19936200Smx205022 			return (err);
19946200Smx205022 		}
19956200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19966200Smx205022 		if (result < 0 || result > 10000) {
19976200Smx205022 			err = EINVAL;
19986200Smx205022 		} else {
19996200Smx205022 			ngep->param_poll_quiet_time = (uint32_t)result;
20006200Smx205022 			goto reprogram;
20016200Smx205022 		}
20026200Smx205022 		return (err);
20036200Smx205022 	}
20046200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
20056200Smx205022 		if (pr_val == NULL) {
20066200Smx205022 			err = EINVAL;
20076200Smx205022 			return (err);
20086200Smx205022 		}
20096200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20106200Smx205022 		if (result < 0 || result > 10000) {
20116200Smx205022 			err = EINVAL;
20126200Smx205022 		} else {
20136200Smx205022 			ngep->param_poll_busy_time = (uint32_t)result;
20146200Smx205022 			goto reprogram;
20156200Smx205022 		}
20166200Smx205022 		return (err);
20176200Smx205022 	}
20186200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
20196200Smx205022 		if (pr_val == NULL) {
20206200Smx205022 			err = EINVAL;
20216200Smx205022 			return (err);
20226200Smx205022 		}
20236200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20246512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20256200Smx205022 			err = EINVAL;
20266200Smx205022 		} else {
20276200Smx205022 			ngep->param_rx_intr_hwater = (uint32_t)result;
20286200Smx205022 			goto reprogram;
20296200Smx205022 		}
20306200Smx205022 		return (err);
20316200Smx205022 	}
20326200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
20336200Smx205022 		if (pr_val == NULL) {
20346200Smx205022 			err = EINVAL;
20356200Smx205022 			return (err);
20366200Smx205022 		}
20376200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20386512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20396200Smx205022 			err = EINVAL;
20406200Smx205022 		} else {
20416200Smx205022 			ngep->param_rx_intr_lwater = (uint32_t)result;
20426200Smx205022 			goto reprogram;
20436200Smx205022 		}
20446200Smx205022 		return (err);
20456200Smx205022 	}
20466200Smx205022 	err = ENOTSUP;
20476200Smx205022 	return (err);
20486200Smx205022 
20496200Smx205022 reprogram:
20506200Smx205022 	if (err == 0) {
20516200Smx205022 		(*ngep->physops->phys_update)(ngep);
20526200Smx205022 		nge_chip_sync(ngep);
20536200Smx205022 	}
20546200Smx205022 
20556200Smx205022 	return (err);
20566200Smx205022 }
20576200Smx205022 
20586200Smx205022 static int
20596512Ssowmini nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_flags,
20606512Ssowmini     uint_t pr_valsize, void *pr_val)
20616200Smx205022 {
20626200Smx205022 	int err = ENOTSUP;
20636789Sam223141 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
20646512Ssowmini 	int value;
20656512Ssowmini 
20666200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
20676512Ssowmini 		value = (is_default ? NGE_TX_COPY_SIZE :
20686512Ssowmini 		    ngep->param_txbcopy_threshold);
20696200Smx205022 		err = 0;
20706200Smx205022 		goto done;
20716200Smx205022 	}
20726200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
20736512Ssowmini 		value = (is_default ? NGE_RX_COPY_SIZE :
20746512Ssowmini 		    ngep->param_rxbcopy_threshold);
20756200Smx205022 		err = 0;
20766200Smx205022 		goto done;
20776200Smx205022 	}
20786200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
20796512Ssowmini 		value = (is_default ? 128 : ngep->param_recv_max_packet);
20806200Smx205022 		err = 0;
20816200Smx205022 		goto done;
20826200Smx205022 	}
20836200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
20846512Ssowmini 		value = (is_default ? NGE_POLL_QUIET_TIME :
20856512Ssowmini 		    ngep->param_poll_quiet_time);
20866200Smx205022 		err = 0;
20876200Smx205022 		goto done;
20886200Smx205022 	}
20896200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
20906512Ssowmini 		value = (is_default ? NGE_POLL_BUSY_TIME :
20916512Ssowmini 		    ngep->param_poll_busy_time);
20926200Smx205022 		err = 0;
20936200Smx205022 		goto done;
20946200Smx205022 	}
20956200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
20966512Ssowmini 		value = (is_default ? 1 : ngep->param_rx_intr_hwater);
20976200Smx205022 		err = 0;
20986200Smx205022 		goto done;
20996200Smx205022 	}
21006200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
21016512Ssowmini 		value = (is_default ? 8 : ngep->param_rx_intr_lwater);
21026200Smx205022 		err = 0;
21036200Smx205022 		goto done;
21046200Smx205022 	}
21056200Smx205022 
21066200Smx205022 done:
21076200Smx205022 	if (err == 0) {
21086512Ssowmini 		(void) snprintf(pr_val, pr_valsize, "%d", value);
21096200Smx205022 	}
21106200Smx205022 	return (err);
21116200Smx205022 }
21126200Smx205022 
21135574Smx205022 /* ARGSUSED */
21145574Smx205022 static boolean_t
21155574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
21165574Smx205022 {
21175574Smx205022 	nge_t	*ngep = arg;
21185574Smx205022 	nge_dev_spec_param_t *dev_param_p;
21195574Smx205022 
21205574Smx205022 	dev_param_p = &ngep->dev_spec_param;
21215574Smx205022 
21225574Smx205022 	switch (cap) {
21235574Smx205022 	case MAC_CAPAB_HCKSUM: {
21245574Smx205022 		uint32_t *hcksum_txflags = cap_data;
21255574Smx205022 
21265574Smx205022 		if (dev_param_p->tx_hw_checksum) {
21275574Smx205022 			*hcksum_txflags = dev_param_p->tx_hw_checksum;
21285574Smx205022 		} else
21295574Smx205022 			return (B_FALSE);
21305574Smx205022 		break;
21315574Smx205022 	}
21325574Smx205022 	default:
21335574Smx205022 		return (B_FALSE);
21345574Smx205022 	}
21355574Smx205022 	return (B_TRUE);
21365574Smx205022 }
21375574Smx205022 
21385574Smx205022 #undef	NGE_DBG
21395574Smx205022 #define	NGE_DBG	NGE_DBG_INIT	/* debug flag for this code	*/
21405574Smx205022 int
21415574Smx205022 nge_restart(nge_t *ngep)
21425574Smx205022 {
21435574Smx205022 	int err = 0;
21447656SSherry.Moore@Sun.COM 	err = nge_reset_dev(ngep);
21457155Smx205022 	/* write back the promisc setting */
21467155Smx205022 	ngep->promisc = ngep->record_promisc;
21476366Smx205022 	nge_chip_sync(ngep);
21485869Smx205022 	if (!err)
21495869Smx205022 		err = nge_chip_start(ngep);
21505574Smx205022 
21515574Smx205022 	if (err) {
21525574Smx205022 		ngep->nge_mac_state = NGE_MAC_STOPPED;
21535574Smx205022 		return (DDI_FAILURE);
21545574Smx205022 	} else {
21555574Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
21565574Smx205022 		return (DDI_SUCCESS);
21575574Smx205022 	}
21585574Smx205022 }
21595574Smx205022 
21605574Smx205022 void
21615574Smx205022 nge_wake_factotum(nge_t *ngep)
21625574Smx205022 {
21635574Smx205022 	mutex_enter(ngep->softlock);
21645574Smx205022 	if (ngep->factotum_flag == 0) {
21655574Smx205022 		ngep->factotum_flag = 1;
21665574Smx205022 		(void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
21675574Smx205022 	}
21685574Smx205022 	mutex_exit(ngep->softlock);
21695574Smx205022 }
21705574Smx205022 
2171*10615SZhen.W@Sun.COM void
2172*10615SZhen.W@Sun.COM nge_interrupt_optimize(nge_t *ngep)
2173*10615SZhen.W@Sun.COM {
2174*10615SZhen.W@Sun.COM 	uint32_t tx_pkts;
2175*10615SZhen.W@Sun.COM 	tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last;
2176*10615SZhen.W@Sun.COM 	ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count;
2177*10615SZhen.W@Sun.COM 	if ((tx_pkts > NGE_POLL_TUNE) &&
2178*10615SZhen.W@Sun.COM 	    (tx_pkts <= NGE_POLL_MAX))
2179*10615SZhen.W@Sun.COM 		ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER);
2180*10615SZhen.W@Sun.COM 	else
2181*10615SZhen.W@Sun.COM 		ngep->tfint_threshold = NGE_TFINT_DEFAULT;
2182*10615SZhen.W@Sun.COM }
2183*10615SZhen.W@Sun.COM 
21845574Smx205022 /*
21855574Smx205022  * High-level cyclic handler
21865574Smx205022  *
21875574Smx205022  * This routine schedules a (low-level) softint callback to the
21885574Smx205022  * factotum.
21895574Smx205022  */
21905574Smx205022 
21915574Smx205022 static void
21925574Smx205022 nge_chip_cyclic(void *arg)
21935574Smx205022 {
21945574Smx205022 	nge_t *ngep;
21955574Smx205022 
21965574Smx205022 	ngep = (nge_t *)arg;
21975574Smx205022 
21985574Smx205022 	switch (ngep->nge_chip_state) {
21995574Smx205022 	default:
22005574Smx205022 		return;
22015574Smx205022 
22025574Smx205022 	case NGE_CHIP_RUNNING:
2203*10615SZhen.W@Sun.COM 		nge_interrupt_optimize(ngep);
22045574Smx205022 		break;
22055574Smx205022 
22065574Smx205022 	case NGE_CHIP_FAULT:
22075574Smx205022 	case NGE_CHIP_ERROR:
22085574Smx205022 		break;
22095574Smx205022 	}
22105574Smx205022 
22115574Smx205022 	nge_wake_factotum(ngep);
22125574Smx205022 }
22135574Smx205022 
22149604SZhen.W@Sun.COM /*
22159604SZhen.W@Sun.COM  * Get/Release semaphore of SMU
22169604SZhen.W@Sun.COM  * For SMU enabled chipset
22179604SZhen.W@Sun.COM  * When nge driver is attached, driver should acquire
22189604SZhen.W@Sun.COM  * semaphore before PHY init and accessing MAC registers.
22199604SZhen.W@Sun.COM  * When nge driver is unattached, driver should release
22209604SZhen.W@Sun.COM  * semaphore.
22219604SZhen.W@Sun.COM  */
22229604SZhen.W@Sun.COM 
22239604SZhen.W@Sun.COM static int
22249604SZhen.W@Sun.COM nge_smu_sema(nge_t *ngep, boolean_t acquire)
22259604SZhen.W@Sun.COM {
22269604SZhen.W@Sun.COM 	nge_tx_en tx_en;
22279604SZhen.W@Sun.COM 	uint32_t tries;
22289604SZhen.W@Sun.COM 
22299604SZhen.W@Sun.COM 	if (acquire) {
22309604SZhen.W@Sun.COM 		for (tries = 0; tries < 5; tries++) {
22319604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
22329604SZhen.W@Sun.COM 			if (tx_en.bits.smu2mac == NGE_SMU_FREE)
22339604SZhen.W@Sun.COM 				break;
22349604SZhen.W@Sun.COM 			delay(drv_usectohz(1000000));
22359604SZhen.W@Sun.COM 		}
22369604SZhen.W@Sun.COM 		if (tx_en.bits.smu2mac != NGE_SMU_FREE)
22379604SZhen.W@Sun.COM 			return (DDI_FAILURE);
22389604SZhen.W@Sun.COM 		for (tries = 0; tries < 5; tries++) {
22399604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
22409604SZhen.W@Sun.COM 			tx_en.bits.mac2smu = NGE_SMU_GET;
22419604SZhen.W@Sun.COM 			nge_reg_put32(ngep, NGE_TX_EN, tx_en.val);
22429604SZhen.W@Sun.COM 			tx_en.val = nge_reg_get32(ngep, NGE_TX_EN);
22439604SZhen.W@Sun.COM 
22449604SZhen.W@Sun.COM 			if (tx_en.bits.mac2smu == NGE_SMU_GET &&
22459604SZhen.W@Sun.COM 			    tx_en.bits.smu2mac == NGE_SMU_FREE)
22469604SZhen.W@Sun.COM 				return (DDI_SUCCESS);
22479604SZhen.W@Sun.COM 			drv_usecwait(10);
22489604SZhen.W@Sun.COM 		}
22499604SZhen.W@Sun.COM 		return (DDI_FAILURE);
22509604SZhen.W@Sun.COM 	} else
22519604SZhen.W@Sun.COM 		nge_reg_put32(ngep, NGE_TX_EN, 0x0);
22529604SZhen.W@Sun.COM 
22539604SZhen.W@Sun.COM 	return (DDI_SUCCESS);
22549604SZhen.W@Sun.COM 
22559604SZhen.W@Sun.COM }
22565574Smx205022 static void
22575574Smx205022 nge_unattach(nge_t *ngep)
22585574Smx205022 {
22595574Smx205022 	send_ring_t *srp;
22605574Smx205022 	buff_ring_t *brp;
22615574Smx205022 
22625574Smx205022 	srp = ngep->send;
22635574Smx205022 	brp = ngep->buff;
22645574Smx205022 	NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
22655574Smx205022 
22665574Smx205022 	/*
22675574Smx205022 	 * Flag that no more activity may be initiated
22685574Smx205022 	 */
22695574Smx205022 	ngep->progress &= ~PROGRESS_READY;
22705574Smx205022 	ngep->nge_mac_state = NGE_MAC_UNATTACH;
22715574Smx205022 
22725574Smx205022 	/*
22735574Smx205022 	 * Quiesce the PHY and MAC (leave it reset but still powered).
22745574Smx205022 	 * Clean up and free all NGE data structures
22755574Smx205022 	 */
22765574Smx205022 	if (ngep->periodic_id != NULL) {
22775574Smx205022 		ddi_periodic_delete(ngep->periodic_id);
22785574Smx205022 		ngep->periodic_id = NULL;
22795574Smx205022 	}
22805574Smx205022 
22815574Smx205022 	if (ngep->progress & PROGRESS_KSTATS)
22825574Smx205022 		nge_fini_kstats(ngep);
22835574Smx205022 
22845574Smx205022 	if (ngep->progress & PROGRESS_HWINT) {
22855574Smx205022 		mutex_enter(ngep->genlock);
22865574Smx205022 		nge_restore_mac_addr(ngep);
22875574Smx205022 		(void) nge_chip_stop(ngep, B_FALSE);
22889604SZhen.W@Sun.COM 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
22899604SZhen.W@Sun.COM 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
22909604SZhen.W@Sun.COM 			(void) nge_smu_sema(ngep, B_FALSE);
22919604SZhen.W@Sun.COM 		}
22925574Smx205022 		mutex_exit(ngep->genlock);
22935574Smx205022 	}
22945574Smx205022 
22955574Smx205022 	if (ngep->progress & PROGRESS_SWINT)
22965574Smx205022 		nge_rem_intrs(ngep);
22975574Smx205022 
22985574Smx205022 	if (ngep->progress & PROGRESS_FACTOTUM)
22995574Smx205022 		(void) ddi_intr_remove_softint(ngep->factotum_hdl);
23005574Smx205022 
23015574Smx205022 	if (ngep->progress & PROGRESS_RESCHED)
23025574Smx205022 		(void) ddi_intr_remove_softint(ngep->resched_hdl);
23035574Smx205022 
23045574Smx205022 	if (ngep->progress & PROGRESS_INTR) {
23055574Smx205022 		mutex_destroy(srp->tx_lock);
23065574Smx205022 		mutex_destroy(srp->tc_lock);
23075574Smx205022 		mutex_destroy(&srp->dmah_lock);
23085574Smx205022 		mutex_destroy(brp->recycle_lock);
23095574Smx205022 
23105574Smx205022 		mutex_destroy(ngep->genlock);
23115574Smx205022 		mutex_destroy(ngep->softlock);
23125574Smx205022 		rw_destroy(ngep->rwlock);
23135574Smx205022 	}
23145574Smx205022 
23155574Smx205022 	if (ngep->progress & PROGRESS_REGS)
23165574Smx205022 		ddi_regs_map_free(&ngep->io_handle);
23175574Smx205022 
23185574Smx205022 	if (ngep->progress & PROGRESS_CFG)
23195574Smx205022 		pci_config_teardown(&ngep->cfg_handle);
23205574Smx205022 
23215574Smx205022 	ddi_remove_minor_node(ngep->devinfo, NULL);
23225574Smx205022 
23235574Smx205022 	kmem_free(ngep, sizeof (*ngep));
23245574Smx205022 }
23255574Smx205022 
23265574Smx205022 static int
23275574Smx205022 nge_resume(dev_info_t *devinfo)
23285574Smx205022 {
23295574Smx205022 	nge_t		*ngep;
23305574Smx205022 	chip_info_t	*infop;
23315869Smx205022 	int 		err;
23325574Smx205022 
23335574Smx205022 	ASSERT(devinfo != NULL);
23345574Smx205022 
23355574Smx205022 	ngep = ddi_get_driver_private(devinfo);
23365869Smx205022 	err = 0;
23375869Smx205022 
23385574Smx205022 	/*
23395574Smx205022 	 * If there are state inconsistancies, this is bad.  Returning
23405574Smx205022 	 * DDI_FAILURE here will eventually cause the machine to panic,
23415574Smx205022 	 * so it is best done here so that there is a possibility of
23425574Smx205022 	 * debugging the problem.
23435574Smx205022 	 */
23445574Smx205022 	if (ngep == NULL)
23455574Smx205022 		cmn_err(CE_PANIC,
23465574Smx205022 		    "nge: ngep returned from ddi_get_driver_private was NULL");
23475574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
23485574Smx205022 
23495574Smx205022 	if (ngep->devinfo != devinfo)
23505574Smx205022 		cmn_err(CE_PANIC,
23515869Smx205022 		    "nge: passed devinfo not the same as saved devinfo");
23525574Smx205022 
23535869Smx205022 	mutex_enter(ngep->genlock);
23545869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
23555574Smx205022 
23565574Smx205022 	/*
23575574Smx205022 	 * Fetch the config space.  Even though we have most of it cached,
23585574Smx205022 	 * some values *might* change across a suspend/resume.
23595574Smx205022 	 */
23605574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
23615574Smx205022 
23625574Smx205022 	/*
23635869Smx205022 	 * Only in one case, this conditional branch can be executed: the port
23645869Smx205022 	 * hasn't been plumbed.
23655574Smx205022 	 */
23665869Smx205022 	if (ngep->suspended == B_FALSE) {
23675869Smx205022 		rw_exit(ngep->rwlock);
23685869Smx205022 		mutex_exit(ngep->genlock);
23695869Smx205022 		return (DDI_SUCCESS);
23705869Smx205022 	}
23715869Smx205022 
23725869Smx205022 	nge_tx_recycle_all(ngep);
23735869Smx205022 	err = nge_reinit_ring(ngep);
23745869Smx205022 	if (!err) {
23755869Smx205022 		err = nge_chip_reset(ngep);
23765869Smx205022 		if (!err)
23775869Smx205022 			err = nge_chip_start(ngep);
23785869Smx205022 	}
23795869Smx205022 
23805869Smx205022 	if (err) {
23815574Smx205022 		/*
23825574Smx205022 		 * We note the failure, but return success, as the
23835574Smx205022 		 * system is still usable without this controller.
23845574Smx205022 		 */
23855574Smx205022 		cmn_err(CE_WARN, "nge: resume: failed to restart controller");
23865869Smx205022 	} else {
23875869Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
23885574Smx205022 	}
23895869Smx205022 	ngep->suspended = B_FALSE;
23905869Smx205022 
23915869Smx205022 	rw_exit(ngep->rwlock);
23925869Smx205022 	mutex_exit(ngep->genlock);
23935869Smx205022 
23945574Smx205022 	return (DDI_SUCCESS);
23955574Smx205022 }
23965574Smx205022 
23975574Smx205022 /*
23985574Smx205022  * attach(9E) -- Attach a device to the system
23995574Smx205022  *
24005574Smx205022  * Called once for each board successfully probed.
24015574Smx205022  */
24025574Smx205022 static int
24035574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
24045574Smx205022 {
24055574Smx205022 	int		err;
24065574Smx205022 	int		i;
24075574Smx205022 	int		instance;
24085574Smx205022 	caddr_t		regs;
24095574Smx205022 	nge_t		*ngep;
24105574Smx205022 	chip_info_t	*infop;
24115574Smx205022 	mac_register_t	*macp;
24125574Smx205022 
24135574Smx205022 	switch (cmd) {
24145574Smx205022 	default:
24155574Smx205022 		return (DDI_FAILURE);
24165574Smx205022 
24175574Smx205022 	case DDI_RESUME:
24185574Smx205022 		return (nge_resume(devinfo));
24195574Smx205022 
24205574Smx205022 	case DDI_ATTACH:
24215574Smx205022 		break;
24225574Smx205022 	}
24235574Smx205022 
24245574Smx205022 	ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
24255574Smx205022 	instance = ddi_get_instance(devinfo);
24265574Smx205022 	ddi_set_driver_private(devinfo, ngep);
24275574Smx205022 	ngep->devinfo = devinfo;
24285574Smx205022 
24295574Smx205022 	(void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
24305574Smx205022 	    NGE_DRIVER_NAME, instance);
24315574Smx205022 	err = pci_config_setup(devinfo, &ngep->cfg_handle);
24325574Smx205022 	if (err != DDI_SUCCESS) {
24335574Smx205022 		nge_problem(ngep, "nge_attach: pci_config_setup() failed");
24345574Smx205022 		goto attach_fail;
24355574Smx205022 	}
24366512Ssowmini 	/*
24376512Ssowmini 	 * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy
24386512Ssowmini 	 * thresholds. Bounds: min 0, max NGE_MAX_SDU
24396512Ssowmini 	 */
24406512Ssowmini 	ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE;
24416512Ssowmini 	ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE;
24426512Ssowmini 
24436512Ssowmini 	/*
24446512Ssowmini 	 * param_recv_max_packet is max packet received per interupt.
24456512Ssowmini 	 * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024
24466512Ssowmini 	 */
24476512Ssowmini 	ngep->param_recv_max_packet = 128;
24486512Ssowmini 
24496512Ssowmini 	/*
24506512Ssowmini 	 * param_poll_quiet_time and param_poll_busy_time are quiet/busy time
24516512Ssowmini 	 * switch from per packet interrupt to polling interrupt.
24526512Ssowmini 	 * Bounds: min 0, max 10000
24536512Ssowmini 	 */
24546512Ssowmini 	ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
24556512Ssowmini 	ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
2456*10615SZhen.W@Sun.COM 	ngep->tfint_threshold = NGE_TFINT_DEFAULT;
2457*10615SZhen.W@Sun.COM 	ngep->poll = B_FALSE;
2458*10615SZhen.W@Sun.COM 	ngep->ch_intr_mode = B_FALSE;
24596512Ssowmini 
24606512Ssowmini 	/*
24616512Ssowmini 	 * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
24626512Ssowmini 	 * to trigger the poll_quiet_time/poll_busy_time counter.
24636512Ssowmini 	 * Bounds: min 0, max  NGE_RECV_SLOTS_DESC_1024.
24646512Ssowmini 	 */
24656512Ssowmini 	ngep->param_rx_intr_hwater = 1;
24666512Ssowmini 	ngep->param_rx_intr_lwater = 8;
24676512Ssowmini 
24686512Ssowmini 
24695574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
24705574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
24715574Smx205022 	nge_init_dev_spec_param(ngep);
24725574Smx205022 	nge_get_props(ngep);
24735574Smx205022 	ngep->progress |= PROGRESS_CFG;
24745574Smx205022 
24755574Smx205022 	err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
24765574Smx205022 	    &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
24775574Smx205022 	if (err != DDI_SUCCESS) {
24785574Smx205022 		nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
24795574Smx205022 		goto attach_fail;
24805574Smx205022 	}
24815574Smx205022 	ngep->io_regs = regs;
24825574Smx205022 	ngep->progress |= PROGRESS_REGS;
24835574Smx205022 
24845574Smx205022 	err = nge_register_intrs_and_init_locks(ngep);
24855574Smx205022 	if (err != DDI_SUCCESS) {
24865574Smx205022 		nge_problem(ngep, "nge_attach:"
24875574Smx205022 		    " register intrs and init locks failed");
24885574Smx205022 		goto attach_fail;
24895574Smx205022 	}
24905574Smx205022 	nge_init_ring_param_lock(ngep);
24915574Smx205022 	ngep->progress |= PROGRESS_INTR;
24925574Smx205022 
24935574Smx205022 	mutex_enter(ngep->genlock);
24945574Smx205022 
24959604SZhen.W@Sun.COM 	if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
24969604SZhen.W@Sun.COM 	    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
24979604SZhen.W@Sun.COM 		err = nge_smu_sema(ngep, B_TRUE);
24989604SZhen.W@Sun.COM 		if (err != DDI_SUCCESS) {
24999604SZhen.W@Sun.COM 			nge_problem(ngep, "nge_attach: nge_smu_sema() failed");
25009604SZhen.W@Sun.COM 			goto attach_fail;
25019604SZhen.W@Sun.COM 		}
25029604SZhen.W@Sun.COM 	}
25035574Smx205022 	/*
25045574Smx205022 	 * Initialise link state variables
25055574Smx205022 	 * Stop, reset & reinitialise the chip.
25065574Smx205022 	 * Initialise the (internal) PHY.
25075574Smx205022 	 */
25085574Smx205022 	nge_phys_init(ngep);
25098218SMin.Xu@Sun.COM 	ngep->nge_chip_state = NGE_CHIP_INITIAL;
25105574Smx205022 	err = nge_chip_reset(ngep);
25115574Smx205022 	if (err != DDI_SUCCESS) {
25125574Smx205022 		nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
25135574Smx205022 		mutex_exit(ngep->genlock);
25145574Smx205022 		goto attach_fail;
25155574Smx205022 	}
25165574Smx205022 	nge_chip_sync(ngep);
25175574Smx205022 
25185574Smx205022 	/*
25195574Smx205022 	 * Now that mutex locks are initialized, enable interrupts.
25205574Smx205022 	 */
25215574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
25225574Smx205022 		/* Call ddi_intr_block_enable() for MSI interrupts */
25235574Smx205022 		(void) ddi_intr_block_enable(ngep->htable,
25245574Smx205022 		    ngep->intr_actual_cnt);
25255574Smx205022 	} else {
25265574Smx205022 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
25275574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
25285574Smx205022 			(void) ddi_intr_enable(ngep->htable[i]);
25295574Smx205022 		}
25305574Smx205022 	}
25315574Smx205022 
25325574Smx205022 	ngep->link_state = LINK_STATE_UNKNOWN;
25335574Smx205022 	ngep->progress |= PROGRESS_HWINT;
25345574Smx205022 
25355574Smx205022 	/*
25365574Smx205022 	 * Register NDD-tweakable parameters
25375574Smx205022 	 */
25385574Smx205022 	if (nge_nd_init(ngep)) {
25395574Smx205022 		nge_problem(ngep, "nge_attach: nge_nd_init() failed");
25405574Smx205022 		mutex_exit(ngep->genlock);
25415574Smx205022 		goto attach_fail;
25425574Smx205022 	}
25435574Smx205022 	ngep->progress |= PROGRESS_NDD;
25445574Smx205022 
25455574Smx205022 	/*
25465574Smx205022 	 * Create & initialise named kstats
25475574Smx205022 	 */
25485574Smx205022 	nge_init_kstats(ngep, instance);
25495574Smx205022 	ngep->progress |= PROGRESS_KSTATS;
25505574Smx205022 
25515574Smx205022 	mutex_exit(ngep->genlock);
25525574Smx205022 
25535574Smx205022 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
25545574Smx205022 		goto attach_fail;
25555574Smx205022 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
25565574Smx205022 	macp->m_driver = ngep;
25575574Smx205022 	macp->m_dip = devinfo;
25585574Smx205022 	macp->m_src_addr = infop->vendor_addr.addr;
25595574Smx205022 	macp->m_callbacks = &nge_m_callbacks;
25605574Smx205022 	macp->m_min_sdu = 0;
25615574Smx205022 	macp->m_max_sdu = ngep->default_mtu;
25625895Syz147064 	macp->m_margin = VTAG_SIZE;
25636512Ssowmini 	macp->m_priv_props = nge_priv_props;
25646512Ssowmini 	macp->m_priv_prop_count = NGE_MAX_PRIV_PROPS;
25655574Smx205022 	/*
25665574Smx205022 	 * Finally, we're ready to register ourselves with the mac
25675574Smx205022 	 * interface; if this succeeds, we're all ready to start()
25685574Smx205022 	 */
25695574Smx205022 	err = mac_register(macp, &ngep->mh);
25705574Smx205022 	mac_free(macp);
25715574Smx205022 	if (err != 0)
25725574Smx205022 		goto attach_fail;
25735574Smx205022 
25745574Smx205022 	/*
25755574Smx205022 	 * Register a periodical handler.
25765574Smx205022 	 * nge_chip_cyclic() is invoked in kernel context.
25775574Smx205022 	 */
25785574Smx205022 	ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
25795574Smx205022 	    NGE_CYCLIC_PERIOD, DDI_IPL_0);
25805574Smx205022 
25815574Smx205022 	ngep->progress |= PROGRESS_READY;
25825574Smx205022 	return (DDI_SUCCESS);
25835574Smx205022 
25845574Smx205022 attach_fail:
25855574Smx205022 	nge_unattach(ngep);
25865574Smx205022 	return (DDI_FAILURE);
25875574Smx205022 }
25885574Smx205022 
25895869Smx205022 static int
25905869Smx205022 nge_suspend(nge_t *ngep)
25915869Smx205022 {
25925869Smx205022 	mutex_enter(ngep->genlock);
25935869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
25945869Smx205022 
25955869Smx205022 	/* if the port hasn't been plumbed, just return */
25965869Smx205022 	if (ngep->nge_mac_state != NGE_MAC_STARTED) {
25975869Smx205022 		rw_exit(ngep->rwlock);
25985869Smx205022 		mutex_exit(ngep->genlock);
25995869Smx205022 		return (DDI_SUCCESS);
26005869Smx205022 	}
26015869Smx205022 	ngep->suspended = B_TRUE;
26025869Smx205022 	(void) nge_chip_stop(ngep, B_FALSE);
26035869Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
26045869Smx205022 
26055869Smx205022 	rw_exit(ngep->rwlock);
26065869Smx205022 	mutex_exit(ngep->genlock);
26075869Smx205022 	return (DDI_SUCCESS);
26085869Smx205022 }
26095869Smx205022 
26105574Smx205022 /*
26115574Smx205022  * detach(9E) -- Detach a device from the system
26125574Smx205022  */
26135574Smx205022 static int
26145574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
26155574Smx205022 {
26165574Smx205022 	int i;
26175574Smx205022 	nge_t *ngep;
26185574Smx205022 	mul_item *p, *nextp;
26195574Smx205022 	buff_ring_t *brp;
26205574Smx205022 
26215574Smx205022 	NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
26225574Smx205022 
26235574Smx205022 	ngep = ddi_get_driver_private(devinfo);
26245574Smx205022 	brp = ngep->buff;
26255574Smx205022 
26265574Smx205022 	switch (cmd) {
26275574Smx205022 	default:
26285574Smx205022 		return (DDI_FAILURE);
26295574Smx205022 
26305574Smx205022 	case DDI_SUSPEND:
26315574Smx205022 		/*
26325574Smx205022 		 * Stop the NIC
26335574Smx205022 		 * Note: This driver doesn't currently support WOL, but
26345574Smx205022 		 *	should it in the future, it is important to
26355574Smx205022 		 *	make sure the PHY remains powered so that the
26365574Smx205022 		 *	wakeup packet can actually be recieved.
26375574Smx205022 		 */
26385869Smx205022 		return (nge_suspend(ngep));
26395574Smx205022 
26405574Smx205022 	case DDI_DETACH:
26415574Smx205022 		break;
26425574Smx205022 	}
26435574Smx205022 
26445574Smx205022 	/* Try to wait all the buffer post to upper layer be released */
26455574Smx205022 	for (i = 0; i < 1000; i++) {
26465574Smx205022 		if (brp->rx_hold == 0)
26475574Smx205022 			break;
26485574Smx205022 		drv_usecwait(1000);
26495574Smx205022 	}
26505574Smx205022 
26515574Smx205022 	/* If there is any posted buffer, reject to detach */
26525574Smx205022 	if (brp->rx_hold != 0)
26535574Smx205022 		return (DDI_FAILURE);
26545574Smx205022 
26555574Smx205022 	/*
26565574Smx205022 	 * Unregister from the GLD subsystem.  This can fail, in
26575574Smx205022 	 * particular if there are DLPI style-2 streams still open -
26585574Smx205022 	 * in which case we just return failure without shutting
26595574Smx205022 	 * down chip operations.
26605574Smx205022 	 */
26615574Smx205022 	if (mac_unregister(ngep->mh) != DDI_SUCCESS)
26625574Smx205022 		return (DDI_FAILURE);
26635574Smx205022 
26645574Smx205022 	/*
26656366Smx205022 	 * Recycle the multicast table. mac_unregister() should be called
26666366Smx205022 	 * before it to ensure the multicast table can be used even if
26676366Smx205022 	 * mac_unregister() fails.
26686366Smx205022 	 */
26696366Smx205022 	for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
26706366Smx205022 		nextp = p->next;
26716366Smx205022 		kmem_free(p, sizeof (mul_item));
26726366Smx205022 	}
26736366Smx205022 	ngep->pcur_mulist = NULL;
26746366Smx205022 
26756366Smx205022 	/*
26765574Smx205022 	 * All activity stopped, so we can clean up & exit
26775574Smx205022 	 */
26785574Smx205022 	nge_unattach(ngep);
26795574Smx205022 	return (DDI_SUCCESS);
26805574Smx205022 }
26815574Smx205022 
26827656SSherry.Moore@Sun.COM /*
26837656SSherry.Moore@Sun.COM  * quiesce(9E) entry point.
26847656SSherry.Moore@Sun.COM  *
26857656SSherry.Moore@Sun.COM  * This function is called when the system is single-threaded at high
26867656SSherry.Moore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
26877656SSherry.Moore@Sun.COM  * blocked.
26887656SSherry.Moore@Sun.COM  *
26897656SSherry.Moore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
26907656SSherry.Moore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
26917656SSherry.Moore@Sun.COM  */
26927656SSherry.Moore@Sun.COM static int
26937656SSherry.Moore@Sun.COM nge_quiesce(dev_info_t *devinfo)
26947656SSherry.Moore@Sun.COM {
26957656SSherry.Moore@Sun.COM 	nge_t *ngep;
26967656SSherry.Moore@Sun.COM 
26977656SSherry.Moore@Sun.COM 	ngep = ddi_get_driver_private(devinfo);
26987656SSherry.Moore@Sun.COM 
26997656SSherry.Moore@Sun.COM 	if (ngep == NULL)
27007656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
27017656SSherry.Moore@Sun.COM 
27027656SSherry.Moore@Sun.COM 	/*
27037656SSherry.Moore@Sun.COM 	 * Turn off debug tracing
27047656SSherry.Moore@Sun.COM 	 */
27057656SSherry.Moore@Sun.COM 	nge_debug = 0;
27067656SSherry.Moore@Sun.COM 	ngep->debug = 0;
27077656SSherry.Moore@Sun.COM 
27087656SSherry.Moore@Sun.COM 	nge_restore_mac_addr(ngep);
27097656SSherry.Moore@Sun.COM 	(void) nge_chip_stop(ngep, B_FALSE);
27107656SSherry.Moore@Sun.COM 
27117656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
27127656SSherry.Moore@Sun.COM }
27137656SSherry.Moore@Sun.COM 
27147656SSherry.Moore@Sun.COM 
27155574Smx205022 
27165574Smx205022 /*
27175574Smx205022  * ========== Module Loading Data & Entry Points ==========
27185574Smx205022  */
27195574Smx205022 
27205574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
27217656SSherry.Moore@Sun.COM     NULL, NULL, D_MP, NULL, nge_quiesce);
27225574Smx205022 
27235574Smx205022 
27245574Smx205022 static struct modldrv nge_modldrv = {
27255574Smx205022 	&mod_driverops,		/* Type of module.  This one is a driver */
27265574Smx205022 	nge_ident,		/* short description */
27275574Smx205022 	&nge_dev_ops		/* driver specific ops */
27285574Smx205022 };
27295574Smx205022 
27305574Smx205022 static struct modlinkage modlinkage = {
27315574Smx205022 	MODREV_1, (void *)&nge_modldrv, NULL
27325574Smx205022 };
27335574Smx205022 
27345574Smx205022 
27355574Smx205022 int
27365574Smx205022 _info(struct modinfo *modinfop)
27375574Smx205022 {
27385574Smx205022 	return (mod_info(&modlinkage, modinfop));
27395574Smx205022 }
27405574Smx205022 
27415574Smx205022 int
27425574Smx205022 _init(void)
27435574Smx205022 {
27445574Smx205022 	int status;
27455574Smx205022 
27465574Smx205022 	mac_init_ops(&nge_dev_ops, "nge");
27475574Smx205022 	status = mod_install(&modlinkage);
27485574Smx205022 	if (status != DDI_SUCCESS)
27495574Smx205022 		mac_fini_ops(&nge_dev_ops);
27505574Smx205022 	else
27515574Smx205022 		mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
27525574Smx205022 
27535574Smx205022 	return (status);
27545574Smx205022 }
27555574Smx205022 
27565574Smx205022 int
27575574Smx205022 _fini(void)
27585574Smx205022 {
27595574Smx205022 	int status;
27605574Smx205022 
27615574Smx205022 	status = mod_remove(&modlinkage);
27625574Smx205022 	if (status == DDI_SUCCESS) {
27635574Smx205022 		mac_fini_ops(&nge_dev_ops);
27645574Smx205022 		mutex_destroy(nge_log_mutex);
27655574Smx205022 	}
27665574Smx205022 
27675574Smx205022 	return (status);
27685574Smx205022 }
27695574Smx205022 
27705574Smx205022 /*
27715574Smx205022  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
27725574Smx205022  */
27735574Smx205022 
27745574Smx205022 /*
27755574Smx205022  * Register interrupts and initialize each mutex and condition variables
27765574Smx205022  */
27775574Smx205022 
27785574Smx205022 static int
27795574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep)
27805574Smx205022 {
27815574Smx205022 	int		err;
27825574Smx205022 	int		intr_types;
27835574Smx205022 	uint_t		soft_prip;
27845574Smx205022 	nge_msi_mask	msi_mask;
27855574Smx205022 	nge_msi_map0_vec map0_vec;
27865574Smx205022 	nge_msi_map1_vec map1_vec;
27875574Smx205022 
27885574Smx205022 	/*
27895574Smx205022 	 * Add the softint handlers:
27905574Smx205022 	 *
27915574Smx205022 	 * Both of these handlers are used to avoid restrictions on the
27925574Smx205022 	 * context and/or mutexes required for some operations.  In
27935574Smx205022 	 * particular, the hardware interrupt handler and its subfunctions
27945574Smx205022 	 * can detect a number of conditions that we don't want to handle
27955574Smx205022 	 * in that context or with that set of mutexes held.  So, these
27965574Smx205022 	 * softints are triggered instead:
27975574Smx205022 	 *
27985574Smx205022 	 * the <resched> softint is triggered if if we have previously
27995574Smx205022 	 * had to refuse to send a packet because of resource shortage
28005574Smx205022 	 * (we've run out of transmit buffers), but the send completion
28015574Smx205022 	 * interrupt handler has now detected that more buffers have
28025574Smx205022 	 * become available.  Its only purpose is to call gld_sched()
28035574Smx205022 	 * to retry the pending transmits (we're not allowed to hold
28045574Smx205022 	 * driver-defined mutexes across gld_sched()).
28055574Smx205022 	 *
28065574Smx205022 	 * the <factotum> is triggered if the h/w interrupt handler
28075574Smx205022 	 * sees the <link state changed> or <error> bits in the status
28085574Smx205022 	 * block.  It's also triggered periodically to poll the link
28095574Smx205022 	 * state, just in case we aren't getting link status change
28105574Smx205022 	 * interrupts ...
28115574Smx205022 	 */
28125574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
28135574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
28145574Smx205022 	if (err != DDI_SUCCESS) {
28155574Smx205022 		nge_problem(ngep,
28165574Smx205022 		    "nge_attach: add nge_reschedule softintr failed");
28175574Smx205022 
28185574Smx205022 		return (DDI_FAILURE);
28195574Smx205022 	}
28205574Smx205022 	ngep->progress |= PROGRESS_RESCHED;
28215574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
28225574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
28235574Smx205022 	if (err != DDI_SUCCESS) {
28245574Smx205022 		nge_problem(ngep,
28255574Smx205022 		    "nge_attach: add nge_chip_factotum softintr failed!");
28265574Smx205022 
28275574Smx205022 		return (DDI_FAILURE);
28285574Smx205022 	}
28295574Smx205022 	if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
28305574Smx205022 	    != DDI_SUCCESS) {
28315574Smx205022 		nge_problem(ngep, "nge_attach: get softintr priority failed\n");
28325574Smx205022 
28335574Smx205022 		return (DDI_FAILURE);
28345574Smx205022 	}
28355574Smx205022 	ngep->soft_pri = soft_prip;
28365574Smx205022 
28375574Smx205022 	ngep->progress |= PROGRESS_FACTOTUM;
28385574Smx205022 	/* Get supported interrupt types */
28395574Smx205022 	if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
28405574Smx205022 	    != DDI_SUCCESS) {
28415574Smx205022 		nge_error(ngep, "ddi_intr_get_supported_types failed\n");
28425574Smx205022 
28435574Smx205022 		return (DDI_FAILURE);
28445574Smx205022 	}
28455574Smx205022 
28465574Smx205022 	NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
28475574Smx205022 	    intr_types));
28485574Smx205022 
28495574Smx205022 	if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
28505574Smx205022 
28515574Smx205022 		/* MSI Configurations for mcp55 chipset */
28525574Smx205022 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
28535574Smx205022 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
28545574Smx205022 
28555574Smx205022 
28565574Smx205022 			/* Enable the 8 vectors */
28575574Smx205022 			msi_mask.msi_mask_val =
28585574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MASK);
28595574Smx205022 			msi_mask.msi_msk_bits.vec0 = NGE_SET;
28605574Smx205022 			msi_mask.msi_msk_bits.vec1 = NGE_SET;
28615574Smx205022 			msi_mask.msi_msk_bits.vec2 = NGE_SET;
28625574Smx205022 			msi_mask.msi_msk_bits.vec3 = NGE_SET;
28635574Smx205022 			msi_mask.msi_msk_bits.vec4 = NGE_SET;
28645574Smx205022 			msi_mask.msi_msk_bits.vec5 = NGE_SET;
28655574Smx205022 			msi_mask.msi_msk_bits.vec6 = NGE_SET;
28665574Smx205022 			msi_mask.msi_msk_bits.vec7 = NGE_SET;
28675574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MASK,
28685574Smx205022 			    msi_mask.msi_mask_val);
28695574Smx205022 
28705574Smx205022 			/*
28715574Smx205022 			 * Remapping the MSI MAP0 and MAP1. MCP55
28725574Smx205022 			 * is default mapping all the interrupt to 0 vector.
28735574Smx205022 			 * Software needs to remapping this.
28745574Smx205022 			 * This mapping is same as CK804.
28755574Smx205022 			 */
28765574Smx205022 			map0_vec.msi_map0_val =
28775574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP0);
28785574Smx205022 			map1_vec.msi_map1_val =
28795574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP1);
28805574Smx205022 			map0_vec.vecs_bits.reint_vec = 0;
28815574Smx205022 			map0_vec.vecs_bits.rcint_vec = 0;
28825574Smx205022 			map0_vec.vecs_bits.miss_vec = 3;
28835574Smx205022 			map0_vec.vecs_bits.teint_vec = 5;
28845574Smx205022 			map0_vec.vecs_bits.tcint_vec = 5;
28855574Smx205022 			map0_vec.vecs_bits.stint_vec = 2;
28865574Smx205022 			map0_vec.vecs_bits.mint_vec = 6;
28875574Smx205022 			map0_vec.vecs_bits.rfint_vec = 0;
28885574Smx205022 			map1_vec.vecs_bits.tfint_vec = 5;
28895574Smx205022 			map1_vec.vecs_bits.feint_vec = 6;
28905574Smx205022 			map1_vec.vecs_bits.resv8_11 = 3;
28915574Smx205022 			map1_vec.vecs_bits.resv12_15 = 1;
28925574Smx205022 			map1_vec.vecs_bits.resv16_19 = 0;
28935574Smx205022 			map1_vec.vecs_bits.resv20_23 = 7;
28945574Smx205022 			map1_vec.vecs_bits.resv24_31 = 0xff;
28955574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP0,
28965574Smx205022 			    map0_vec.msi_map0_val);
28975574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP1,
28985574Smx205022 			    map1_vec.msi_map1_val);
28995574Smx205022 		}
29005574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
29015574Smx205022 			NGE_DEBUG(("MSI registration failed, "
29025574Smx205022 			    "trying FIXED interrupt type\n"));
29035574Smx205022 		} else {
29045574Smx205022 			nge_log(ngep, "Using MSI interrupt type\n");
29055574Smx205022 
29065574Smx205022 			ngep->intr_type = DDI_INTR_TYPE_MSI;
29075574Smx205022 			ngep->progress |= PROGRESS_SWINT;
29085574Smx205022 		}
29095574Smx205022 	}
29105574Smx205022 
29115574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT) &&
29125574Smx205022 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
29135574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
29145574Smx205022 			nge_error(ngep, "FIXED interrupt "
29155574Smx205022 			    "registration failed\n");
29165574Smx205022 
29175574Smx205022 			return (DDI_FAILURE);
29185574Smx205022 		}
29195574Smx205022 
29205574Smx205022 		nge_log(ngep, "Using FIXED interrupt type\n");
29215574Smx205022 
29225574Smx205022 		ngep->intr_type = DDI_INTR_TYPE_FIXED;
29235574Smx205022 		ngep->progress |= PROGRESS_SWINT;
29245574Smx205022 	}
29255574Smx205022 
29265574Smx205022 
29275574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT)) {
29285574Smx205022 		nge_error(ngep, "No interrupts registered\n");
29295574Smx205022 
29305574Smx205022 		return (DDI_FAILURE);
29315574Smx205022 	}
29325574Smx205022 	mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
29335574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29345574Smx205022 	mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
29355574Smx205022 	    DDI_INTR_PRI(ngep->soft_pri));
29365574Smx205022 	rw_init(ngep->rwlock, NULL, RW_DRIVER,
29375574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
29385574Smx205022 
29395574Smx205022 	return (DDI_SUCCESS);
29405574Smx205022 }
29415574Smx205022 
29425574Smx205022 /*
29435574Smx205022  * nge_add_intrs:
29445574Smx205022  *
29455574Smx205022  * Register FIXED or MSI interrupts.
29465574Smx205022  */
29475574Smx205022 static int
29485574Smx205022 nge_add_intrs(nge_t *ngep, int	intr_type)
29495574Smx205022 {
29505574Smx205022 	dev_info_t	*dip = ngep->devinfo;
29515574Smx205022 	int		avail, actual, intr_size, count = 0;
29525574Smx205022 	int		i, flag, ret;
29535574Smx205022 
29545574Smx205022 	NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
29555574Smx205022 
29565574Smx205022 	/* Get number of interrupts */
29575574Smx205022 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
29585574Smx205022 	if ((ret != DDI_SUCCESS) || (count == 0)) {
29595574Smx205022 		nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
29605574Smx205022 		    "count: %d", ret, count);
29615574Smx205022 
29625574Smx205022 		return (DDI_FAILURE);
29635574Smx205022 	}
29645574Smx205022 
29655574Smx205022 	/* Get number of available interrupts */
29665574Smx205022 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
29675574Smx205022 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
29685574Smx205022 		nge_error(ngep, "ddi_intr_get_navail() failure, "
29695574Smx205022 		    "ret: %d, avail: %d\n", ret, avail);
29705574Smx205022 
29715574Smx205022 		return (DDI_FAILURE);
29725574Smx205022 	}
29735574Smx205022 
29745574Smx205022 	if (avail < count) {
29755574Smx205022 		NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
29765574Smx205022 		    count, avail));
29775574Smx205022 	}
29785574Smx205022 	flag = DDI_INTR_ALLOC_NORMAL;
29795574Smx205022 
29805574Smx205022 	/* Allocate an array of interrupt handles */
29815574Smx205022 	intr_size = count * sizeof (ddi_intr_handle_t);
29825574Smx205022 	ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
29835574Smx205022 
29845574Smx205022 	/* Call ddi_intr_alloc() */
29855574Smx205022 	ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
29865574Smx205022 	    count, &actual, flag);
29875574Smx205022 
29885574Smx205022 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
29895574Smx205022 		nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
29905574Smx205022 
29915574Smx205022 		kmem_free(ngep->htable, intr_size);
29925574Smx205022 		return (DDI_FAILURE);
29935574Smx205022 	}
29945574Smx205022 
29955574Smx205022 	if (actual < count) {
29965574Smx205022 		NGE_DEBUG(("Requested: %d, Received: %d\n",
29975574Smx205022 		    count, actual));
29985574Smx205022 	}
29995574Smx205022 
30005574Smx205022 	ngep->intr_actual_cnt = actual;
30015574Smx205022 	ngep->intr_req_cnt = count;
30025574Smx205022 
30035574Smx205022 	/*
30045574Smx205022 	 * Get priority for first msi, assume remaining are all the same
30055574Smx205022 	 */
30065574Smx205022 	if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
30075574Smx205022 	    DDI_SUCCESS) {
30085574Smx205022 		nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
30095574Smx205022 
30105574Smx205022 		/* Free already allocated intr */
30115574Smx205022 		for (i = 0; i < actual; i++) {
30125574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
30135574Smx205022 		}
30145574Smx205022 
30155574Smx205022 		kmem_free(ngep->htable, intr_size);
30165574Smx205022 
30175574Smx205022 		return (DDI_FAILURE);
30185574Smx205022 	}
30195574Smx205022 	/* Test for high level mutex */
30205574Smx205022 	if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
30215574Smx205022 		nge_error(ngep, "nge_add_intrs:"
30225574Smx205022 		    "Hi level interrupt not supported");
30235574Smx205022 
30245574Smx205022 		for (i = 0; i < actual; i++)
30255574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
30265574Smx205022 
30275574Smx205022 		kmem_free(ngep->htable, intr_size);
30285574Smx205022 
30295574Smx205022 		return (DDI_FAILURE);
30305574Smx205022 	}
30315574Smx205022 
30325574Smx205022 
30335574Smx205022 	/* Call ddi_intr_add_handler() */
30345574Smx205022 	for (i = 0; i < actual; i++) {
30355574Smx205022 		if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
30365574Smx205022 		    (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
30375574Smx205022 			nge_error(ngep, "ddi_intr_add_handler() "
30385574Smx205022 			    "failed %d\n", ret);
30395574Smx205022 
30405574Smx205022 			/* Free already allocated intr */
30415574Smx205022 			for (i = 0; i < actual; i++) {
30425574Smx205022 				(void) ddi_intr_free(ngep->htable[i]);
30435574Smx205022 			}
30445574Smx205022 
30455574Smx205022 			kmem_free(ngep->htable, intr_size);
30465574Smx205022 
30475574Smx205022 			return (DDI_FAILURE);
30485574Smx205022 		}
30495574Smx205022 	}
30505574Smx205022 
30515574Smx205022 	if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
30525574Smx205022 	    != DDI_SUCCESS) {
30535574Smx205022 		nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
30545574Smx205022 
30555574Smx205022 		for (i = 0; i < actual; i++) {
30565574Smx205022 			(void) ddi_intr_remove_handler(ngep->htable[i]);
30575574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
30585574Smx205022 		}
30595574Smx205022 
30605574Smx205022 		kmem_free(ngep->htable, intr_size);
30615574Smx205022 
30625574Smx205022 		return (DDI_FAILURE);
30635574Smx205022 	}
30645574Smx205022 
30655574Smx205022 	return (DDI_SUCCESS);
30665574Smx205022 }
30675574Smx205022 
30685574Smx205022 /*
30695574Smx205022  * nge_rem_intrs:
30705574Smx205022  *
30715574Smx205022  * Unregister FIXED or MSI interrupts
30725574Smx205022  */
30735574Smx205022 static void
30745574Smx205022 nge_rem_intrs(nge_t *ngep)
30755574Smx205022 {
30765574Smx205022 	int	i;
30775574Smx205022 
30785574Smx205022 	NGE_DEBUG(("nge_rem_intrs\n"));
30795574Smx205022 
30805574Smx205022 	/* Disable all interrupts */
30815574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
30825574Smx205022 		/* Call ddi_intr_block_disable() */
30835574Smx205022 		(void) ddi_intr_block_disable(ngep->htable,
30845574Smx205022 		    ngep->intr_actual_cnt);
30855574Smx205022 	} else {
30865574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
30875574Smx205022 			(void) ddi_intr_disable(ngep->htable[i]);
30885574Smx205022 		}
30895574Smx205022 	}
30905574Smx205022 
30915574Smx205022 	/* Call ddi_intr_remove_handler() */
30925574Smx205022 	for (i = 0; i < ngep->intr_actual_cnt; i++) {
30935574Smx205022 		(void) ddi_intr_remove_handler(ngep->htable[i]);
30945574Smx205022 		(void) ddi_intr_free(ngep->htable[i]);
30955574Smx205022 	}
30965574Smx205022 
30975574Smx205022 	kmem_free(ngep->htable,
30985574Smx205022 	    ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
30995574Smx205022 }
3100