xref: /onnv-gate/usr/src/uts/common/io/nge/nge_main.c (revision 7155:1515c6a3e4b0)
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 /*
235869Smx205022  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245574Smx205022  * Use is subject to license terms.
255574Smx205022  */
265574Smx205022 
275574Smx205022 #pragma ident	"%Z%%M%	%I%	%E% SMI"
285574Smx205022 
295574Smx205022 #include "nge.h"
305574Smx205022 
315574Smx205022 /*
325574Smx205022  * Describes the chip's DMA engine
335574Smx205022  */
345574Smx205022 
355574Smx205022 static ddi_dma_attr_t hot_dma_attr = {
365574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
375574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
385574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
395574Smx205022 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
405574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
415574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
425574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
435574Smx205022 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
445574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
455574Smx205022 	1,				/* dma_attr_sgllen 	*/
465574Smx205022 	0x00000001,			/* dma_attr_granular 	*/
475574Smx205022 	0
485574Smx205022 };
495574Smx205022 
505574Smx205022 static ddi_dma_attr_t hot_tx_dma_attr = {
515574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
525574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
535574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_addr_hi	*/
545574Smx205022 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
555574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
565574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
575574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
585574Smx205022 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
595574Smx205022 	0x000000FFFFFFFFFFull,		/* dma_attr_seg		*/
605574Smx205022 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
615574Smx205022 	1,				/* dma_attr_granular 	*/
625574Smx205022 	0
635574Smx205022 };
645574Smx205022 
655574Smx205022 static ddi_dma_attr_t sum_dma_attr = {
665574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
675574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
685574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
695574Smx205022 	0x000000007FFFFFFFull,		/* dma_attr_count_max	*/
705574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
715574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
725574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
735574Smx205022 	0x000000000000FFFFull,		/* dma_attr_maxxfer	*/
745574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
755574Smx205022 	1,				/* dma_attr_sgllen 	*/
765574Smx205022 	0x00000001,			/* dma_attr_granular 	*/
775574Smx205022 	0
785574Smx205022 };
795574Smx205022 
805574Smx205022 static ddi_dma_attr_t sum_tx_dma_attr = {
815574Smx205022 	DMA_ATTR_V0,			/* dma_attr version	*/
825574Smx205022 	0x0000000000000000ull,		/* dma_attr_addr_lo	*/
835574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_addr_hi	*/
845574Smx205022 	0x0000000000003FFFull,		/* dma_attr_count_max	*/
855574Smx205022 	0x0000000000000010ull,		/* dma_attr_align	*/
865574Smx205022 	0x00000FFF,			/* dma_attr_burstsizes	*/
875574Smx205022 	0x00000001,			/* dma_attr_minxfer	*/
885574Smx205022 	0x0000000000003FFFull,		/* dma_attr_maxxfer	*/
895574Smx205022 	0x00000000FFFFFFFFull,		/* dma_attr_seg		*/
905574Smx205022 	NGE_MAX_COOKIES,		/* dma_attr_sgllen 	*/
915574Smx205022 	1,				/* dma_attr_granular 	*/
925574Smx205022 	0
935574Smx205022 };
945574Smx205022 
955574Smx205022 /*
965574Smx205022  * DMA access attributes for data.
975574Smx205022  */
985574Smx205022 ddi_device_acc_attr_t nge_data_accattr = {
995574Smx205022 	DDI_DEVICE_ATTR_V0,
1005574Smx205022 	DDI_STRUCTURE_LE_ACC,
1015574Smx205022 	DDI_STRICTORDER_ACC,
1025574Smx205022 	DDI_DEFAULT_ACC
1035574Smx205022 };
1045574Smx205022 
1055574Smx205022 /*
1065574Smx205022  * DMA access attributes for descriptors.
1075574Smx205022  */
1085574Smx205022 static ddi_device_acc_attr_t nge_desc_accattr = {
1095574Smx205022 	DDI_DEVICE_ATTR_V0,
1105574Smx205022 	DDI_STRUCTURE_LE_ACC,
1115574Smx205022 	DDI_STRICTORDER_ACC,
1125574Smx205022 	DDI_DEFAULT_ACC
1135574Smx205022 };
1145574Smx205022 
1155574Smx205022 /*
1165574Smx205022  * PIO access attributes for registers
1175574Smx205022  */
1185574Smx205022 static ddi_device_acc_attr_t nge_reg_accattr = {
1195574Smx205022 	DDI_DEVICE_ATTR_V0,
1205574Smx205022 	DDI_STRUCTURE_LE_ACC,
1215574Smx205022 	DDI_STRICTORDER_ACC,
1225574Smx205022 	DDI_DEFAULT_ACC
1235574Smx205022 };
1245574Smx205022 
1255574Smx205022 /*
1265574Smx205022  * NIC DESC MODE 2
1275574Smx205022  */
1285574Smx205022 
1295574Smx205022 static const nge_desc_attr_t nge_sum_desc = {
1305574Smx205022 
1315574Smx205022 	sizeof (sum_rx_bd),
1325574Smx205022 	sizeof (sum_tx_bd),
1335574Smx205022 	&sum_dma_attr,
1345574Smx205022 	&sum_tx_dma_attr,
1355574Smx205022 	nge_sum_rxd_fill,
1365574Smx205022 	nge_sum_rxd_check,
1375574Smx205022 	nge_sum_txd_fill,
1385574Smx205022 	nge_sum_txd_check,
1395574Smx205022 };
1405574Smx205022 
1415574Smx205022 /*
1425574Smx205022  * NIC DESC MODE 3
1435574Smx205022  */
1445574Smx205022 
1455574Smx205022 static const nge_desc_attr_t nge_hot_desc = {
1465574Smx205022 
1475574Smx205022 	sizeof (hot_rx_bd),
1485574Smx205022 	sizeof (hot_tx_bd),
1495574Smx205022 	&hot_dma_attr,
1505574Smx205022 	&hot_tx_dma_attr,
1515574Smx205022 	nge_hot_rxd_fill,
1525574Smx205022 	nge_hot_rxd_check,
1535574Smx205022 	nge_hot_txd_fill,
1545574Smx205022 	nge_hot_txd_check,
1555574Smx205022 };
1565574Smx205022 
1576512Ssowmini static char nge_ident[] = "nVidia 1Gb Ethernet";
1585574Smx205022 static char clsize_propname[] = "cache-line-size";
1595574Smx205022 static char latency_propname[] = "latency-timer";
1605574Smx205022 static char debug_propname[]	= "nge-debug-flags";
1615659Sjj146644 static char intr_moderation[] = "intr-moderation";
1625574Smx205022 static char rx_data_hw[] = "rx-data-hw";
1635574Smx205022 static char rx_prd_lw[] = "rx-prd-lw";
1645574Smx205022 static char rx_prd_hw[] = "rx-prd-hw";
1655574Smx205022 static char sw_intr_intv[] = "sw-intr-intvl";
1665574Smx205022 static char nge_desc_mode[] = "desc-mode";
1675574Smx205022 static char default_mtu[] = "default_mtu";
1685574Smx205022 static char low_memory_mode[] = "minimal-memory-usage";
1695574Smx205022 extern kmutex_t nge_log_mutex[1];
1705574Smx205022 
1715574Smx205022 static int		nge_m_start(void *);
1725574Smx205022 static void		nge_m_stop(void *);
1735574Smx205022 static int		nge_m_promisc(void *, boolean_t);
1745574Smx205022 static int		nge_m_multicst(void *, boolean_t, const uint8_t *);
1755574Smx205022 static int		nge_m_unicst(void *, const uint8_t *);
1765574Smx205022 static void		nge_m_ioctl(void *, queue_t *, mblk_t *);
1775574Smx205022 static boolean_t	nge_m_getcapab(void *, mac_capab_t, void *);
1786200Smx205022 static int		nge_m_setprop(void *, const char *, mac_prop_id_t,
1796200Smx205022 	uint_t, const void *);
1806200Smx205022 static int		nge_m_getprop(void *, const char *, mac_prop_id_t,
1816512Ssowmini 	uint_t, uint_t, void *);
1826200Smx205022 static int		nge_set_priv_prop(nge_t *, const char *, uint_t,
1836200Smx205022 	const void *);
1846200Smx205022 static int		nge_get_priv_prop(nge_t *, const char *, uint_t,
1856512Ssowmini 	uint_t, void *);
1866200Smx205022 
1876200Smx205022 #define		NGE_M_CALLBACK_FLAGS\
1886200Smx205022 		(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
1895574Smx205022 
1905574Smx205022 static mac_callbacks_t nge_m_callbacks = {
1915574Smx205022 	NGE_M_CALLBACK_FLAGS,
1925574Smx205022 	nge_m_stat,
1935574Smx205022 	nge_m_start,
1945574Smx205022 	nge_m_stop,
1955574Smx205022 	nge_m_promisc,
1965574Smx205022 	nge_m_multicst,
1975574Smx205022 	nge_m_unicst,
1985574Smx205022 	nge_m_tx,
1995659Sjj146644 	NULL,
2005574Smx205022 	nge_m_ioctl,
2016200Smx205022 	nge_m_getcapab,
2026200Smx205022 	NULL,
2036200Smx205022 	NULL,
2046200Smx205022 	nge_m_setprop,
2056200Smx205022 	nge_m_getprop
2065574Smx205022 };
2075574Smx205022 
2086512Ssowmini mac_priv_prop_t nge_priv_props[] = {
2096512Ssowmini 	{"_tx_bcopy_threshold", MAC_PROP_PERM_RW},
2106512Ssowmini 	{"_rx_bcopy_threshold", MAC_PROP_PERM_RW},
2116512Ssowmini 	{"_recv_max_packet", MAC_PROP_PERM_RW},
2126512Ssowmini 	{"_poll_quiet_time", MAC_PROP_PERM_RW},
2136512Ssowmini 	{"_poll_busy_time", MAC_PROP_PERM_RW},
2146512Ssowmini 	{"_rx_intr_hwater", MAC_PROP_PERM_RW},
2156512Ssowmini 	{"_rx_intr_lwater", MAC_PROP_PERM_RW},
2166512Ssowmini 	{"_adv_pause_cap", MAC_PROP_PERM_RW},
2176512Ssowmini 	{"_adv_asym_pause_cap", MAC_PROP_PERM_RW},
2186512Ssowmini 	{"_tx_n_intr", MAC_PROP_PERM_RW}
2196512Ssowmini };
2206512Ssowmini 
2216512Ssowmini #define	NGE_MAX_PRIV_PROPS \
2226512Ssowmini 	(sizeof (nge_priv_props)/sizeof (mac_priv_prop_t))
2236512Ssowmini 
2245574Smx205022 static int nge_add_intrs(nge_t *, int);
2255574Smx205022 static void nge_rem_intrs(nge_t *);
2265574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *);
2275574Smx205022 
2285574Smx205022 /*
2295574Smx205022  * NGE MSI tunable:
2305574Smx205022  */
2315574Smx205022 boolean_t nge_enable_msi = B_FALSE;
2325574Smx205022 
2335574Smx205022 static enum ioc_reply
2345574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
2355574Smx205022 {
2365574Smx205022 	/*
2375574Smx205022 	 * If the mode isn't being changed, there's nothing to do ...
2385574Smx205022 	 */
2395574Smx205022 	if (mode == ngep->param_loop_mode)
2405574Smx205022 		return (IOC_ACK);
2415574Smx205022 
2425574Smx205022 	/*
2435574Smx205022 	 * Validate the requested mode and prepare a suitable message
2445574Smx205022 	 * to explain the link down/up cycle that the change will
2455574Smx205022 	 * probably induce ...
2465574Smx205022 	 */
2475574Smx205022 	switch (mode) {
2485574Smx205022 	default:
2495574Smx205022 		return (IOC_INVAL);
2505574Smx205022 
2515574Smx205022 	case NGE_LOOP_NONE:
2525574Smx205022 	case NGE_LOOP_EXTERNAL_100:
2535574Smx205022 	case NGE_LOOP_EXTERNAL_10:
2545574Smx205022 	case NGE_LOOP_INTERNAL_PHY:
2555574Smx205022 		break;
2565574Smx205022 	}
2575574Smx205022 
2585574Smx205022 	/*
2595574Smx205022 	 * All OK; tell the caller to reprogram
2605574Smx205022 	 * the PHY and/or MAC for the new mode ...
2615574Smx205022 	 */
2625574Smx205022 	ngep->param_loop_mode = mode;
2635574Smx205022 	return (IOC_RESTART_ACK);
2645574Smx205022 }
2655574Smx205022 
2665574Smx205022 #undef	NGE_DBG
2675574Smx205022 #define	NGE_DBG		NGE_DBG_INIT
2685574Smx205022 
2695574Smx205022 /*
2705574Smx205022  * Utility routine to carve a slice off a chunk of allocated memory,
2715574Smx205022  * updating the chunk descriptor accordingly.  The size of the slice
2725574Smx205022  * is given by the product of the <qty> and <size> parameters.
2735574Smx205022  */
2745574Smx205022 void
2755574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
2765574Smx205022     uint32_t qty, uint32_t size)
2775574Smx205022 {
2785574Smx205022 	size_t totsize;
2795574Smx205022 
2805574Smx205022 	totsize = qty*size;
2815574Smx205022 	ASSERT(size > 0);
2825574Smx205022 	ASSERT(totsize <= chunk->alength);
2835574Smx205022 
2845574Smx205022 	*slice = *chunk;
2855574Smx205022 	slice->nslots = qty;
2865574Smx205022 	slice->size = size;
2875574Smx205022 	slice->alength = totsize;
2885574Smx205022 
2895574Smx205022 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
2905574Smx205022 	chunk->alength -= totsize;
2915574Smx205022 	chunk->offset += totsize;
2925574Smx205022 	chunk->cookie.dmac_laddress += totsize;
2935574Smx205022 	chunk->cookie.dmac_size -= totsize;
2945574Smx205022 }
2955574Smx205022 
2965574Smx205022 /*
2975574Smx205022  * Allocate an area of memory and a DMA handle for accessing it
2985574Smx205022  */
2995574Smx205022 int
3005574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
3015574Smx205022     uint_t dma_flags, dma_area_t *dma_p)
3025574Smx205022 {
3035574Smx205022 	int err;
3045574Smx205022 	caddr_t va;
3055574Smx205022 
3065574Smx205022 	NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
3075574Smx205022 	    (void *)ngep, memsize, attr_p, dma_flags, dma_p));
3085574Smx205022 	/*
3095574Smx205022 	 * Allocate handle
3105574Smx205022 	 */
3115574Smx205022 	err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
3125574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
3135574Smx205022 	if (err != DDI_SUCCESS)
3145574Smx205022 		goto fail;
3155574Smx205022 
3165574Smx205022 	/*
3175574Smx205022 	 * Allocate memory
3185574Smx205022 	 */
3195574Smx205022 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
3205574Smx205022 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
3215574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
3225574Smx205022 	if (err != DDI_SUCCESS)
3235574Smx205022 		goto fail;
3245574Smx205022 
3255574Smx205022 	/*
3265574Smx205022 	 * Bind the two together
3275574Smx205022 	 */
3285574Smx205022 	dma_p->mem_va = va;
3295574Smx205022 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
3305574Smx205022 	    va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
3315574Smx205022 	    &dma_p->cookie, &dma_p->ncookies);
3325574Smx205022 
3335574Smx205022 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
3345574Smx205022 		goto fail;
3355574Smx205022 
3365574Smx205022 	dma_p->nslots = ~0U;
3375574Smx205022 	dma_p->size = ~0U;
3385574Smx205022 	dma_p->offset = 0;
3395574Smx205022 
3405574Smx205022 	return (DDI_SUCCESS);
3415574Smx205022 
3425574Smx205022 fail:
3435574Smx205022 	nge_free_dma_mem(dma_p);
3445574Smx205022 	NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
3455574Smx205022 
3465574Smx205022 	return (DDI_FAILURE);
3475574Smx205022 }
3485574Smx205022 
3495574Smx205022 /*
3505574Smx205022  * Free one allocated area of DMAable memory
3515574Smx205022  */
3525574Smx205022 void
3535574Smx205022 nge_free_dma_mem(dma_area_t *dma_p)
3545574Smx205022 {
3555574Smx205022 	if (dma_p->dma_hdl != NULL) {
3565574Smx205022 		if (dma_p->ncookies) {
3575574Smx205022 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
3585574Smx205022 			dma_p->ncookies = 0;
3595574Smx205022 		}
3605574Smx205022 	}
3615574Smx205022 	if (dma_p->acc_hdl != NULL) {
3625574Smx205022 		ddi_dma_mem_free(&dma_p->acc_hdl);
3635574Smx205022 		dma_p->acc_hdl = NULL;
3645574Smx205022 	}
3655574Smx205022 	if (dma_p->dma_hdl != NULL) {
3665574Smx205022 		ddi_dma_free_handle(&dma_p->dma_hdl);
3675574Smx205022 		dma_p->dma_hdl = NULL;
3685574Smx205022 	}
3695574Smx205022 }
3705574Smx205022 
3715574Smx205022 #define	ALLOC_TX_BUF	0x1
3725574Smx205022 #define	ALLOC_TX_DESC	0x2
3735574Smx205022 #define	ALLOC_RX_DESC	0x4
3745574Smx205022 
3755574Smx205022 int
3765574Smx205022 nge_alloc_bufs(nge_t *ngep)
3775574Smx205022 {
3785574Smx205022 	int err;
3795574Smx205022 	int split;
3805574Smx205022 	int progress;
3815574Smx205022 	size_t txbuffsize;
3825574Smx205022 	size_t rxdescsize;
3835574Smx205022 	size_t txdescsize;
3845574Smx205022 
3855574Smx205022 	txbuffsize = ngep->tx_desc * ngep->buf_size;
3865574Smx205022 	rxdescsize = ngep->rx_desc;
3875574Smx205022 	txdescsize = ngep->tx_desc;
3885574Smx205022 	rxdescsize *= ngep->desc_attr.rxd_size;
3895574Smx205022 	txdescsize *= ngep->desc_attr.txd_size;
3905574Smx205022 	progress = 0;
3915574Smx205022 
3925574Smx205022 	NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
3935574Smx205022 	/*
3945574Smx205022 	 * Allocate memory & handles for TX buffers
3955574Smx205022 	 */
3965574Smx205022 	ASSERT((txbuffsize % ngep->nge_split) == 0);
3975574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
3985574Smx205022 		err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
3995574Smx205022 		    &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
4005574Smx205022 		    &ngep->send->buf[split]);
4015574Smx205022 		if (err != DDI_SUCCESS)
4025574Smx205022 			goto fail;
4035574Smx205022 	}
4045574Smx205022 
4055574Smx205022 	progress |= ALLOC_TX_BUF;
4065574Smx205022 
4075574Smx205022 	/*
4085574Smx205022 	 * Allocate memory & handles for receive return rings and
4095574Smx205022 	 * buffer (producer) descriptor rings
4105574Smx205022 	 */
4115574Smx205022 	err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
4125574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
4135574Smx205022 	if (err != DDI_SUCCESS)
4145574Smx205022 		goto fail;
4155574Smx205022 	progress |= ALLOC_RX_DESC;
4165574Smx205022 
4175574Smx205022 	/*
4185574Smx205022 	 * Allocate memory & handles for TX descriptor rings,
4195574Smx205022 	 */
4205574Smx205022 	err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
4215574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
4225574Smx205022 	if (err != DDI_SUCCESS)
4235574Smx205022 		goto fail;
4245574Smx205022 	return (DDI_SUCCESS);
4255574Smx205022 
4265574Smx205022 fail:
4275574Smx205022 	if (progress & ALLOC_RX_DESC)
4285574Smx205022 		nge_free_dma_mem(&ngep->recv->desc);
4295574Smx205022 	if (progress & ALLOC_TX_BUF) {
4305574Smx205022 		for (split = 0; split < ngep->nge_split; ++split)
4315574Smx205022 			nge_free_dma_mem(&ngep->send->buf[split]);
4325574Smx205022 	}
4335574Smx205022 
4345574Smx205022 	return (DDI_FAILURE);
4355574Smx205022 }
4365574Smx205022 
4375574Smx205022 /*
4385574Smx205022  * This routine frees the transmit and receive buffers and descriptors.
4395574Smx205022  * Make sure the chip is stopped before calling it!
4405574Smx205022  */
4415574Smx205022 void
4425574Smx205022 nge_free_bufs(nge_t *ngep)
4435574Smx205022 {
4445574Smx205022 	int split;
4455574Smx205022 
4465574Smx205022 	NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
4475574Smx205022 
4485574Smx205022 	nge_free_dma_mem(&ngep->recv->desc);
4495574Smx205022 	nge_free_dma_mem(&ngep->send->desc);
4505574Smx205022 
4515574Smx205022 	for (split = 0; split < ngep->nge_split; ++split)
4525574Smx205022 		nge_free_dma_mem(&ngep->send->buf[split]);
4535574Smx205022 }
4545574Smx205022 
4555574Smx205022 /*
4565574Smx205022  * Clean up initialisation done above before the memory is freed
4575574Smx205022  */
4585574Smx205022 static void
4595574Smx205022 nge_fini_send_ring(nge_t *ngep)
4605574Smx205022 {
4615574Smx205022 	uint32_t slot;
4625574Smx205022 	size_t dmah_num;
4635574Smx205022 	send_ring_t *srp;
4645574Smx205022 	sw_tx_sbd_t *ssbdp;
4655574Smx205022 
4665574Smx205022 	srp = ngep->send;
4675574Smx205022 	ssbdp = srp->sw_sbds;
4685574Smx205022 
4695574Smx205022 	NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
4705574Smx205022 
4715574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
4725574Smx205022 
4735574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
4745574Smx205022 		if (srp->dmahndl[slot].hndl) {
4755574Smx205022 			(void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
4765574Smx205022 			ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
4775574Smx205022 			srp->dmahndl[slot].hndl = NULL;
4785574Smx205022 			srp->dmahndl[slot].next = NULL;
4795574Smx205022 		}
4805574Smx205022 	}
4815574Smx205022 
4825574Smx205022 	srp->dmah_free.head = NULL;
4835574Smx205022 	srp->dmah_free.tail = NULL;
4845574Smx205022 
4855574Smx205022 	kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
4865574Smx205022 
4875574Smx205022 }
4885574Smx205022 
4895574Smx205022 /*
4905574Smx205022  * Initialise the specified Send Ring, using the information in the
4915574Smx205022  * <dma_area> descriptors that it contains to set up all the other
4925574Smx205022  * fields. This routine should be called only once for each ring.
4935574Smx205022  */
4945574Smx205022 static int
4955574Smx205022 nge_init_send_ring(nge_t *ngep)
4965574Smx205022 {
4975574Smx205022 	size_t dmah_num;
4985574Smx205022 	uint32_t nslots;
4995574Smx205022 	uint32_t err;
5005574Smx205022 	uint32_t slot;
5015574Smx205022 	uint32_t split;
5025574Smx205022 	send_ring_t *srp;
5035574Smx205022 	sw_tx_sbd_t *ssbdp;
5045574Smx205022 	dma_area_t desc;
5055574Smx205022 	dma_area_t pbuf;
5065574Smx205022 
5075574Smx205022 	srp = ngep->send;
5085574Smx205022 	srp->desc.nslots = ngep->tx_desc;
5095574Smx205022 	nslots = srp->desc.nslots;
5105574Smx205022 
5115574Smx205022 	NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
5125574Smx205022 	/*
5135574Smx205022 	 * Other one-off initialisation of per-ring data
5145574Smx205022 	 */
5155574Smx205022 	srp->ngep = ngep;
5165574Smx205022 
5175574Smx205022 	/*
5185574Smx205022 	 * Allocate the array of s/w Send Buffer Descriptors
5195574Smx205022 	 */
5205574Smx205022 	ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
5215574Smx205022 	srp->sw_sbds = ssbdp;
5225574Smx205022 
5235574Smx205022 	/*
5245574Smx205022 	 * Now initialise each array element once and for all
5255574Smx205022 	 */
5265574Smx205022 	desc = srp->desc;
5275574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
5285574Smx205022 		pbuf = srp->buf[split];
5295574Smx205022 		for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
5305574Smx205022 			nge_slice_chunk(&ssbdp->desc, &desc, 1,
5315574Smx205022 			    ngep->desc_attr.txd_size);
5325574Smx205022 			nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
5335574Smx205022 			    ngep->buf_size);
5345574Smx205022 		}
5355574Smx205022 		ASSERT(pbuf.alength == 0);
5365574Smx205022 	}
5375574Smx205022 	ASSERT(desc.alength == 0);
5385574Smx205022 
5395574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5405574Smx205022 
5415574Smx205022 	/* preallocate dma handles for tx buffer */
5425574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
5435574Smx205022 
5445574Smx205022 		err = ddi_dma_alloc_handle(ngep->devinfo,
5455574Smx205022 		    ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
5465574Smx205022 		    NULL, &srp->dmahndl[slot].hndl);
5475574Smx205022 
5485574Smx205022 		if (err != DDI_SUCCESS) {
5495574Smx205022 			nge_fini_send_ring(ngep);
5505574Smx205022 			nge_error(ngep,
5515574Smx205022 			    "nge_init_send_ring: alloc dma handle fails");
5525574Smx205022 			return (DDI_FAILURE);
5535574Smx205022 		}
5545574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5555574Smx205022 	}
5565574Smx205022 
5575574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5585574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5595574Smx205022 	srp->dmah_free.tail->next = NULL;
5605574Smx205022 
5615574Smx205022 	return (DDI_SUCCESS);
5625574Smx205022 }
5635574Smx205022 
5645574Smx205022 /*
5655574Smx205022  * Intialize the tx recycle pointer and tx sending pointer of tx ring
5665574Smx205022  * and set the type of tx's data descriptor by default.
5675574Smx205022  */
5685574Smx205022 static void
5695574Smx205022 nge_reinit_send_ring(nge_t *ngep)
5705574Smx205022 {
5715574Smx205022 	size_t dmah_num;
5725574Smx205022 	uint32_t slot;
5735574Smx205022 	send_ring_t *srp;
5745574Smx205022 	sw_tx_sbd_t *ssbdp;
5755574Smx205022 
5765574Smx205022 	srp = ngep->send;
5775574Smx205022 
5785574Smx205022 	/*
5795574Smx205022 	 * Reinitialise control variables ...
5805574Smx205022 	 */
5815574Smx205022 
5825574Smx205022 	srp->tx_hwmark = NGE_DESC_MIN;
5835574Smx205022 	srp->tx_lwmark = NGE_DESC_MIN;
5845574Smx205022 
5855574Smx205022 	srp->tx_next = 0;
5865574Smx205022 	srp->tx_free = srp->desc.nslots;
5875574Smx205022 	srp->tc_next = 0;
5885574Smx205022 
5895574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5905574Smx205022 
5915574Smx205022 	for (slot = 0; slot - dmah_num != 0; ++slot)
5925574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5935574Smx205022 
5945574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5955574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5965574Smx205022 	srp->dmah_free.tail->next = NULL;
5975574Smx205022 
5985574Smx205022 	/*
5995574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
6005574Smx205022 	 */
6015574Smx205022 	for (slot = 0; slot < srp->desc.nslots; ++slot) {
6025574Smx205022 		ssbdp = &srp->sw_sbds[slot];
6035574Smx205022 		ssbdp->flags = HOST_OWN;
6045574Smx205022 	}
6055574Smx205022 
6065574Smx205022 	DMA_ZERO(srp->desc);
6075574Smx205022 	DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
6085574Smx205022 }
6095574Smx205022 
6105574Smx205022 /*
6115574Smx205022  * Initialize the slot number of rx's ring
6125574Smx205022  */
6135574Smx205022 static void
6145574Smx205022 nge_init_recv_ring(nge_t *ngep)
6155574Smx205022 {
6165574Smx205022 	recv_ring_t *rrp;
6175574Smx205022 
6185574Smx205022 	rrp = ngep->recv;
6195574Smx205022 	rrp->desc.nslots = ngep->rx_desc;
6205574Smx205022 	rrp->ngep = ngep;
6215574Smx205022 }
6225574Smx205022 
6235574Smx205022 /*
6245574Smx205022  * Intialize the rx recycle pointer and rx sending pointer of rx ring
6255574Smx205022  */
6265574Smx205022 static void
6275574Smx205022 nge_reinit_recv_ring(nge_t *ngep)
6285574Smx205022 {
6295574Smx205022 	recv_ring_t *rrp;
6305574Smx205022 
6315574Smx205022 	rrp = ngep->recv;
6325574Smx205022 
6335574Smx205022 	/*
6345574Smx205022 	 * Reinitialise control variables ...
6355574Smx205022 	 */
6365574Smx205022 	rrp->prod_index = 0;
6375574Smx205022 	/*
6385574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
6395574Smx205022 	 */
6405574Smx205022 	DMA_ZERO(rrp->desc);
6415574Smx205022 	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
6425574Smx205022 }
6435574Smx205022 
6445574Smx205022 /*
6455574Smx205022  * Clean up initialisation done above before the memory is freed
6465574Smx205022  */
6475574Smx205022 static void
6485574Smx205022 nge_fini_buff_ring(nge_t *ngep)
6495574Smx205022 {
6505574Smx205022 	uint32_t i;
6515574Smx205022 	buff_ring_t *brp;
6525574Smx205022 	dma_area_t *bufp;
6535574Smx205022 	sw_rx_sbd_t *bsbdp;
6545574Smx205022 
6555574Smx205022 	brp = ngep->buff;
6565574Smx205022 	bsbdp = brp->sw_rbds;
6575574Smx205022 
6585574Smx205022 	NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
6595574Smx205022 
6605574Smx205022 	mutex_enter(brp->recycle_lock);
6615574Smx205022 	brp->buf_sign++;
6625574Smx205022 	mutex_exit(brp->recycle_lock);
6635574Smx205022 	for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
6645574Smx205022 		if (bsbdp->bufp) {
6655574Smx205022 			if (bsbdp->bufp->mp)
6665574Smx205022 				freemsg(bsbdp->bufp->mp);
6675574Smx205022 			nge_free_dma_mem(bsbdp->bufp);
6685574Smx205022 			kmem_free(bsbdp->bufp, sizeof (dma_area_t));
6695574Smx205022 			bsbdp->bufp = NULL;
6705574Smx205022 		}
6715574Smx205022 	}
6725574Smx205022 	while (brp->free_list != NULL) {
6735574Smx205022 		bufp = brp->free_list;
6745574Smx205022 		brp->free_list = bufp->next;
6755574Smx205022 		bufp->next = NULL;
6765574Smx205022 		if (bufp->mp)
6775574Smx205022 			freemsg(bufp->mp);
6785574Smx205022 		nge_free_dma_mem(bufp);
6795574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6805574Smx205022 	}
6815574Smx205022 	while (brp->recycle_list != NULL) {
6825574Smx205022 		bufp = brp->recycle_list;
6835574Smx205022 		brp->recycle_list = bufp->next;
6845574Smx205022 		bufp->next = NULL;
6855574Smx205022 		if (bufp->mp)
6865574Smx205022 			freemsg(bufp->mp);
6875574Smx205022 		nge_free_dma_mem(bufp);
6885574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6895574Smx205022 	}
6905574Smx205022 
6915574Smx205022 
6925574Smx205022 	kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
6935574Smx205022 	brp->sw_rbds = NULL;
6945574Smx205022 }
6955574Smx205022 
6965574Smx205022 /*
6975574Smx205022  * Intialize the Rx's data ring and free ring
6985574Smx205022  */
6995574Smx205022 static int
7005574Smx205022 nge_init_buff_ring(nge_t *ngep)
7015574Smx205022 {
7025574Smx205022 	uint32_t err;
7035574Smx205022 	uint32_t slot;
7045574Smx205022 	uint32_t nslots_buff;
7055574Smx205022 	uint32_t nslots_recv;
7065574Smx205022 	buff_ring_t *brp;
7075574Smx205022 	recv_ring_t *rrp;
7085574Smx205022 	dma_area_t desc;
7095574Smx205022 	dma_area_t *bufp;
7105574Smx205022 	sw_rx_sbd_t *bsbdp;
7115574Smx205022 
7125574Smx205022 	rrp = ngep->recv;
7135574Smx205022 	brp = ngep->buff;
7145574Smx205022 	brp->nslots = ngep->rx_buf;
7155574Smx205022 	brp->rx_bcopy = B_FALSE;
7165574Smx205022 	nslots_recv = rrp->desc.nslots;
7175574Smx205022 	nslots_buff = brp->nslots;
7185574Smx205022 	brp->ngep = ngep;
7195574Smx205022 
7205574Smx205022 	NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
7215574Smx205022 
7225574Smx205022 	/*
7235574Smx205022 	 * Allocate the array of s/w Recv Buffer Descriptors
7245574Smx205022 	 */
7255574Smx205022 	bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
7265574Smx205022 	brp->sw_rbds = bsbdp;
7275574Smx205022 	brp->free_list = NULL;
7285574Smx205022 	brp->recycle_list = NULL;
7295574Smx205022 	for (slot = 0; slot < nslots_buff; ++slot) {
7305574Smx205022 		bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
7315574Smx205022 		err = nge_alloc_dma_mem(ngep, (ngep->buf_size
7325574Smx205022 		    + NGE_HEADROOM),
7335574Smx205022 		    &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
7345574Smx205022 		if (err != DDI_SUCCESS) {
7355574Smx205022 			kmem_free(bufp, sizeof (dma_area_t));
7365574Smx205022 			return (DDI_FAILURE);
7375574Smx205022 		}
7385574Smx205022 
7395574Smx205022 		bufp->alength -= NGE_HEADROOM;
7405574Smx205022 		bufp->offset += NGE_HEADROOM;
7415574Smx205022 		bufp->private = (caddr_t)ngep;
7425574Smx205022 		bufp->rx_recycle.free_func = nge_recv_recycle;
7435574Smx205022 		bufp->rx_recycle.free_arg = (caddr_t)bufp;
7445574Smx205022 		bufp->signature = brp->buf_sign;
7455574Smx205022 		bufp->rx_delivered = B_FALSE;
7465574Smx205022 		bufp->mp = desballoc(DMA_VPTR(*bufp),
7475574Smx205022 		    ngep->buf_size + NGE_HEADROOM,
7485574Smx205022 		    0, &bufp->rx_recycle);
7495574Smx205022 
7505574Smx205022 		if (bufp->mp == NULL) {
7515574Smx205022 			return (DDI_FAILURE);
7525574Smx205022 		}
7535574Smx205022 		bufp->next = brp->free_list;
7545574Smx205022 		brp->free_list = bufp;
7555574Smx205022 	}
7565574Smx205022 
7575574Smx205022 	/*
7585574Smx205022 	 * Now initialise each array element once and for all
7595574Smx205022 	 */
7605574Smx205022 	desc = rrp->desc;
7615574Smx205022 	for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
7625574Smx205022 		nge_slice_chunk(&bsbdp->desc, &desc, 1,
7635574Smx205022 		    ngep->desc_attr.rxd_size);
7645574Smx205022 		bufp = brp->free_list;
7655574Smx205022 		brp->free_list = bufp->next;
7665574Smx205022 		bsbdp->bufp = bufp;
7675574Smx205022 		bsbdp->flags = CONTROLER_OWN;
7685574Smx205022 		bufp->next = NULL;
7695574Smx205022 	}
7705574Smx205022 
7715574Smx205022 	ASSERT(desc.alength == 0);
7725574Smx205022 	return (DDI_SUCCESS);
7735574Smx205022 }
7745574Smx205022 
7755574Smx205022 /*
7765574Smx205022  * Fill the host address of data in rx' descriptor
7775574Smx205022  * and initialize free pointers of rx free ring
7785574Smx205022  */
7795574Smx205022 static int
7805574Smx205022 nge_reinit_buff_ring(nge_t *ngep)
7815574Smx205022 {
7825574Smx205022 	uint32_t slot;
7835574Smx205022 	uint32_t nslots_recv;
7845574Smx205022 	buff_ring_t *brp;
7855574Smx205022 	recv_ring_t *rrp;
7865574Smx205022 	sw_rx_sbd_t *bsbdp;
7875574Smx205022 	void *hw_bd_p;
7885574Smx205022 
7895574Smx205022 	brp = ngep->buff;
7905574Smx205022 	rrp = ngep->recv;
7915574Smx205022 	bsbdp = brp->sw_rbds;
7925574Smx205022 	nslots_recv = rrp->desc.nslots;
7935574Smx205022 	for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
7945574Smx205022 		hw_bd_p = DMA_VPTR(bsbdp->desc);
7955574Smx205022 	/*
7965574Smx205022 	 * There is a scenario: When the traffic of small tcp
7975574Smx205022 	 * packet is heavy, suspending the tcp traffic will
7985574Smx205022 	 * cause the preallocated buffers for rx not to be
7995574Smx205022 	 * released in time by tcp taffic and cause rx's buffer
8005574Smx205022 	 * pointers not to be refilled in time.
8015574Smx205022 	 *
8025574Smx205022 	 * At this point, if we reinitialize the driver, the bufp
8035574Smx205022 	 * pointer for rx's traffic will be NULL.
8045574Smx205022 	 * So the result of the reinitializion fails.
8055574Smx205022 	 */
8065574Smx205022 		if (bsbdp->bufp == NULL)
8075574Smx205022 			return (DDI_FAILURE);
8085574Smx205022 
8095574Smx205022 		ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
8105574Smx205022 		    bsbdp->bufp->alength);
8115574Smx205022 	}
8125574Smx205022 	return (DDI_SUCCESS);
8135574Smx205022 }
8145574Smx205022 
8155574Smx205022 static void
8165574Smx205022 nge_init_ring_param_lock(nge_t *ngep)
8175574Smx205022 {
8185574Smx205022 	buff_ring_t *brp;
8195574Smx205022 	send_ring_t *srp;
8205574Smx205022 
8215574Smx205022 	srp = ngep->send;
8225574Smx205022 	brp = ngep->buff;
8235574Smx205022 
8245574Smx205022 	/* Init the locks for send ring */
8255574Smx205022 	mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
8265574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8275574Smx205022 	mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
8285574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8295574Smx205022 	mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
8305574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8315574Smx205022 
8325574Smx205022 	/* Init parameters of buffer ring */
8335574Smx205022 	brp->free_list = NULL;
8345574Smx205022 	brp->recycle_list = NULL;
8355574Smx205022 	brp->rx_hold = 0;
8365574Smx205022 	brp->buf_sign = 0;
8375574Smx205022 
8385574Smx205022 	/* Init recycle list lock */
8395574Smx205022 	mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
8405574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8415574Smx205022 }
8425574Smx205022 
8435574Smx205022 int
8445574Smx205022 nge_init_rings(nge_t *ngep)
8455574Smx205022 {
8465574Smx205022 	uint32_t err;
8475574Smx205022 
8485574Smx205022 	err = nge_init_send_ring(ngep);
8495574Smx205022 	if (err != DDI_SUCCESS) {
8505574Smx205022 		return (err);
8515574Smx205022 	}
8525574Smx205022 	nge_init_recv_ring(ngep);
8535574Smx205022 
8545574Smx205022 	err = nge_init_buff_ring(ngep);
8555574Smx205022 	if (err != DDI_SUCCESS) {
8565574Smx205022 		nge_fini_send_ring(ngep);
8575574Smx205022 		return (DDI_FAILURE);
8585574Smx205022 	}
8595574Smx205022 
8605574Smx205022 	return (err);
8615574Smx205022 }
8625574Smx205022 
8635574Smx205022 static int
8645574Smx205022 nge_reinit_ring(nge_t *ngep)
8655574Smx205022 {
8665574Smx205022 	int err;
8675574Smx205022 
8685574Smx205022 	nge_reinit_recv_ring(ngep);
8695574Smx205022 	nge_reinit_send_ring(ngep);
8705574Smx205022 	err = nge_reinit_buff_ring(ngep);
8715574Smx205022 	return (err);
8725574Smx205022 }
8735574Smx205022 
8745574Smx205022 
8755574Smx205022 void
8765574Smx205022 nge_fini_rings(nge_t *ngep)
8775574Smx205022 {
8785574Smx205022 	/*
8795574Smx205022 	 * For receive ring, nothing need to be finished.
8805574Smx205022 	 * So only finish buffer ring and send ring here.
8815574Smx205022 	 */
8825574Smx205022 	nge_fini_buff_ring(ngep);
8835574Smx205022 	nge_fini_send_ring(ngep);
8845574Smx205022 }
8855574Smx205022 
8865574Smx205022 /*
8875574Smx205022  * Loopback ioctl code
8885574Smx205022  */
8895574Smx205022 
8905574Smx205022 static lb_property_t loopmodes[] = {
8915574Smx205022 	{ normal,	"normal",	NGE_LOOP_NONE		},
8925574Smx205022 	{ external,	"100Mbps",	NGE_LOOP_EXTERNAL_100	},
8935574Smx205022 	{ external,	"10Mbps",	NGE_LOOP_EXTERNAL_10	},
8945574Smx205022 	{ internal,	"PHY",		NGE_LOOP_INTERNAL_PHY	},
8955574Smx205022 };
8965574Smx205022 
8975574Smx205022 enum ioc_reply
8985574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
8995574Smx205022 {
9005574Smx205022 	int cmd;
9015574Smx205022 	uint32_t *lbmp;
9025574Smx205022 	lb_info_sz_t *lbsp;
9035574Smx205022 	lb_property_t *lbpp;
9045574Smx205022 
9055574Smx205022 	/*
9065574Smx205022 	 * Validate format of ioctl
9075574Smx205022 	 */
9085574Smx205022 	if (mp->b_cont == NULL)
9095574Smx205022 		return (IOC_INVAL);
9105574Smx205022 
9115574Smx205022 	cmd = iocp->ioc_cmd;
9125574Smx205022 
9135574Smx205022 	switch (cmd) {
9145574Smx205022 	default:
9155574Smx205022 		return (IOC_INVAL);
9165574Smx205022 
9175574Smx205022 	case LB_GET_INFO_SIZE:
9185574Smx205022 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
9195574Smx205022 			return (IOC_INVAL);
9205574Smx205022 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
9215574Smx205022 		*lbsp = sizeof (loopmodes);
9225574Smx205022 		return (IOC_REPLY);
9235574Smx205022 
9245574Smx205022 	case LB_GET_INFO:
9255574Smx205022 		if (iocp->ioc_count != sizeof (loopmodes))
9265574Smx205022 			return (IOC_INVAL);
9275574Smx205022 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
9285574Smx205022 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
9295574Smx205022 		return (IOC_REPLY);
9305574Smx205022 
9315574Smx205022 	case LB_GET_MODE:
9325574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9335574Smx205022 			return (IOC_INVAL);
9345574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9355574Smx205022 		*lbmp = ngep->param_loop_mode;
9365574Smx205022 		return (IOC_REPLY);
9375574Smx205022 
9385574Smx205022 	case LB_SET_MODE:
9395574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9405574Smx205022 			return (IOC_INVAL);
9415574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9425574Smx205022 		return (nge_set_loop_mode(ngep, *lbmp));
9435574Smx205022 	}
9445574Smx205022 }
9455574Smx205022 
9465574Smx205022 #undef	NGE_DBG
9475574Smx205022 #define	NGE_DBG	NGE_DBG_NEMO
9485574Smx205022 
9495574Smx205022 
9505574Smx205022 static void
9515574Smx205022 nge_check_desc_prop(nge_t *ngep)
9525574Smx205022 {
9535574Smx205022 	if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
9545574Smx205022 		ngep->desc_mode = DESC_HOT;
9555574Smx205022 
9565574Smx205022 	if (ngep->desc_mode == DESC_OFFLOAD)	{
9575574Smx205022 
9585574Smx205022 		ngep->desc_attr = nge_sum_desc;
9595574Smx205022 
9605574Smx205022 	}	else if (ngep->desc_mode == DESC_HOT)	{
9615574Smx205022 
9625574Smx205022 		ngep->desc_attr = nge_hot_desc;
9635574Smx205022 	}
9645574Smx205022 }
9655574Smx205022 
9665574Smx205022 /*
9675574Smx205022  * nge_get_props -- get the parameters to tune the driver
9685574Smx205022  */
9695574Smx205022 static void
9705574Smx205022 nge_get_props(nge_t *ngep)
9715574Smx205022 {
9725574Smx205022 	chip_info_t *infop;
9735574Smx205022 	dev_info_t *devinfo;
9745574Smx205022 	nge_dev_spec_param_t *dev_param_p;
9755574Smx205022 
9765574Smx205022 	devinfo = ngep->devinfo;
9775574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
9785574Smx205022 	dev_param_p = &ngep->dev_spec_param;
9795574Smx205022 
9805574Smx205022 	infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9815574Smx205022 	    DDI_PROP_DONTPASS, clsize_propname, 32);
9825574Smx205022 
9835574Smx205022 	infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9845574Smx205022 	    DDI_PROP_DONTPASS, latency_propname, 64);
9855659Sjj146644 	ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9865659Sjj146644 	    DDI_PROP_DONTPASS, intr_moderation, NGE_SET);
9875574Smx205022 	ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9885574Smx205022 	    DDI_PROP_DONTPASS, rx_data_hw, 0x20);
9895574Smx205022 	ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9905574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
9915574Smx205022 	ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9925574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
9935574Smx205022 
9945574Smx205022 	ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9955574Smx205022 	    DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
9965574Smx205022 	ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9975574Smx205022 	    DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
9985574Smx205022 	ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9995574Smx205022 	    DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
10005574Smx205022 	ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10015574Smx205022 	    DDI_PROP_DONTPASS, low_memory_mode, 0);
10025574Smx205022 
10035574Smx205022 	if (dev_param_p->jumbo) {
10045574Smx205022 		ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
10055574Smx205022 		    DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
10065574Smx205022 	} else
10075574Smx205022 		ngep->default_mtu = ETHERMTU;
10085574Smx205022 
10095574Smx205022 	if (ngep->default_mtu > ETHERMTU &&
10105574Smx205022 	    ngep->default_mtu <= NGE_MTU_2500) {
10115574Smx205022 		ngep->buf_size = NGE_JB2500_BUFSZ;
10125574Smx205022 		ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
10135574Smx205022 		ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
10145574Smx205022 		ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
10155574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10165574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_2500 &&
10175574Smx205022 	    ngep->default_mtu <= NGE_MTU_4500) {
10185574Smx205022 		ngep->buf_size = NGE_JB4500_BUFSZ;
10195574Smx205022 		ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
10205574Smx205022 		ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
10215574Smx205022 		ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
10225574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10235574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_4500 &&
10245574Smx205022 	    ngep->default_mtu <= NGE_MAX_MTU) {
10255574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10265574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10275574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10285574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10295574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10305574Smx205022 	} else if (ngep->default_mtu > NGE_MAX_MTU) {
10315574Smx205022 		ngep->default_mtu = NGE_MAX_MTU;
10325574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10335574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10345574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10355574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10365574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10375574Smx205022 	} else if (ngep->lowmem_mode != 0) {
10385574Smx205022 		ngep->default_mtu = ETHERMTU;
10395574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10405574Smx205022 		ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
10415574Smx205022 		ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
10425574Smx205022 		ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
10435574Smx205022 		ngep->nge_split = NGE_SPLIT_32;
10445574Smx205022 	} else {
10455574Smx205022 		ngep->default_mtu = ETHERMTU;
10465574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10475574Smx205022 		ngep->tx_desc = dev_param_p->tx_desc_num;
10485574Smx205022 		ngep->rx_desc = dev_param_p->rx_desc_num;
10495574Smx205022 		ngep->rx_buf = dev_param_p->rx_desc_num * 2;
10505574Smx205022 		ngep->nge_split = dev_param_p->nge_split;
10515574Smx205022 	}
10525574Smx205022 
10535574Smx205022 	nge_check_desc_prop(ngep);
10545574Smx205022 }
10555574Smx205022 
10565574Smx205022 
10575574Smx205022 static int
10585574Smx205022 nge_reset(nge_t *ngep)
10595574Smx205022 {
10605574Smx205022 	int err;
10615869Smx205022 	nge_mul_addr1 maddr1;
10625869Smx205022 	nge_sw_statistics_t *sw_stp;
10635869Smx205022 	sw_stp = &ngep->statistics.sw_statistics;
10645574Smx205022 	send_ring_t *srp = ngep->send;
10655574Smx205022 
10665574Smx205022 	ASSERT(mutex_owned(ngep->genlock));
10675574Smx205022 	mutex_enter(srp->tc_lock);
10685574Smx205022 	mutex_enter(srp->tx_lock);
10695574Smx205022 
10705574Smx205022 	nge_tx_recycle_all(ngep);
10715574Smx205022 	err = nge_reinit_ring(ngep);
10725574Smx205022 	if (err == DDI_FAILURE) {
10735574Smx205022 		mutex_exit(srp->tx_lock);
10745574Smx205022 		mutex_exit(srp->tc_lock);
10755574Smx205022 		return (err);
10765574Smx205022 	}
10775574Smx205022 	err = nge_chip_reset(ngep);
10785869Smx205022 	/*
10795869Smx205022 	 * Clear the Multicast mac address table
10805869Smx205022 	 */
10815869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
10825869Smx205022 	maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
10835869Smx205022 	maddr1.addr_bits.addr = 0;
10845869Smx205022 	nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
10855869Smx205022 
10865574Smx205022 	mutex_exit(srp->tx_lock);
10875574Smx205022 	mutex_exit(srp->tc_lock);
10885574Smx205022 	if (err == DDI_FAILURE)
10895574Smx205022 		return (err);
10905574Smx205022 	ngep->watchdog = 0;
10915574Smx205022 	ngep->resched_needed = B_FALSE;
10925574Smx205022 	ngep->promisc = B_FALSE;
10935574Smx205022 	ngep->param_loop_mode = NGE_LOOP_NONE;
10945574Smx205022 	ngep->factotum_flag = 0;
10955574Smx205022 	ngep->resched_needed = 0;
10965574Smx205022 	ngep->nge_mac_state = NGE_MAC_RESET;
10975574Smx205022 	ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
10985574Smx205022 	ngep->max_sdu += VTAG_SIZE;
10995574Smx205022 	ngep->rx_def = 0x16;
11005869Smx205022 
11015869Smx205022 	/* Clear the software statistics */
11025869Smx205022 	sw_stp->recv_count = 0;
11035869Smx205022 	sw_stp->xmit_count = 0;
11045869Smx205022 	sw_stp->rbytes = 0;
11055869Smx205022 	sw_stp->obytes = 0;
11065869Smx205022 
11075574Smx205022 	return (DDI_SUCCESS);
11085574Smx205022 }
11095574Smx205022 
11105574Smx205022 static void
11115574Smx205022 nge_m_stop(void *arg)
11125574Smx205022 {
11135574Smx205022 	nge_t *ngep = arg;		/* private device info	*/
11145574Smx205022 
11155574Smx205022 	NGE_TRACE(("nge_m_stop($%p)", arg));
11165574Smx205022 
11175574Smx205022 	/*
11185574Smx205022 	 * Just stop processing, then record new MAC state
11195574Smx205022 	 */
11205574Smx205022 	mutex_enter(ngep->genlock);
11215869Smx205022 	/* If suspended, the adapter is already stopped, just return. */
11225869Smx205022 	if (ngep->suspended) {
11235869Smx205022 		ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
11245869Smx205022 		mutex_exit(ngep->genlock);
11255869Smx205022 		return;
11265869Smx205022 	}
11275574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11285574Smx205022 
11295574Smx205022 	(void) nge_chip_stop(ngep, B_FALSE);
11305574Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
11315574Smx205022 
11325574Smx205022 	/* Recycle all the TX BD */
11335574Smx205022 	nge_tx_recycle_all(ngep);
11345574Smx205022 	nge_fini_rings(ngep);
11355574Smx205022 	nge_free_bufs(ngep);
11365574Smx205022 
11375574Smx205022 	NGE_DEBUG(("nge_m_stop($%p) done", arg));
11385574Smx205022 
11395574Smx205022 	rw_exit(ngep->rwlock);
11405574Smx205022 	mutex_exit(ngep->genlock);
11415574Smx205022 }
11425574Smx205022 
11435574Smx205022 static int
11445574Smx205022 nge_m_start(void *arg)
11455574Smx205022 {
11465574Smx205022 	int err;
11475574Smx205022 	nge_t *ngep = arg;
11485574Smx205022 
11495574Smx205022 	NGE_TRACE(("nge_m_start($%p)", arg));
11505869Smx205022 
11515869Smx205022 	/*
11525869Smx205022 	 * Start processing and record new MAC state
11535869Smx205022 	 */
11545869Smx205022 	mutex_enter(ngep->genlock);
11555574Smx205022 	/*
11565574Smx205022 	 * If suspended, don't start, as the resume processing
11575574Smx205022 	 * will recall this function with the suspended flag off.
11585574Smx205022 	 */
11595869Smx205022 	if (ngep->suspended) {
11605869Smx205022 		mutex_exit(ngep->genlock);
11615988Svb160487 		return (EIO);
11625869Smx205022 	}
11635574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11645574Smx205022 	err = nge_alloc_bufs(ngep);
11655574Smx205022 	if (err != DDI_SUCCESS) {
11665574Smx205022 		nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
11675574Smx205022 		goto finish;
11685574Smx205022 	}
11695574Smx205022 	err = nge_init_rings(ngep);
11705574Smx205022 	if (err != DDI_SUCCESS) {
11715574Smx205022 		nge_free_bufs(ngep);
11725988Svb160487 		nge_problem(ngep, "nge_init_rings() failed,err=%x", err);
11735574Smx205022 		goto finish;
11745574Smx205022 	}
11755574Smx205022 	err = nge_restart(ngep);
11765574Smx205022 
11775574Smx205022 	NGE_DEBUG(("nge_m_start($%p) done", arg));
11785988Svb160487 finish:
11795988Svb160487 	rw_exit(ngep->rwlock);
11805988Svb160487 	mutex_exit(ngep->genlock);
11815574Smx205022 
11825988Svb160487 	return (err == DDI_SUCCESS ? 0 : EIO);
11835574Smx205022 }
11845574Smx205022 
11855574Smx205022 static int
11865574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr)
11875574Smx205022 {
11885574Smx205022 	nge_t *ngep = arg;
11895574Smx205022 
11905574Smx205022 	NGE_TRACE(("nge_m_unicst($%p)", arg));
11915574Smx205022 	/*
11925574Smx205022 	 * Remember the new current address in the driver state
11935574Smx205022 	 * Sync the chip's idea of the address too ...
11945574Smx205022 	 */
11955574Smx205022 	mutex_enter(ngep->genlock);
11965574Smx205022 
11975574Smx205022 	ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
11985574Smx205022 	ngep->cur_uni_addr.set = 1;
11995574Smx205022 
12005574Smx205022 	/*
12015574Smx205022 	 * If we are suspended, we want to quit now, and not update
12025574Smx205022 	 * the chip.  Doing so might put it in a bad state, but the
12035574Smx205022 	 * resume will get the unicast address installed.
12045574Smx205022 	 */
12055869Smx205022 	if (ngep->suspended) {
12065869Smx205022 		mutex_exit(ngep->genlock);
12075574Smx205022 		return (DDI_SUCCESS);
12085869Smx205022 	}
12095574Smx205022 	nge_chip_sync(ngep);
12105574Smx205022 
12115574Smx205022 	NGE_DEBUG(("nge_m_unicst($%p) done", arg));
12125574Smx205022 	mutex_exit(ngep->genlock);
12135574Smx205022 
12145574Smx205022 	return (0);
12155574Smx205022 }
12165574Smx205022 
12175574Smx205022 static int
12185574Smx205022 nge_m_promisc(void *arg, boolean_t on)
12195574Smx205022 {
12205574Smx205022 	nge_t *ngep = arg;
12215574Smx205022 
12225574Smx205022 	NGE_TRACE(("nge_m_promisc($%p)", arg));
12235574Smx205022 
12245574Smx205022 	/*
12255574Smx205022 	 * Store specified mode and pass to chip layer to update h/w
12265574Smx205022 	 */
12275574Smx205022 	mutex_enter(ngep->genlock);
12285869Smx205022 	/*
12295869Smx205022 	 * If suspended, there is no need to do anything, even
12305869Smx205022 	 * recording the promiscuious mode is not neccessary, as
12315869Smx205022 	 * it won't be properly set on resume.  Just return failing.
12325869Smx205022 	 */
12335869Smx205022 	if (ngep->suspended) {
12345869Smx205022 		mutex_exit(ngep->genlock);
12355869Smx205022 		return (DDI_FAILURE);
12365869Smx205022 	}
12375574Smx205022 	if (ngep->promisc == on) {
12385574Smx205022 		mutex_exit(ngep->genlock);
12395574Smx205022 		NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12405574Smx205022 		return (0);
12415574Smx205022 	}
12425574Smx205022 	ngep->promisc = on;
1243*7155Smx205022 	ngep->record_promisc = ngep->promisc;
12445574Smx205022 	nge_chip_sync(ngep);
12455574Smx205022 	NGE_DEBUG(("nge_m_promisc($%p) done", arg));
12465574Smx205022 	mutex_exit(ngep->genlock);
12475574Smx205022 
12485574Smx205022 	return (0);
12495574Smx205022 }
12505574Smx205022 
12515574Smx205022 static void nge_mulparam(nge_t *ngep)
12525574Smx205022 {
12535574Smx205022 	uint8_t number;
12545574Smx205022 	ether_addr_t pand;
12555574Smx205022 	ether_addr_t por;
12565574Smx205022 	mul_item *plist;
12575574Smx205022 
12585574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12595574Smx205022 		pand[number] = 0x00;
12605574Smx205022 		por[number] = 0x00;
12615574Smx205022 	}
12625574Smx205022 	for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
12635574Smx205022 		for (number = 0; number < ETHERADDRL; number++) {
12645574Smx205022 			pand[number] &= plist->mul_addr[number];
12655574Smx205022 			por[number] |= plist->mul_addr[number];
12665574Smx205022 		}
12675574Smx205022 	}
12685574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12695574Smx205022 		ngep->cur_mul_addr.addr[number]
12705574Smx205022 		    = pand[number] & por[number];
12715574Smx205022 		ngep->cur_mul_mask.addr[number]
12725574Smx205022 		    = pand [number] | (~por[number]);
12735574Smx205022 	}
12745574Smx205022 }
12755574Smx205022 static int
12765574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
12775574Smx205022 {
12785574Smx205022 	boolean_t update;
12795574Smx205022 	boolean_t b_eq;
12805574Smx205022 	nge_t *ngep = arg;
12815574Smx205022 	mul_item *plist;
12825574Smx205022 	mul_item *plist_prev;
12835574Smx205022 	mul_item *pitem;
12845574Smx205022 
12855574Smx205022 	NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
12865574Smx205022 	    (add) ? "add" : "remove", ether_sprintf((void *)mca)));
12875574Smx205022 
12885574Smx205022 	update = B_FALSE;
12895574Smx205022 	plist = plist_prev = NULL;
12905574Smx205022 	mutex_enter(ngep->genlock);
12915574Smx205022 	if (add) {
12925574Smx205022 		if (ngep->pcur_mulist != NULL) {
12935574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
12945574Smx205022 			    plist = plist->next) {
12955574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
12965574Smx205022 				if (b_eq) {
12975574Smx205022 					plist->ref_cnt++;
12985574Smx205022 					break;
12995574Smx205022 				}
13005574Smx205022 				plist_prev = plist;
13015574Smx205022 			}
13025574Smx205022 		}
13035574Smx205022 
13045574Smx205022 		if (plist == NULL) {
13055574Smx205022 			pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
13065574Smx205022 			ether_copy(mca, pitem->mul_addr);
13075574Smx205022 			pitem ->ref_cnt++;
13085574Smx205022 			pitem ->next = NULL;
13095574Smx205022 			if (plist_prev == NULL)
13105574Smx205022 				ngep->pcur_mulist = pitem;
13115574Smx205022 			else
13125574Smx205022 				plist_prev->next = pitem;
13135574Smx205022 			update = B_TRUE;
13145574Smx205022 		}
13155574Smx205022 	} else {
13165574Smx205022 		if (ngep->pcur_mulist != NULL) {
13175574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
13185574Smx205022 			    plist = plist->next) {
13195574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
13205574Smx205022 				if (b_eq) {
13215574Smx205022 					update = B_TRUE;
13225574Smx205022 					break;
13235574Smx205022 				}
13245574Smx205022 				plist_prev = plist;
13255574Smx205022 			}
13265574Smx205022 
13275574Smx205022 			if (update) {
13285574Smx205022 				if ((plist_prev == NULL) &&
13295574Smx205022 				    (plist->next == NULL))
13305574Smx205022 					ngep->pcur_mulist = NULL;
13315574Smx205022 				else if ((plist_prev == NULL) &&
13325574Smx205022 				    (plist->next != NULL))
13335574Smx205022 					ngep->pcur_mulist = plist->next;
13345574Smx205022 				else
13355574Smx205022 					plist_prev->next = plist->next;
13365574Smx205022 				kmem_free(plist, sizeof (mul_item));
13375574Smx205022 			}
13385574Smx205022 		}
13395574Smx205022 	}
13405574Smx205022 
13415869Smx205022 	if (update && !ngep->suspended) {
13425574Smx205022 		nge_mulparam(ngep);
13435574Smx205022 		nge_chip_sync(ngep);
13445574Smx205022 	}
13455574Smx205022 	NGE_DEBUG(("nge_m_multicst($%p) done", arg));
13465574Smx205022 	mutex_exit(ngep->genlock);
13475574Smx205022 
13485574Smx205022 	return (0);
13495574Smx205022 }
13505574Smx205022 
13515574Smx205022 static void
13525574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
13535574Smx205022 {
13545574Smx205022 	int err;
13555574Smx205022 	int cmd;
13565574Smx205022 	nge_t *ngep = arg;
13575574Smx205022 	struct iocblk *iocp;
13585574Smx205022 	enum ioc_reply status;
13595574Smx205022 	boolean_t need_privilege;
13605574Smx205022 
13615574Smx205022 	/*
13625574Smx205022 	 * If suspended, we might actually be able to do some of
13635574Smx205022 	 * these ioctls, but it is harder to make sure they occur
13645574Smx205022 	 * without actually putting the hardware in an undesireable
13655574Smx205022 	 * state.  So just NAK it.
13665574Smx205022 	 */
13675869Smx205022 	mutex_enter(ngep->genlock);
13685574Smx205022 	if (ngep->suspended) {
13695574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13705869Smx205022 		mutex_exit(ngep->genlock);
13715574Smx205022 		return;
13725574Smx205022 	}
13735869Smx205022 	mutex_exit(ngep->genlock);
13745574Smx205022 
13755574Smx205022 	/*
13765574Smx205022 	 * Validate the command before bothering with the mutex ...
13775574Smx205022 	 */
13785574Smx205022 	iocp = (struct iocblk *)mp->b_rptr;
13795574Smx205022 	iocp->ioc_error = 0;
13805574Smx205022 	need_privilege = B_TRUE;
13815574Smx205022 	cmd = iocp->ioc_cmd;
13825574Smx205022 
13835574Smx205022 	NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
13845574Smx205022 	switch (cmd) {
13855574Smx205022 	default:
13865574Smx205022 		NGE_LDB(NGE_DBG_BADIOC,
13875574Smx205022 		    ("nge_m_ioctl: unknown cmd 0x%x", cmd));
13885574Smx205022 
13895574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13905574Smx205022 		return;
13915574Smx205022 
13925574Smx205022 	case NGE_MII_READ:
13935574Smx205022 	case NGE_MII_WRITE:
13945574Smx205022 	case NGE_SEE_READ:
13955574Smx205022 	case NGE_SEE_WRITE:
13965574Smx205022 	case NGE_DIAG:
13975574Smx205022 	case NGE_PEEK:
13985574Smx205022 	case NGE_POKE:
13995574Smx205022 	case NGE_PHY_RESET:
14005574Smx205022 	case NGE_SOFT_RESET:
14015574Smx205022 	case NGE_HARD_RESET:
14025574Smx205022 		break;
14035574Smx205022 
14045574Smx205022 	case LB_GET_INFO_SIZE:
14055574Smx205022 	case LB_GET_INFO:
14065574Smx205022 	case LB_GET_MODE:
14075574Smx205022 		need_privilege = B_FALSE;
14085574Smx205022 		break;
14095574Smx205022 	case LB_SET_MODE:
14105574Smx205022 		break;
14115574Smx205022 	}
14125574Smx205022 
14135574Smx205022 	if (need_privilege) {
14145574Smx205022 		/*
14155574Smx205022 		 * Check for specific net_config privilege.
14165574Smx205022 		 */
14175574Smx205022 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
14185574Smx205022 		if (err != 0) {
14195574Smx205022 			NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
14205574Smx205022 			    cmd, err));
14215574Smx205022 			miocnak(wq, mp, 0, err);
14225574Smx205022 			return;
14235574Smx205022 		}
14245574Smx205022 	}
14255574Smx205022 
14265574Smx205022 	mutex_enter(ngep->genlock);
14275574Smx205022 
14285574Smx205022 	switch (cmd) {
14295574Smx205022 	default:
14305574Smx205022 		_NOTE(NOTREACHED)
14315574Smx205022 		status = IOC_INVAL;
14325574Smx205022 	break;
14335574Smx205022 
14345574Smx205022 	case NGE_MII_READ:
14355574Smx205022 	case NGE_MII_WRITE:
14365574Smx205022 	case NGE_SEE_READ:
14375574Smx205022 	case NGE_SEE_WRITE:
14385574Smx205022 	case NGE_DIAG:
14395574Smx205022 	case NGE_PEEK:
14405574Smx205022 	case NGE_POKE:
14415574Smx205022 	case NGE_PHY_RESET:
14425574Smx205022 	case NGE_SOFT_RESET:
14435574Smx205022 	case NGE_HARD_RESET:
14445574Smx205022 		status = nge_chip_ioctl(ngep, mp, iocp);
14455574Smx205022 	break;
14465574Smx205022 
14475574Smx205022 	case LB_GET_INFO_SIZE:
14485574Smx205022 	case LB_GET_INFO:
14495574Smx205022 	case LB_GET_MODE:
14505574Smx205022 	case LB_SET_MODE:
14515574Smx205022 		status = nge_loop_ioctl(ngep, mp, iocp);
14525574Smx205022 	break;
14535574Smx205022 
14545574Smx205022 	}
14555574Smx205022 
14565574Smx205022 	/*
14575574Smx205022 	 * Do we need to reprogram the PHY and/or the MAC?
14585574Smx205022 	 * Do it now, while we still have the mutex.
14595574Smx205022 	 *
14605574Smx205022 	 * Note: update the PHY first, 'cos it controls the
14615574Smx205022 	 * speed/duplex parameters that the MAC code uses.
14625574Smx205022 	 */
14635574Smx205022 
14645574Smx205022 	NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
14655574Smx205022 
14665574Smx205022 	switch (status) {
14675574Smx205022 	case IOC_RESTART_REPLY:
14685574Smx205022 	case IOC_RESTART_ACK:
14695574Smx205022 		(*ngep->physops->phys_update)(ngep);
14705574Smx205022 		nge_chip_sync(ngep);
14715574Smx205022 		break;
14725574Smx205022 
14735574Smx205022 	default:
14745574Smx205022 	break;
14755574Smx205022 	}
14765574Smx205022 
14775574Smx205022 	mutex_exit(ngep->genlock);
14785574Smx205022 
14795574Smx205022 	/*
14805574Smx205022 	 * Finally, decide how to reply
14815574Smx205022 	 */
14825574Smx205022 	switch (status) {
14835574Smx205022 
14845574Smx205022 	default:
14855574Smx205022 	case IOC_INVAL:
14865574Smx205022 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
14875574Smx205022 		    EINVAL : iocp->ioc_error);
14885574Smx205022 		break;
14895574Smx205022 
14905574Smx205022 	case IOC_DONE:
14915574Smx205022 		break;
14925574Smx205022 
14935574Smx205022 	case IOC_RESTART_ACK:
14945574Smx205022 	case IOC_ACK:
14955574Smx205022 		miocack(wq, mp, 0, 0);
14965574Smx205022 		break;
14975574Smx205022 
14985574Smx205022 	case IOC_RESTART_REPLY:
14995574Smx205022 	case IOC_REPLY:
15005574Smx205022 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
15015574Smx205022 		    M_IOCACK : M_IOCNAK;
15025574Smx205022 		qreply(wq, mp);
15035574Smx205022 		break;
15045574Smx205022 	}
15055574Smx205022 }
15065574Smx205022 
15076200Smx205022 static boolean_t
15086200Smx205022 nge_param_locked(mac_prop_id_t pr_num)
15096200Smx205022 {
15106200Smx205022 	/*
15116200Smx205022 	 * All adv_* parameters are locked (read-only) while
15126200Smx205022 	 * the device is in any sort of loopback mode ...
15136200Smx205022 	 */
15146200Smx205022 	switch (pr_num) {
15156789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15166789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15176789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15186789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
15196789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15206789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15216789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15226789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15236789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15246789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15256789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15266789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15276789Sam223141 		case MAC_PROP_AUTONEG:
15286789Sam223141 		case MAC_PROP_FLOWCTRL:
15296200Smx205022 			return (B_TRUE);
15306200Smx205022 	}
15316200Smx205022 	return (B_FALSE);
15326200Smx205022 }
15336200Smx205022 
15346200Smx205022 /*
15356200Smx205022  * callback functions for set/get of properties
15366200Smx205022  */
15376200Smx205022 static int
15386200Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
15396200Smx205022     uint_t pr_valsize, const void *pr_val)
15406200Smx205022 {
15416200Smx205022 	nge_t *ngep = barg;
15426200Smx205022 	int err = 0;
15436512Ssowmini 	uint32_t cur_mtu, new_mtu;
15446200Smx205022 	link_flowctrl_t fl;
15456200Smx205022 
15466200Smx205022 	mutex_enter(ngep->genlock);
15476200Smx205022 	if (ngep->param_loop_mode != NGE_LOOP_NONE &&
15486200Smx205022 	    nge_param_locked(pr_num)) {
15496200Smx205022 		/*
15506200Smx205022 		 * All adv_* parameters are locked (read-only)
15516200Smx205022 		 * while the device is in any sort of loopback mode.
15526200Smx205022 		 */
15536200Smx205022 		mutex_exit(ngep->genlock);
15546200Smx205022 		return (EBUSY);
15556200Smx205022 	}
15566200Smx205022 	switch (pr_num) {
15576789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
15586200Smx205022 			ngep->param_en_1000fdx = *(uint8_t *)pr_val;
15596200Smx205022 			ngep->param_adv_1000fdx = *(uint8_t *)pr_val;
15606200Smx205022 			goto reprogram;
15616789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
15626200Smx205022 			ngep->param_en_100fdx = *(uint8_t *)pr_val;
15636200Smx205022 			ngep->param_adv_100fdx = *(uint8_t *)pr_val;
15646200Smx205022 			goto reprogram;
15656789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
15666200Smx205022 			ngep->param_en_100hdx = *(uint8_t *)pr_val;
15676200Smx205022 			ngep->param_adv_100hdx = *(uint8_t *)pr_val;
15686200Smx205022 			goto reprogram;
15696789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
15706200Smx205022 			ngep->param_en_10fdx = *(uint8_t *)pr_val;
15716200Smx205022 			ngep->param_adv_10fdx = *(uint8_t *)pr_val;
15726200Smx205022 			goto reprogram;
15736789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
15746200Smx205022 			ngep->param_en_10hdx = *(uint8_t *)pr_val;
15756200Smx205022 			ngep->param_adv_10hdx = *(uint8_t *)pr_val;
15766200Smx205022 reprogram:
15776200Smx205022 		(*ngep->physops->phys_update)(ngep);
15786200Smx205022 		nge_chip_sync(ngep);
15796200Smx205022 		break;
15806200Smx205022 
15816789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
15826789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
15836789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
15846789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
15856789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
15866789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
15876789Sam223141 		case MAC_PROP_STATUS:
15886789Sam223141 		case MAC_PROP_SPEED:
15896789Sam223141 		case MAC_PROP_DUPLEX:
15906789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
15916200Smx205022 			err = ENOTSUP; /* read-only prop. Can't set this */
15926200Smx205022 			break;
15936789Sam223141 		case MAC_PROP_AUTONEG:
15946200Smx205022 			ngep->param_adv_autoneg = *(uint8_t *)pr_val;
15956200Smx205022 			(*ngep->physops->phys_update)(ngep);
15966200Smx205022 			nge_chip_sync(ngep);
15976200Smx205022 			break;
15986789Sam223141 		case MAC_PROP_MTU:
15996200Smx205022 			cur_mtu = ngep->default_mtu;
16006200Smx205022 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
16016200Smx205022 			if (new_mtu == cur_mtu) {
16026200Smx205022 				err = 0;
16036200Smx205022 				break;
16046200Smx205022 			}
16056200Smx205022 			if (new_mtu < ETHERMTU ||
16066200Smx205022 			    new_mtu > NGE_MAX_MTU) {
16076200Smx205022 				err = EINVAL;
16086200Smx205022 				break;
16096200Smx205022 			}
16106200Smx205022 			if ((new_mtu > ETHERMTU) &&
16116200Smx205022 			    (!ngep->dev_spec_param.jumbo)) {
16126200Smx205022 				err = EINVAL;
16136200Smx205022 				break;
16146200Smx205022 			}
16156200Smx205022 			if (ngep->nge_mac_state == NGE_MAC_STARTED) {
16166200Smx205022 				err = EBUSY;
16176200Smx205022 				break;
16186200Smx205022 			}
16196200Smx205022 
16206200Smx205022 			ngep->default_mtu = new_mtu;
16216200Smx205022 			if (ngep->default_mtu > ETHERMTU &&
16226200Smx205022 			    ngep->default_mtu <= NGE_MTU_2500) {
16236200Smx205022 				ngep->buf_size = NGE_JB2500_BUFSZ;
16246200Smx205022 				ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
16256200Smx205022 				ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
16266200Smx205022 				ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
16276200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16286200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_2500 &&
16296200Smx205022 			    ngep->default_mtu <= NGE_MTU_4500) {
16306200Smx205022 				ngep->buf_size = NGE_JB4500_BUFSZ;
16316200Smx205022 				ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
16326200Smx205022 				ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
16336200Smx205022 				ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
16346200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16356200Smx205022 			} else if (ngep->default_mtu > NGE_MTU_4500 &&
16366200Smx205022 			    ngep->default_mtu <= NGE_MAX_MTU) {
16376200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16386200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16396200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16406200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16416200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16426200Smx205022 			} else if (ngep->default_mtu > NGE_MAX_MTU) {
16436200Smx205022 				ngep->default_mtu = NGE_MAX_MTU;
16446200Smx205022 				ngep->buf_size = NGE_JB9000_BUFSZ;
16456200Smx205022 				ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
16466200Smx205022 				ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
16476200Smx205022 				ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
16486200Smx205022 				ngep->nge_split = NGE_SPLIT_256;
16496200Smx205022 			} else if (ngep->lowmem_mode != 0) {
16506200Smx205022 				ngep->default_mtu = ETHERMTU;
16516200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16526200Smx205022 				ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
16536200Smx205022 				ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
16546200Smx205022 				ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
16556200Smx205022 				ngep->nge_split = NGE_SPLIT_32;
16566200Smx205022 			} else {
16576200Smx205022 				ngep->default_mtu = ETHERMTU;
16586200Smx205022 				ngep->buf_size = NGE_STD_BUFSZ;
16596200Smx205022 				ngep->tx_desc =
16606200Smx205022 				    ngep->dev_spec_param.tx_desc_num;
16616200Smx205022 				ngep->rx_desc =
16626200Smx205022 				    ngep->dev_spec_param.rx_desc_num;
16636200Smx205022 				ngep->rx_buf =
16646200Smx205022 				    ngep->dev_spec_param.rx_desc_num * 2;
16656200Smx205022 				ngep->nge_split =
16666200Smx205022 				    ngep->dev_spec_param.nge_split;
16676200Smx205022 			}
16686200Smx205022 
16696200Smx205022 			err = mac_maxsdu_update(ngep->mh, ngep->default_mtu);
16706200Smx205022 
16716200Smx205022 			break;
16726789Sam223141 		case MAC_PROP_FLOWCTRL:
16736200Smx205022 			bcopy(pr_val, &fl, sizeof (fl));
16746200Smx205022 			switch (fl) {
16756200Smx205022 			default:
16766200Smx205022 				err = ENOTSUP;
16776200Smx205022 				break;
16786200Smx205022 			case LINK_FLOWCTRL_NONE:
16796200Smx205022 				ngep->param_adv_pause = 0;
16806200Smx205022 				ngep->param_adv_asym_pause = 0;
16816200Smx205022 
16826200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
16836200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
16846200Smx205022 				break;
16856200Smx205022 			case LINK_FLOWCTRL_RX:
16866200Smx205022 				if (!((ngep->param_lp_pause == 0) &&
16876200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
16886200Smx205022 					err = EINVAL;
16896200Smx205022 					break;
16906200Smx205022 				}
16916200Smx205022 				ngep->param_adv_pause = 1;
16926200Smx205022 				ngep->param_adv_asym_pause = 1;
16936200Smx205022 
16946200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
16956200Smx205022 				ngep->param_link_tx_pause = B_FALSE;
16966200Smx205022 				break;
16976200Smx205022 			case LINK_FLOWCTRL_TX:
16986200Smx205022 				if (!((ngep->param_lp_pause == 1) &&
16996200Smx205022 				    (ngep->param_lp_asym_pause == 1))) {
17006200Smx205022 					err = EINVAL;
17016200Smx205022 					break;
17026200Smx205022 				}
17036200Smx205022 				ngep->param_adv_pause = 0;
17046200Smx205022 				ngep->param_adv_asym_pause = 1;
17056200Smx205022 
17066200Smx205022 				ngep->param_link_rx_pause = B_FALSE;
17076200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17086200Smx205022 				break;
17096200Smx205022 			case LINK_FLOWCTRL_BI:
17106200Smx205022 				if (ngep->param_lp_pause != 1) {
17116200Smx205022 					err = EINVAL;
17126200Smx205022 					break;
17136200Smx205022 				}
17146200Smx205022 				ngep->param_adv_pause = 1;
17156200Smx205022 
17166200Smx205022 				ngep->param_link_rx_pause = B_TRUE;
17176200Smx205022 				ngep->param_link_tx_pause = B_TRUE;
17186200Smx205022 				break;
17196200Smx205022 			}
17206200Smx205022 
17216200Smx205022 			if (err == 0) {
17226200Smx205022 				(*ngep->physops->phys_update)(ngep);
17236200Smx205022 				nge_chip_sync(ngep);
17246200Smx205022 			}
17256200Smx205022 
17266200Smx205022 			break;
17276789Sam223141 		case MAC_PROP_PRIVATE:
17286200Smx205022 			err = nge_set_priv_prop(ngep, pr_name, pr_valsize,
17296200Smx205022 			    pr_val);
17306200Smx205022 			if (err == 0) {
17316200Smx205022 				(*ngep->physops->phys_update)(ngep);
17326200Smx205022 				nge_chip_sync(ngep);
17336200Smx205022 			}
17346200Smx205022 			break;
17356200Smx205022 		default:
17366200Smx205022 			err = ENOTSUP;
17376200Smx205022 	}
17386200Smx205022 	mutex_exit(ngep->genlock);
17396200Smx205022 	return (err);
17406200Smx205022 }
17416200Smx205022 
17426200Smx205022 static int
17436200Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
17446512Ssowmini     uint_t pr_flags, uint_t pr_valsize, void *pr_val)
17456200Smx205022 {
17466200Smx205022 	nge_t *ngep = barg;
17476512Ssowmini 	int err = 0;
17486200Smx205022 	link_flowctrl_t fl;
17496512Ssowmini 	uint64_t speed;
17506789Sam223141 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
17516512Ssowmini 
17526512Ssowmini 	if (pr_valsize == 0)
17536512Ssowmini 		return (EINVAL);
17546200Smx205022 
17556200Smx205022 	bzero(pr_val, pr_valsize);
17566200Smx205022 	switch (pr_num) {
17576789Sam223141 		case MAC_PROP_DUPLEX:
17586512Ssowmini 			if (pr_valsize >= sizeof (link_duplex_t)) {
17596512Ssowmini 				bcopy(&ngep->param_link_duplex, pr_val,
17606512Ssowmini 				    sizeof (link_duplex_t));
17616512Ssowmini 			} else
17626512Ssowmini 				err = EINVAL;
17636200Smx205022 			break;
17646789Sam223141 		case MAC_PROP_SPEED:
17656200Smx205022 			if (pr_valsize >= sizeof (uint64_t)) {
17666512Ssowmini 				speed = ngep->param_link_speed * 1000000ull;
17676512Ssowmini 				bcopy(&speed, pr_val, sizeof (speed));
17686512Ssowmini 			} else
17696512Ssowmini 				err = EINVAL;
17706200Smx205022 			break;
17716789Sam223141 		case MAC_PROP_AUTONEG:
17726512Ssowmini 			if (is_default) {
17736512Ssowmini 				*(uint8_t *)pr_val = 1;
17746512Ssowmini 			} else {
17756200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_autoneg;
17766200Smx205022 			}
17776200Smx205022 			break;
17786789Sam223141 		case MAC_PROP_FLOWCTRL:
17796200Smx205022 			if (pr_valsize >= sizeof (link_flowctrl_t)) {
17806789Sam223141 				if (pr_flags & MAC_PROP_DEFAULT) {
17816512Ssowmini 					fl = LINK_FLOWCTRL_BI;
17826512Ssowmini 					bcopy(&fl, pr_val, sizeof (fl));
17836512Ssowmini 					break;
17846512Ssowmini 				}
17856200Smx205022 				if (ngep->param_link_rx_pause &&
17866200Smx205022 				    !ngep->param_link_tx_pause)
17876200Smx205022 					fl = LINK_FLOWCTRL_RX;
17886200Smx205022 
17896200Smx205022 				if (!ngep->param_link_rx_pause &&
17906200Smx205022 				    !ngep->param_link_tx_pause)
17916200Smx205022 					fl = LINK_FLOWCTRL_NONE;
17926200Smx205022 
17936200Smx205022 				if (!ngep->param_link_rx_pause &&
17946200Smx205022 				    ngep->param_link_tx_pause)
17956200Smx205022 					fl = LINK_FLOWCTRL_TX;
17966200Smx205022 
17976200Smx205022 				if (ngep->param_link_rx_pause &&
17986200Smx205022 				    ngep->param_link_tx_pause)
17996200Smx205022 					fl = LINK_FLOWCTRL_BI;
18006200Smx205022 				bcopy(&fl, pr_val, sizeof (fl));
18016512Ssowmini 			} else
18026512Ssowmini 				err = EINVAL;
18036200Smx205022 			break;
18046789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
18056512Ssowmini 			if (is_default) {
18066512Ssowmini 				*(uint8_t *)pr_val = 1;
18076512Ssowmini 			} else {
18086200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_1000fdx;
18096200Smx205022 			}
18106200Smx205022 			break;
18116789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
18126512Ssowmini 			if (is_default) {
18136512Ssowmini 				*(uint8_t *)pr_val = 1;
18146512Ssowmini 			} else {
18156200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_1000fdx;
18166200Smx205022 			}
18176200Smx205022 			break;
18186789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
18196512Ssowmini 			if (is_default) {
18206512Ssowmini 				*(uint8_t *)pr_val = 0;
18216512Ssowmini 			} else {
18226200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_1000hdx;
18236200Smx205022 			}
18246200Smx205022 			break;
18256789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
18266512Ssowmini 			if (is_default) {
18276512Ssowmini 				*(uint8_t *)pr_val = 0;
18286512Ssowmini 			} else {
18296200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_1000hdx;
18306200Smx205022 			}
18316200Smx205022 			break;
18326789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
18336512Ssowmini 			if (is_default) {
18346512Ssowmini 				*(uint8_t *)pr_val = 1;
18356512Ssowmini 			} else {
18366200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_100fdx;
18376200Smx205022 			}
18386200Smx205022 			break;
18396789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
18406512Ssowmini 			if (is_default) {
18416512Ssowmini 				*(uint8_t *)pr_val = 1;
18426512Ssowmini 			} else {
18436200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_100fdx;
18446200Smx205022 			}
18456200Smx205022 			break;
18466789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
18476512Ssowmini 			if (is_default) {
18486512Ssowmini 				*(uint8_t *)pr_val = 1;
18496512Ssowmini 			} else {
18506200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_100hdx;
18516200Smx205022 			}
18526200Smx205022 			break;
18536789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
18546512Ssowmini 			if (is_default) {
18556512Ssowmini 				*(uint8_t *)pr_val = 1;
18566512Ssowmini 			} else {
18576200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_100hdx;
18586200Smx205022 			}
18596200Smx205022 			break;
18606789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
18616512Ssowmini 			if (is_default) {
18626512Ssowmini 				*(uint8_t *)pr_val = 1;
18636512Ssowmini 			} else {
18646200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_10fdx;
18656200Smx205022 			}
18666200Smx205022 			break;
18676789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
18686512Ssowmini 			if (is_default) {
18696512Ssowmini 				*(uint8_t *)pr_val = 1;
18706512Ssowmini 			} else {
18716200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_10fdx;
18726200Smx205022 			}
18736200Smx205022 			break;
18746789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
18756512Ssowmini 			if (is_default) {
18766512Ssowmini 				*(uint8_t *)pr_val = 1;
18776512Ssowmini 			} else {
18786200Smx205022 				*(uint8_t *)pr_val = ngep->param_adv_10hdx;
18796200Smx205022 			}
18806200Smx205022 			break;
18816789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
18826512Ssowmini 			if (is_default) {
18836512Ssowmini 				*(uint8_t *)pr_val = 1;
18846512Ssowmini 			} else {
18856200Smx205022 				*(uint8_t *)pr_val = ngep->param_en_10hdx;
18866200Smx205022 			}
18876200Smx205022 			break;
18886789Sam223141 		case MAC_PROP_ADV_100T4_CAP:
18896789Sam223141 		case MAC_PROP_EN_100T4_CAP:
18906512Ssowmini 			*(uint8_t *)pr_val = 0;
18916512Ssowmini 			break;
18926789Sam223141 		case MAC_PROP_PRIVATE:
18936512Ssowmini 			err = nge_get_priv_prop(ngep, pr_name, pr_flags,
18946512Ssowmini 			    pr_valsize, pr_val);
18956200Smx205022 			break;
18966200Smx205022 		default:
18976200Smx205022 			err = ENOTSUP;
18986200Smx205022 	}
18996200Smx205022 	return (err);
19006200Smx205022 }
19016200Smx205022 
19026200Smx205022 /* ARGSUSED */
19036200Smx205022 static int
19046200Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize,
19056200Smx205022     const void *pr_val)
19066200Smx205022 {
19076200Smx205022 	int err = 0;
19086200Smx205022 	long result;
19096200Smx205022 
19106200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
19116200Smx205022 		if (pr_val == NULL) {
19126200Smx205022 			err = EINVAL;
19136200Smx205022 			return (err);
19146200Smx205022 		}
19156200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19166200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19176200Smx205022 			err = EINVAL;
19186200Smx205022 		} else {
19196200Smx205022 			ngep->param_txbcopy_threshold = (uint32_t)result;
19206200Smx205022 			goto reprogram;
19216200Smx205022 		}
19226200Smx205022 		return (err);
19236200Smx205022 	}
19246200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
19256200Smx205022 		if (pr_val == NULL) {
19266200Smx205022 			err = EINVAL;
19276200Smx205022 			return (err);
19286200Smx205022 		}
19296200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19306200Smx205022 		if (result < 0 || result > NGE_MAX_SDU) {
19316200Smx205022 			err = EINVAL;
19326200Smx205022 		} else {
19336200Smx205022 			ngep->param_rxbcopy_threshold = (uint32_t)result;
19346200Smx205022 			goto reprogram;
19356200Smx205022 		}
19366200Smx205022 		return (err);
19376200Smx205022 	}
19386200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
19396200Smx205022 		if (pr_val == NULL) {
19406200Smx205022 			err = EINVAL;
19416200Smx205022 			return (err);
19426200Smx205022 		}
19436200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19446200Smx205022 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
19456200Smx205022 			err = EINVAL;
19466200Smx205022 		} else {
19476200Smx205022 			ngep->param_recv_max_packet = (uint32_t)result;
19486200Smx205022 			goto reprogram;
19496200Smx205022 		}
19506200Smx205022 		return (err);
19516200Smx205022 	}
19526200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
19536200Smx205022 		if (pr_val == NULL) {
19546200Smx205022 			err = EINVAL;
19556200Smx205022 			return (err);
19566200Smx205022 		}
19576200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19586200Smx205022 		if (result < 0 || result > 10000) {
19596200Smx205022 			err = EINVAL;
19606200Smx205022 		} else {
19616200Smx205022 			ngep->param_poll_quiet_time = (uint32_t)result;
19626200Smx205022 			goto reprogram;
19636200Smx205022 		}
19646200Smx205022 		return (err);
19656200Smx205022 	}
19666200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
19676200Smx205022 		if (pr_val == NULL) {
19686200Smx205022 			err = EINVAL;
19696200Smx205022 			return (err);
19706200Smx205022 		}
19716200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19726200Smx205022 		if (result < 0 || result > 10000) {
19736200Smx205022 			err = EINVAL;
19746200Smx205022 		} else {
19756200Smx205022 			ngep->param_poll_busy_time = (uint32_t)result;
19766200Smx205022 			goto reprogram;
19776200Smx205022 		}
19786200Smx205022 		return (err);
19796200Smx205022 	}
19806200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
19816200Smx205022 		if (pr_val == NULL) {
19826200Smx205022 			err = EINVAL;
19836200Smx205022 			return (err);
19846200Smx205022 		}
19856200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
19866512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
19876200Smx205022 			err = EINVAL;
19886200Smx205022 		} else {
19896200Smx205022 			ngep->param_rx_intr_hwater = (uint32_t)result;
19906200Smx205022 			goto reprogram;
19916200Smx205022 		}
19926200Smx205022 		return (err);
19936200Smx205022 	}
19946200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
19956200Smx205022 		if (pr_val == NULL) {
19966200Smx205022 			err = EINVAL;
19976200Smx205022 			return (err);
19986200Smx205022 		}
19996200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20006512Ssowmini 		if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) {
20016200Smx205022 			err = EINVAL;
20026200Smx205022 		} else {
20036200Smx205022 			ngep->param_rx_intr_lwater = (uint32_t)result;
20046200Smx205022 			goto reprogram;
20056200Smx205022 		}
20066200Smx205022 		return (err);
20076200Smx205022 	}
20086200Smx205022 	if (strcmp(pr_name, "_tx_n_intr") == 0) {
20096200Smx205022 		if (pr_val == NULL) {
20106200Smx205022 			err = EINVAL;
20116200Smx205022 			return (err);
20126200Smx205022 		}
20136200Smx205022 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
20146200Smx205022 		if (result < 1 || result > 10000) {
20156200Smx205022 			err = EINVAL;
20166200Smx205022 		} else {
20176200Smx205022 			ngep->param_tx_n_intr = (uint32_t)result;
20186200Smx205022 			goto reprogram;
20196200Smx205022 		}
20206200Smx205022 		return (err);
20216200Smx205022 	}
20226200Smx205022 
20236200Smx205022 	err = ENOTSUP;
20246200Smx205022 	return (err);
20256200Smx205022 
20266200Smx205022 reprogram:
20276200Smx205022 	if (err == 0) {
20286200Smx205022 		(*ngep->physops->phys_update)(ngep);
20296200Smx205022 		nge_chip_sync(ngep);
20306200Smx205022 	}
20316200Smx205022 
20326200Smx205022 	return (err);
20336200Smx205022 }
20346200Smx205022 
20356200Smx205022 static int
20366512Ssowmini nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_flags,
20376512Ssowmini     uint_t pr_valsize, void *pr_val)
20386200Smx205022 {
20396200Smx205022 	int err = ENOTSUP;
20406789Sam223141 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
20416512Ssowmini 	int value;
20426512Ssowmini 
20436512Ssowmini 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
20446512Ssowmini 		value = (is_default ? 1 : ngep->param_adv_pause);
20456512Ssowmini 		err = 0;
20466512Ssowmini 		goto done;
20476512Ssowmini 	}
20486512Ssowmini 	if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
20496512Ssowmini 		value = (is_default ? 1 : ngep->param_adv_asym_pause);
20506512Ssowmini 		err = 0;
20516512Ssowmini 		goto done;
20526512Ssowmini 	}
20536200Smx205022 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
20546512Ssowmini 		value = (is_default ? NGE_TX_COPY_SIZE :
20556512Ssowmini 		    ngep->param_txbcopy_threshold);
20566200Smx205022 		err = 0;
20576200Smx205022 		goto done;
20586200Smx205022 	}
20596200Smx205022 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
20606512Ssowmini 		value = (is_default ? NGE_RX_COPY_SIZE :
20616512Ssowmini 		    ngep->param_rxbcopy_threshold);
20626200Smx205022 		err = 0;
20636200Smx205022 		goto done;
20646200Smx205022 	}
20656200Smx205022 	if (strcmp(pr_name, "_recv_max_packet") == 0) {
20666512Ssowmini 		value = (is_default ? 128 : ngep->param_recv_max_packet);
20676200Smx205022 		err = 0;
20686200Smx205022 		goto done;
20696200Smx205022 	}
20706200Smx205022 	if (strcmp(pr_name, "_poll_quiet_time") == 0) {
20716512Ssowmini 		value = (is_default ? NGE_POLL_QUIET_TIME :
20726512Ssowmini 		    ngep->param_poll_quiet_time);
20736200Smx205022 		err = 0;
20746200Smx205022 		goto done;
20756200Smx205022 	}
20766200Smx205022 	if (strcmp(pr_name, "_poll_busy_time") == 0) {
20776512Ssowmini 		value = (is_default ? NGE_POLL_BUSY_TIME :
20786512Ssowmini 		    ngep->param_poll_busy_time);
20796200Smx205022 		err = 0;
20806200Smx205022 		goto done;
20816200Smx205022 	}
20826200Smx205022 	if (strcmp(pr_name, "_rx_intr_hwater") == 0) {
20836512Ssowmini 		value = (is_default ? 1 : ngep->param_rx_intr_hwater);
20846200Smx205022 		err = 0;
20856200Smx205022 		goto done;
20866200Smx205022 	}
20876200Smx205022 	if (strcmp(pr_name, "_rx_intr_lwater") == 0) {
20886512Ssowmini 		value = (is_default ? 8 : ngep->param_rx_intr_lwater);
20896200Smx205022 		err = 0;
20906200Smx205022 		goto done;
20916200Smx205022 	}
20926200Smx205022 	if (strcmp(pr_name, "_tx_n_intr") == 0) {
20936512Ssowmini 		value = (is_default ? NGE_TX_N_INTR :
20946512Ssowmini 		    ngep->param_tx_n_intr);
20956200Smx205022 		err = 0;
20966200Smx205022 		goto done;
20976200Smx205022 	}
20986200Smx205022 
20996200Smx205022 done:
21006200Smx205022 	if (err == 0) {
21016512Ssowmini 		(void) snprintf(pr_val, pr_valsize, "%d", value);
21026200Smx205022 	}
21036200Smx205022 	return (err);
21046200Smx205022 }
21056200Smx205022 
21065574Smx205022 /* ARGSUSED */
21075574Smx205022 static boolean_t
21085574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
21095574Smx205022 {
21105574Smx205022 	nge_t	*ngep = arg;
21115574Smx205022 	nge_dev_spec_param_t *dev_param_p;
21125574Smx205022 
21135574Smx205022 	dev_param_p = &ngep->dev_spec_param;
21145574Smx205022 
21155574Smx205022 	switch (cap) {
21165574Smx205022 	case MAC_CAPAB_HCKSUM: {
21175574Smx205022 		uint32_t *hcksum_txflags = cap_data;
21185574Smx205022 
21195574Smx205022 		if (dev_param_p->tx_hw_checksum) {
21205574Smx205022 			*hcksum_txflags = dev_param_p->tx_hw_checksum;
21215574Smx205022 		} else
21225574Smx205022 			return (B_FALSE);
21235574Smx205022 		break;
21245574Smx205022 	}
21255574Smx205022 	case MAC_CAPAB_POLL:
21265574Smx205022 		/*
21275574Smx205022 		 * There's nothing for us to fill in, simply returning
21285574Smx205022 		 * B_TRUE, stating that we support polling is sufficient.
21295574Smx205022 		 */
21305574Smx205022 		break;
21315574Smx205022 	default:
21325574Smx205022 		return (B_FALSE);
21335574Smx205022 	}
21345574Smx205022 	return (B_TRUE);
21355574Smx205022 }
21365574Smx205022 
21375574Smx205022 #undef	NGE_DBG
21385574Smx205022 #define	NGE_DBG	NGE_DBG_INIT	/* debug flag for this code	*/
21395574Smx205022 int
21405574Smx205022 nge_restart(nge_t *ngep)
21415574Smx205022 {
21425574Smx205022 	int err = 0;
21435869Smx205022 	err = nge_reset(ngep);
2144*7155Smx205022 	/* write back the promisc setting */
2145*7155Smx205022 	ngep->promisc = ngep->record_promisc;
21466366Smx205022 	nge_chip_sync(ngep);
21475869Smx205022 	if (!err)
21485869Smx205022 		err = nge_chip_start(ngep);
21495574Smx205022 
21505574Smx205022 	if (err) {
21515574Smx205022 		ngep->nge_mac_state = NGE_MAC_STOPPED;
21525574Smx205022 		return (DDI_FAILURE);
21535574Smx205022 	} else {
21545574Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
21555574Smx205022 		return (DDI_SUCCESS);
21565574Smx205022 	}
21575574Smx205022 }
21585574Smx205022 
21595574Smx205022 void
21605574Smx205022 nge_wake_factotum(nge_t *ngep)
21615574Smx205022 {
21625574Smx205022 	mutex_enter(ngep->softlock);
21635574Smx205022 	if (ngep->factotum_flag == 0) {
21645574Smx205022 		ngep->factotum_flag = 1;
21655574Smx205022 		(void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
21665574Smx205022 	}
21675574Smx205022 	mutex_exit(ngep->softlock);
21685574Smx205022 }
21695574Smx205022 
21705574Smx205022 /*
21715574Smx205022  * High-level cyclic handler
21725574Smx205022  *
21735574Smx205022  * This routine schedules a (low-level) softint callback to the
21745574Smx205022  * factotum.
21755574Smx205022  */
21765574Smx205022 
21775574Smx205022 static void
21785574Smx205022 nge_chip_cyclic(void *arg)
21795574Smx205022 {
21805574Smx205022 	nge_t *ngep;
21815574Smx205022 
21825574Smx205022 	ngep = (nge_t *)arg;
21835574Smx205022 
21845574Smx205022 	switch (ngep->nge_chip_state) {
21855574Smx205022 	default:
21865574Smx205022 		return;
21875574Smx205022 
21885574Smx205022 	case NGE_CHIP_RUNNING:
21895574Smx205022 		break;
21905574Smx205022 
21915574Smx205022 	case NGE_CHIP_FAULT:
21925574Smx205022 	case NGE_CHIP_ERROR:
21935574Smx205022 		break;
21945574Smx205022 	}
21955574Smx205022 
21965574Smx205022 	nge_wake_factotum(ngep);
21975574Smx205022 }
21985574Smx205022 
21995574Smx205022 static void
22005574Smx205022 nge_unattach(nge_t *ngep)
22015574Smx205022 {
22025574Smx205022 	send_ring_t *srp;
22035574Smx205022 	buff_ring_t *brp;
22045574Smx205022 
22055574Smx205022 	srp = ngep->send;
22065574Smx205022 	brp = ngep->buff;
22075574Smx205022 	NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
22085574Smx205022 
22095574Smx205022 	/*
22105574Smx205022 	 * Flag that no more activity may be initiated
22115574Smx205022 	 */
22125574Smx205022 	ngep->progress &= ~PROGRESS_READY;
22135574Smx205022 	ngep->nge_mac_state = NGE_MAC_UNATTACH;
22145574Smx205022 
22155574Smx205022 	/*
22165574Smx205022 	 * Quiesce the PHY and MAC (leave it reset but still powered).
22175574Smx205022 	 * Clean up and free all NGE data structures
22185574Smx205022 	 */
22195574Smx205022 	if (ngep->periodic_id != NULL) {
22205574Smx205022 		ddi_periodic_delete(ngep->periodic_id);
22215574Smx205022 		ngep->periodic_id = NULL;
22225574Smx205022 	}
22235574Smx205022 
22245574Smx205022 	if (ngep->progress & PROGRESS_KSTATS)
22255574Smx205022 		nge_fini_kstats(ngep);
22265574Smx205022 
22275574Smx205022 	if (ngep->progress & PROGRESS_HWINT) {
22285574Smx205022 		mutex_enter(ngep->genlock);
22295574Smx205022 		nge_restore_mac_addr(ngep);
22305574Smx205022 		(void) nge_chip_stop(ngep, B_FALSE);
22315574Smx205022 		mutex_exit(ngep->genlock);
22325574Smx205022 	}
22335574Smx205022 
22345574Smx205022 	if (ngep->progress & PROGRESS_SWINT)
22355574Smx205022 		nge_rem_intrs(ngep);
22365574Smx205022 
22375574Smx205022 	if (ngep->progress & PROGRESS_FACTOTUM)
22385574Smx205022 		(void) ddi_intr_remove_softint(ngep->factotum_hdl);
22395574Smx205022 
22405574Smx205022 	if (ngep->progress & PROGRESS_RESCHED)
22415574Smx205022 		(void) ddi_intr_remove_softint(ngep->resched_hdl);
22425574Smx205022 
22435574Smx205022 	if (ngep->progress & PROGRESS_INTR) {
22445574Smx205022 		mutex_destroy(srp->tx_lock);
22455574Smx205022 		mutex_destroy(srp->tc_lock);
22465574Smx205022 		mutex_destroy(&srp->dmah_lock);
22475574Smx205022 		mutex_destroy(brp->recycle_lock);
22485574Smx205022 
22495574Smx205022 		mutex_destroy(ngep->genlock);
22505574Smx205022 		mutex_destroy(ngep->softlock);
22515574Smx205022 		rw_destroy(ngep->rwlock);
22525574Smx205022 	}
22535574Smx205022 
22545574Smx205022 	if (ngep->progress & PROGRESS_REGS)
22555574Smx205022 		ddi_regs_map_free(&ngep->io_handle);
22565574Smx205022 
22575574Smx205022 	if (ngep->progress & PROGRESS_CFG)
22585574Smx205022 		pci_config_teardown(&ngep->cfg_handle);
22595574Smx205022 
22605574Smx205022 	ddi_remove_minor_node(ngep->devinfo, NULL);
22615574Smx205022 
22625574Smx205022 	kmem_free(ngep, sizeof (*ngep));
22635574Smx205022 }
22645574Smx205022 
22655574Smx205022 static int
22665574Smx205022 nge_resume(dev_info_t *devinfo)
22675574Smx205022 {
22685574Smx205022 	nge_t		*ngep;
22695574Smx205022 	chip_info_t	*infop;
22705869Smx205022 	int 		err;
22715574Smx205022 
22725574Smx205022 	ASSERT(devinfo != NULL);
22735574Smx205022 
22745574Smx205022 	ngep = ddi_get_driver_private(devinfo);
22755869Smx205022 	err = 0;
22765869Smx205022 
22775574Smx205022 	/*
22785574Smx205022 	 * If there are state inconsistancies, this is bad.  Returning
22795574Smx205022 	 * DDI_FAILURE here will eventually cause the machine to panic,
22805574Smx205022 	 * so it is best done here so that there is a possibility of
22815574Smx205022 	 * debugging the problem.
22825574Smx205022 	 */
22835574Smx205022 	if (ngep == NULL)
22845574Smx205022 		cmn_err(CE_PANIC,
22855574Smx205022 		    "nge: ngep returned from ddi_get_driver_private was NULL");
22865574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
22875574Smx205022 
22885574Smx205022 	if (ngep->devinfo != devinfo)
22895574Smx205022 		cmn_err(CE_PANIC,
22905869Smx205022 		    "nge: passed devinfo not the same as saved devinfo");
22915574Smx205022 
22925869Smx205022 	mutex_enter(ngep->genlock);
22935869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
22945574Smx205022 
22955574Smx205022 	/*
22965574Smx205022 	 * Fetch the config space.  Even though we have most of it cached,
22975574Smx205022 	 * some values *might* change across a suspend/resume.
22985574Smx205022 	 */
22995574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
23005574Smx205022 
23015574Smx205022 	/*
23025869Smx205022 	 * Only in one case, this conditional branch can be executed: the port
23035869Smx205022 	 * hasn't been plumbed.
23045574Smx205022 	 */
23055869Smx205022 	if (ngep->suspended == B_FALSE) {
23065869Smx205022 		rw_exit(ngep->rwlock);
23075869Smx205022 		mutex_exit(ngep->genlock);
23085869Smx205022 		return (DDI_SUCCESS);
23095869Smx205022 	}
23105869Smx205022 
23115869Smx205022 	nge_tx_recycle_all(ngep);
23125869Smx205022 	err = nge_reinit_ring(ngep);
23135869Smx205022 	if (!err) {
23145869Smx205022 		err = nge_chip_reset(ngep);
23155869Smx205022 		if (!err)
23165869Smx205022 			err = nge_chip_start(ngep);
23175869Smx205022 	}
23185869Smx205022 
23195869Smx205022 	if (err) {
23205574Smx205022 		/*
23215574Smx205022 		 * We note the failure, but return success, as the
23225574Smx205022 		 * system is still usable without this controller.
23235574Smx205022 		 */
23245574Smx205022 		cmn_err(CE_WARN, "nge: resume: failed to restart controller");
23255869Smx205022 	} else {
23265869Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
23275574Smx205022 	}
23285869Smx205022 	ngep->suspended = B_FALSE;
23295869Smx205022 
23305869Smx205022 	rw_exit(ngep->rwlock);
23315869Smx205022 	mutex_exit(ngep->genlock);
23325869Smx205022 
23335574Smx205022 	return (DDI_SUCCESS);
23345574Smx205022 }
23355574Smx205022 
23365574Smx205022 /*
23375574Smx205022  * attach(9E) -- Attach a device to the system
23385574Smx205022  *
23395574Smx205022  * Called once for each board successfully probed.
23405574Smx205022  */
23415574Smx205022 static int
23425574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
23435574Smx205022 {
23445574Smx205022 	int		err;
23455574Smx205022 	int		i;
23465574Smx205022 	int		instance;
23475574Smx205022 	caddr_t		regs;
23485574Smx205022 	nge_t		*ngep;
23495574Smx205022 	chip_info_t	*infop;
23505574Smx205022 	mac_register_t	*macp;
23515574Smx205022 
23525574Smx205022 	switch (cmd) {
23535574Smx205022 	default:
23545574Smx205022 		return (DDI_FAILURE);
23555574Smx205022 
23565574Smx205022 	case DDI_RESUME:
23575574Smx205022 		return (nge_resume(devinfo));
23585574Smx205022 
23595574Smx205022 	case DDI_ATTACH:
23605574Smx205022 		break;
23615574Smx205022 	}
23625574Smx205022 
23635574Smx205022 	ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
23645574Smx205022 	instance = ddi_get_instance(devinfo);
23655574Smx205022 	ddi_set_driver_private(devinfo, ngep);
23665574Smx205022 	ngep->devinfo = devinfo;
23675574Smx205022 
23685574Smx205022 	(void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
23695574Smx205022 	    NGE_DRIVER_NAME, instance);
23705574Smx205022 	err = pci_config_setup(devinfo, &ngep->cfg_handle);
23715574Smx205022 	if (err != DDI_SUCCESS) {
23725574Smx205022 		nge_problem(ngep, "nge_attach: pci_config_setup() failed");
23735574Smx205022 		goto attach_fail;
23745574Smx205022 	}
23756512Ssowmini 	/*
23766512Ssowmini 	 * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy
23776512Ssowmini 	 * thresholds. Bounds: min 0, max NGE_MAX_SDU
23786512Ssowmini 	 */
23796512Ssowmini 	ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE;
23806512Ssowmini 	ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE;
23816512Ssowmini 
23826512Ssowmini 	/*
23836512Ssowmini 	 * param_recv_max_packet is max packet received per interupt.
23846512Ssowmini 	 * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024
23856512Ssowmini 	 */
23866512Ssowmini 	ngep->param_recv_max_packet = 128;
23876512Ssowmini 
23886512Ssowmini 	/*
23896512Ssowmini 	 * param_poll_quiet_time and param_poll_busy_time are quiet/busy time
23906512Ssowmini 	 * switch from per packet interrupt to polling interrupt.
23916512Ssowmini 	 * Bounds: min 0, max 10000
23926512Ssowmini 	 */
23936512Ssowmini 	ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME;
23946512Ssowmini 	ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME;
23956512Ssowmini 
23966512Ssowmini 	/*
23976512Ssowmini 	 * param_rx_intr_hwater/param_rx_intr_lwater: ackets received
23986512Ssowmini 	 * to trigger the poll_quiet_time/poll_busy_time counter.
23996512Ssowmini 	 * Bounds: min 0, max  NGE_RECV_SLOTS_DESC_1024.
24006512Ssowmini 	 */
24016512Ssowmini 	ngep->param_rx_intr_hwater = 1;
24026512Ssowmini 	ngep->param_rx_intr_lwater = 8;
24036512Ssowmini 
24046512Ssowmini 	/*
24056512Ssowmini 	 * param_tx_n_intr: Per N tx packets to do tx recycle in poll mode.
24066512Ssowmini 	 * Bounds: min 1, max 10000.
24076512Ssowmini 	 */
24086512Ssowmini 	ngep->param_tx_n_intr = NGE_TX_N_INTR;
24096512Ssowmini 
24105574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
24115574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
24125574Smx205022 	nge_init_dev_spec_param(ngep);
24135574Smx205022 	nge_get_props(ngep);
24145574Smx205022 	ngep->progress |= PROGRESS_CFG;
24155574Smx205022 
24165574Smx205022 	err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
24175574Smx205022 	    &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
24185574Smx205022 	if (err != DDI_SUCCESS) {
24195574Smx205022 		nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
24205574Smx205022 		goto attach_fail;
24215574Smx205022 	}
24225574Smx205022 	ngep->io_regs = regs;
24235574Smx205022 	ngep->progress |= PROGRESS_REGS;
24245574Smx205022 
24255574Smx205022 	err = nge_register_intrs_and_init_locks(ngep);
24265574Smx205022 	if (err != DDI_SUCCESS) {
24275574Smx205022 		nge_problem(ngep, "nge_attach:"
24285574Smx205022 		    " register intrs and init locks failed");
24295574Smx205022 		goto attach_fail;
24305574Smx205022 	}
24315574Smx205022 	nge_init_ring_param_lock(ngep);
24325574Smx205022 	ngep->progress |= PROGRESS_INTR;
24335574Smx205022 
24345574Smx205022 	mutex_enter(ngep->genlock);
24355574Smx205022 
24365574Smx205022 	/*
24375574Smx205022 	 * Initialise link state variables
24385574Smx205022 	 * Stop, reset & reinitialise the chip.
24395574Smx205022 	 * Initialise the (internal) PHY.
24405574Smx205022 	 */
24415574Smx205022 	nge_phys_init(ngep);
24425574Smx205022 	err = nge_chip_reset(ngep);
24435574Smx205022 	if (err != DDI_SUCCESS) {
24445574Smx205022 		nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
24455574Smx205022 		mutex_exit(ngep->genlock);
24465574Smx205022 		goto attach_fail;
24475574Smx205022 	}
24485574Smx205022 	nge_chip_sync(ngep);
24495574Smx205022 
24505574Smx205022 	/*
24515574Smx205022 	 * Now that mutex locks are initialized, enable interrupts.
24525574Smx205022 	 */
24535574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
24545574Smx205022 		/* Call ddi_intr_block_enable() for MSI interrupts */
24555574Smx205022 		(void) ddi_intr_block_enable(ngep->htable,
24565574Smx205022 		    ngep->intr_actual_cnt);
24575574Smx205022 	} else {
24585574Smx205022 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
24595574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
24605574Smx205022 			(void) ddi_intr_enable(ngep->htable[i]);
24615574Smx205022 		}
24625574Smx205022 	}
24635574Smx205022 
24645574Smx205022 	ngep->link_state = LINK_STATE_UNKNOWN;
24655574Smx205022 	ngep->progress |= PROGRESS_HWINT;
24665574Smx205022 
24675574Smx205022 	/*
24685574Smx205022 	 * Register NDD-tweakable parameters
24695574Smx205022 	 */
24705574Smx205022 	if (nge_nd_init(ngep)) {
24715574Smx205022 		nge_problem(ngep, "nge_attach: nge_nd_init() failed");
24725574Smx205022 		mutex_exit(ngep->genlock);
24735574Smx205022 		goto attach_fail;
24745574Smx205022 	}
24755574Smx205022 	ngep->progress |= PROGRESS_NDD;
24765574Smx205022 
24775574Smx205022 	/*
24785574Smx205022 	 * Create & initialise named kstats
24795574Smx205022 	 */
24805574Smx205022 	nge_init_kstats(ngep, instance);
24815574Smx205022 	ngep->progress |= PROGRESS_KSTATS;
24825574Smx205022 
24835574Smx205022 	mutex_exit(ngep->genlock);
24845574Smx205022 
24855574Smx205022 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
24865574Smx205022 		goto attach_fail;
24875574Smx205022 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
24885574Smx205022 	macp->m_driver = ngep;
24895574Smx205022 	macp->m_dip = devinfo;
24905574Smx205022 	macp->m_src_addr = infop->vendor_addr.addr;
24915574Smx205022 	macp->m_callbacks = &nge_m_callbacks;
24925574Smx205022 	macp->m_min_sdu = 0;
24935574Smx205022 	macp->m_max_sdu = ngep->default_mtu;
24945895Syz147064 	macp->m_margin = VTAG_SIZE;
24956512Ssowmini 	macp->m_priv_props = nge_priv_props;
24966512Ssowmini 	macp->m_priv_prop_count = NGE_MAX_PRIV_PROPS;
24975574Smx205022 	/*
24985574Smx205022 	 * Finally, we're ready to register ourselves with the mac
24995574Smx205022 	 * interface; if this succeeds, we're all ready to start()
25005574Smx205022 	 */
25015574Smx205022 	err = mac_register(macp, &ngep->mh);
25025574Smx205022 	mac_free(macp);
25035574Smx205022 	if (err != 0)
25045574Smx205022 		goto attach_fail;
25055574Smx205022 
25065574Smx205022 	/*
25075574Smx205022 	 * Register a periodical handler.
25085574Smx205022 	 * nge_chip_cyclic() is invoked in kernel context.
25095574Smx205022 	 */
25105574Smx205022 	ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
25115574Smx205022 	    NGE_CYCLIC_PERIOD, DDI_IPL_0);
25125574Smx205022 
25135574Smx205022 	ngep->progress |= PROGRESS_READY;
25145574Smx205022 	return (DDI_SUCCESS);
25155574Smx205022 
25165574Smx205022 attach_fail:
25175574Smx205022 	nge_unattach(ngep);
25185574Smx205022 	return (DDI_FAILURE);
25195574Smx205022 }
25205574Smx205022 
25215869Smx205022 static int
25225869Smx205022 nge_suspend(nge_t *ngep)
25235869Smx205022 {
25245869Smx205022 	mutex_enter(ngep->genlock);
25255869Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
25265869Smx205022 
25275869Smx205022 	/* if the port hasn't been plumbed, just return */
25285869Smx205022 	if (ngep->nge_mac_state != NGE_MAC_STARTED) {
25295869Smx205022 		rw_exit(ngep->rwlock);
25305869Smx205022 		mutex_exit(ngep->genlock);
25315869Smx205022 		return (DDI_SUCCESS);
25325869Smx205022 	}
25335869Smx205022 	ngep->suspended = B_TRUE;
25345869Smx205022 	(void) nge_chip_stop(ngep, B_FALSE);
25355869Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
25365869Smx205022 
25375869Smx205022 	rw_exit(ngep->rwlock);
25385869Smx205022 	mutex_exit(ngep->genlock);
25395869Smx205022 	return (DDI_SUCCESS);
25405869Smx205022 }
25415869Smx205022 
25425574Smx205022 /*
25435574Smx205022  * detach(9E) -- Detach a device from the system
25445574Smx205022  */
25455574Smx205022 static int
25465574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
25475574Smx205022 {
25485574Smx205022 	int i;
25495574Smx205022 	nge_t *ngep;
25505574Smx205022 	mul_item *p, *nextp;
25515574Smx205022 	buff_ring_t *brp;
25525574Smx205022 
25535574Smx205022 	NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
25545574Smx205022 
25555574Smx205022 	ngep = ddi_get_driver_private(devinfo);
25565574Smx205022 	brp = ngep->buff;
25575574Smx205022 
25585574Smx205022 	switch (cmd) {
25595574Smx205022 	default:
25605574Smx205022 		return (DDI_FAILURE);
25615574Smx205022 
25625574Smx205022 	case DDI_SUSPEND:
25635574Smx205022 		/*
25645574Smx205022 		 * Stop the NIC
25655574Smx205022 		 * Note: This driver doesn't currently support WOL, but
25665574Smx205022 		 *	should it in the future, it is important to
25675574Smx205022 		 *	make sure the PHY remains powered so that the
25685574Smx205022 		 *	wakeup packet can actually be recieved.
25695574Smx205022 		 */
25705869Smx205022 		return (nge_suspend(ngep));
25715574Smx205022 
25725574Smx205022 	case DDI_DETACH:
25735574Smx205022 		break;
25745574Smx205022 	}
25755574Smx205022 
25765574Smx205022 	/* Try to wait all the buffer post to upper layer be released */
25775574Smx205022 	for (i = 0; i < 1000; i++) {
25785574Smx205022 		if (brp->rx_hold == 0)
25795574Smx205022 			break;
25805574Smx205022 		drv_usecwait(1000);
25815574Smx205022 	}
25825574Smx205022 
25835574Smx205022 	/* If there is any posted buffer, reject to detach */
25845574Smx205022 	if (brp->rx_hold != 0)
25855574Smx205022 		return (DDI_FAILURE);
25865574Smx205022 
25875574Smx205022 	/*
25885574Smx205022 	 * Unregister from the GLD subsystem.  This can fail, in
25895574Smx205022 	 * particular if there are DLPI style-2 streams still open -
25905574Smx205022 	 * in which case we just return failure without shutting
25915574Smx205022 	 * down chip operations.
25925574Smx205022 	 */
25935574Smx205022 	if (mac_unregister(ngep->mh) != DDI_SUCCESS)
25945574Smx205022 		return (DDI_FAILURE);
25955574Smx205022 
25965574Smx205022 	/*
25976366Smx205022 	 * Recycle the multicast table. mac_unregister() should be called
25986366Smx205022 	 * before it to ensure the multicast table can be used even if
25996366Smx205022 	 * mac_unregister() fails.
26006366Smx205022 	 */
26016366Smx205022 	for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
26026366Smx205022 		nextp = p->next;
26036366Smx205022 		kmem_free(p, sizeof (mul_item));
26046366Smx205022 	}
26056366Smx205022 	ngep->pcur_mulist = NULL;
26066366Smx205022 
26076366Smx205022 	/*
26085574Smx205022 	 * All activity stopped, so we can clean up & exit
26095574Smx205022 	 */
26105574Smx205022 	nge_unattach(ngep);
26115574Smx205022 	return (DDI_SUCCESS);
26125574Smx205022 }
26135574Smx205022 
26145574Smx205022 
26155574Smx205022 /*
26165574Smx205022  * ========== Module Loading Data & Entry Points ==========
26175574Smx205022  */
26185574Smx205022 
26195574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
26205574Smx205022     nodev, NULL, D_MP, NULL);
26215574Smx205022 
26225574Smx205022 
26235574Smx205022 static struct modldrv nge_modldrv = {
26245574Smx205022 	&mod_driverops,		/* Type of module.  This one is a driver */
26255574Smx205022 	nge_ident,		/* short description */
26265574Smx205022 	&nge_dev_ops		/* driver specific ops */
26275574Smx205022 };
26285574Smx205022 
26295574Smx205022 static struct modlinkage modlinkage = {
26305574Smx205022 	MODREV_1, (void *)&nge_modldrv, NULL
26315574Smx205022 };
26325574Smx205022 
26335574Smx205022 
26345574Smx205022 int
26355574Smx205022 _info(struct modinfo *modinfop)
26365574Smx205022 {
26375574Smx205022 	return (mod_info(&modlinkage, modinfop));
26385574Smx205022 }
26395574Smx205022 
26405574Smx205022 int
26415574Smx205022 _init(void)
26425574Smx205022 {
26435574Smx205022 	int status;
26445574Smx205022 
26455574Smx205022 	mac_init_ops(&nge_dev_ops, "nge");
26465574Smx205022 	status = mod_install(&modlinkage);
26475574Smx205022 	if (status != DDI_SUCCESS)
26485574Smx205022 		mac_fini_ops(&nge_dev_ops);
26495574Smx205022 	else
26505574Smx205022 		mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
26515574Smx205022 
26525574Smx205022 	return (status);
26535574Smx205022 }
26545574Smx205022 
26555574Smx205022 int
26565574Smx205022 _fini(void)
26575574Smx205022 {
26585574Smx205022 	int status;
26595574Smx205022 
26605574Smx205022 	status = mod_remove(&modlinkage);
26615574Smx205022 	if (status == DDI_SUCCESS) {
26625574Smx205022 		mac_fini_ops(&nge_dev_ops);
26635574Smx205022 		mutex_destroy(nge_log_mutex);
26645574Smx205022 	}
26655574Smx205022 
26665574Smx205022 	return (status);
26675574Smx205022 }
26685574Smx205022 
26695574Smx205022 /*
26705574Smx205022  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
26715574Smx205022  */
26725574Smx205022 
26735574Smx205022 /*
26745574Smx205022  * Register interrupts and initialize each mutex and condition variables
26755574Smx205022  */
26765574Smx205022 
26775574Smx205022 static int
26785574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep)
26795574Smx205022 {
26805574Smx205022 	int		err;
26815574Smx205022 	int		intr_types;
26825574Smx205022 	uint_t		soft_prip;
26835574Smx205022 	nge_msi_mask	msi_mask;
26845574Smx205022 	nge_msi_map0_vec map0_vec;
26855574Smx205022 	nge_msi_map1_vec map1_vec;
26865574Smx205022 
26875574Smx205022 	/*
26885574Smx205022 	 * Add the softint handlers:
26895574Smx205022 	 *
26905574Smx205022 	 * Both of these handlers are used to avoid restrictions on the
26915574Smx205022 	 * context and/or mutexes required for some operations.  In
26925574Smx205022 	 * particular, the hardware interrupt handler and its subfunctions
26935574Smx205022 	 * can detect a number of conditions that we don't want to handle
26945574Smx205022 	 * in that context or with that set of mutexes held.  So, these
26955574Smx205022 	 * softints are triggered instead:
26965574Smx205022 	 *
26975574Smx205022 	 * the <resched> softint is triggered if if we have previously
26985574Smx205022 	 * had to refuse to send a packet because of resource shortage
26995574Smx205022 	 * (we've run out of transmit buffers), but the send completion
27005574Smx205022 	 * interrupt handler has now detected that more buffers have
27015574Smx205022 	 * become available.  Its only purpose is to call gld_sched()
27025574Smx205022 	 * to retry the pending transmits (we're not allowed to hold
27035574Smx205022 	 * driver-defined mutexes across gld_sched()).
27045574Smx205022 	 *
27055574Smx205022 	 * the <factotum> is triggered if the h/w interrupt handler
27065574Smx205022 	 * sees the <link state changed> or <error> bits in the status
27075574Smx205022 	 * block.  It's also triggered periodically to poll the link
27085574Smx205022 	 * state, just in case we aren't getting link status change
27095574Smx205022 	 * interrupts ...
27105574Smx205022 	 */
27115574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
27125574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
27135574Smx205022 	if (err != DDI_SUCCESS) {
27145574Smx205022 		nge_problem(ngep,
27155574Smx205022 		    "nge_attach: add nge_reschedule softintr failed");
27165574Smx205022 
27175574Smx205022 		return (DDI_FAILURE);
27185574Smx205022 	}
27195574Smx205022 	ngep->progress |= PROGRESS_RESCHED;
27205574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
27215574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
27225574Smx205022 	if (err != DDI_SUCCESS) {
27235574Smx205022 		nge_problem(ngep,
27245574Smx205022 		    "nge_attach: add nge_chip_factotum softintr failed!");
27255574Smx205022 
27265574Smx205022 		return (DDI_FAILURE);
27275574Smx205022 	}
27285574Smx205022 	if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
27295574Smx205022 	    != DDI_SUCCESS) {
27305574Smx205022 		nge_problem(ngep, "nge_attach: get softintr priority failed\n");
27315574Smx205022 
27325574Smx205022 		return (DDI_FAILURE);
27335574Smx205022 	}
27345574Smx205022 	ngep->soft_pri = soft_prip;
27355574Smx205022 
27365574Smx205022 	ngep->progress |= PROGRESS_FACTOTUM;
27375574Smx205022 	/* Get supported interrupt types */
27385574Smx205022 	if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
27395574Smx205022 	    != DDI_SUCCESS) {
27405574Smx205022 		nge_error(ngep, "ddi_intr_get_supported_types failed\n");
27415574Smx205022 
27425574Smx205022 		return (DDI_FAILURE);
27435574Smx205022 	}
27445574Smx205022 
27455574Smx205022 	NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
27465574Smx205022 	    intr_types));
27475574Smx205022 
27485574Smx205022 	if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
27495574Smx205022 
27505574Smx205022 		/* MSI Configurations for mcp55 chipset */
27515574Smx205022 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
27525574Smx205022 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
27535574Smx205022 
27545574Smx205022 
27555574Smx205022 			/* Enable the 8 vectors */
27565574Smx205022 			msi_mask.msi_mask_val =
27575574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MASK);
27585574Smx205022 			msi_mask.msi_msk_bits.vec0 = NGE_SET;
27595574Smx205022 			msi_mask.msi_msk_bits.vec1 = NGE_SET;
27605574Smx205022 			msi_mask.msi_msk_bits.vec2 = NGE_SET;
27615574Smx205022 			msi_mask.msi_msk_bits.vec3 = NGE_SET;
27625574Smx205022 			msi_mask.msi_msk_bits.vec4 = NGE_SET;
27635574Smx205022 			msi_mask.msi_msk_bits.vec5 = NGE_SET;
27645574Smx205022 			msi_mask.msi_msk_bits.vec6 = NGE_SET;
27655574Smx205022 			msi_mask.msi_msk_bits.vec7 = NGE_SET;
27665574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MASK,
27675574Smx205022 			    msi_mask.msi_mask_val);
27685574Smx205022 
27695574Smx205022 			/*
27705574Smx205022 			 * Remapping the MSI MAP0 and MAP1. MCP55
27715574Smx205022 			 * is default mapping all the interrupt to 0 vector.
27725574Smx205022 			 * Software needs to remapping this.
27735574Smx205022 			 * This mapping is same as CK804.
27745574Smx205022 			 */
27755574Smx205022 			map0_vec.msi_map0_val =
27765574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP0);
27775574Smx205022 			map1_vec.msi_map1_val =
27785574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP1);
27795574Smx205022 			map0_vec.vecs_bits.reint_vec = 0;
27805574Smx205022 			map0_vec.vecs_bits.rcint_vec = 0;
27815574Smx205022 			map0_vec.vecs_bits.miss_vec = 3;
27825574Smx205022 			map0_vec.vecs_bits.teint_vec = 5;
27835574Smx205022 			map0_vec.vecs_bits.tcint_vec = 5;
27845574Smx205022 			map0_vec.vecs_bits.stint_vec = 2;
27855574Smx205022 			map0_vec.vecs_bits.mint_vec = 6;
27865574Smx205022 			map0_vec.vecs_bits.rfint_vec = 0;
27875574Smx205022 			map1_vec.vecs_bits.tfint_vec = 5;
27885574Smx205022 			map1_vec.vecs_bits.feint_vec = 6;
27895574Smx205022 			map1_vec.vecs_bits.resv8_11 = 3;
27905574Smx205022 			map1_vec.vecs_bits.resv12_15 = 1;
27915574Smx205022 			map1_vec.vecs_bits.resv16_19 = 0;
27925574Smx205022 			map1_vec.vecs_bits.resv20_23 = 7;
27935574Smx205022 			map1_vec.vecs_bits.resv24_31 = 0xff;
27945574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP0,
27955574Smx205022 			    map0_vec.msi_map0_val);
27965574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP1,
27975574Smx205022 			    map1_vec.msi_map1_val);
27985574Smx205022 		}
27995574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
28005574Smx205022 			NGE_DEBUG(("MSI registration failed, "
28015574Smx205022 			    "trying FIXED interrupt type\n"));
28025574Smx205022 		} else {
28035574Smx205022 			nge_log(ngep, "Using MSI interrupt type\n");
28045574Smx205022 
28055574Smx205022 			ngep->intr_type = DDI_INTR_TYPE_MSI;
28065574Smx205022 			ngep->progress |= PROGRESS_SWINT;
28075574Smx205022 		}
28085574Smx205022 	}
28095574Smx205022 
28105574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT) &&
28115574Smx205022 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
28125574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
28135574Smx205022 			nge_error(ngep, "FIXED interrupt "
28145574Smx205022 			    "registration failed\n");
28155574Smx205022 
28165574Smx205022 			return (DDI_FAILURE);
28175574Smx205022 		}
28185574Smx205022 
28195574Smx205022 		nge_log(ngep, "Using FIXED interrupt type\n");
28205574Smx205022 
28215574Smx205022 		ngep->intr_type = DDI_INTR_TYPE_FIXED;
28225574Smx205022 		ngep->progress |= PROGRESS_SWINT;
28235574Smx205022 	}
28245574Smx205022 
28255574Smx205022 
28265574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT)) {
28275574Smx205022 		nge_error(ngep, "No interrupts registered\n");
28285574Smx205022 
28295574Smx205022 		return (DDI_FAILURE);
28305574Smx205022 	}
28315574Smx205022 	mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
28325574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
28335574Smx205022 	mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
28345574Smx205022 	    DDI_INTR_PRI(ngep->soft_pri));
28355574Smx205022 	rw_init(ngep->rwlock, NULL, RW_DRIVER,
28365574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
28375574Smx205022 
28385574Smx205022 	return (DDI_SUCCESS);
28395574Smx205022 }
28405574Smx205022 
28415574Smx205022 /*
28425574Smx205022  * nge_add_intrs:
28435574Smx205022  *
28445574Smx205022  * Register FIXED or MSI interrupts.
28455574Smx205022  */
28465574Smx205022 static int
28475574Smx205022 nge_add_intrs(nge_t *ngep, int	intr_type)
28485574Smx205022 {
28495574Smx205022 	dev_info_t	*dip = ngep->devinfo;
28505574Smx205022 	int		avail, actual, intr_size, count = 0;
28515574Smx205022 	int		i, flag, ret;
28525574Smx205022 
28535574Smx205022 	NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
28545574Smx205022 
28555574Smx205022 	/* Get number of interrupts */
28565574Smx205022 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
28575574Smx205022 	if ((ret != DDI_SUCCESS) || (count == 0)) {
28585574Smx205022 		nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
28595574Smx205022 		    "count: %d", ret, count);
28605574Smx205022 
28615574Smx205022 		return (DDI_FAILURE);
28625574Smx205022 	}
28635574Smx205022 
28645574Smx205022 	/* Get number of available interrupts */
28655574Smx205022 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
28665574Smx205022 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
28675574Smx205022 		nge_error(ngep, "ddi_intr_get_navail() failure, "
28685574Smx205022 		    "ret: %d, avail: %d\n", ret, avail);
28695574Smx205022 
28705574Smx205022 		return (DDI_FAILURE);
28715574Smx205022 	}
28725574Smx205022 
28735574Smx205022 	if (avail < count) {
28745574Smx205022 		NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
28755574Smx205022 		    count, avail));
28765574Smx205022 	}
28775574Smx205022 	flag = DDI_INTR_ALLOC_NORMAL;
28785574Smx205022 
28795574Smx205022 	/* Allocate an array of interrupt handles */
28805574Smx205022 	intr_size = count * sizeof (ddi_intr_handle_t);
28815574Smx205022 	ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
28825574Smx205022 
28835574Smx205022 	/* Call ddi_intr_alloc() */
28845574Smx205022 	ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
28855574Smx205022 	    count, &actual, flag);
28865574Smx205022 
28875574Smx205022 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
28885574Smx205022 		nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
28895574Smx205022 
28905574Smx205022 		kmem_free(ngep->htable, intr_size);
28915574Smx205022 		return (DDI_FAILURE);
28925574Smx205022 	}
28935574Smx205022 
28945574Smx205022 	if (actual < count) {
28955574Smx205022 		NGE_DEBUG(("Requested: %d, Received: %d\n",
28965574Smx205022 		    count, actual));
28975574Smx205022 	}
28985574Smx205022 
28995574Smx205022 	ngep->intr_actual_cnt = actual;
29005574Smx205022 	ngep->intr_req_cnt = count;
29015574Smx205022 
29025574Smx205022 	/*
29035574Smx205022 	 * Get priority for first msi, assume remaining are all the same
29045574Smx205022 	 */
29055574Smx205022 	if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
29065574Smx205022 	    DDI_SUCCESS) {
29075574Smx205022 		nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
29085574Smx205022 
29095574Smx205022 		/* Free already allocated intr */
29105574Smx205022 		for (i = 0; i < actual; i++) {
29115574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
29125574Smx205022 		}
29135574Smx205022 
29145574Smx205022 		kmem_free(ngep->htable, intr_size);
29155574Smx205022 
29165574Smx205022 		return (DDI_FAILURE);
29175574Smx205022 	}
29185574Smx205022 	/* Test for high level mutex */
29195574Smx205022 	if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
29205574Smx205022 		nge_error(ngep, "nge_add_intrs:"
29215574Smx205022 		    "Hi level interrupt not supported");
29225574Smx205022 
29235574Smx205022 		for (i = 0; i < actual; i++)
29245574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
29255574Smx205022 
29265574Smx205022 		kmem_free(ngep->htable, intr_size);
29275574Smx205022 
29285574Smx205022 		return (DDI_FAILURE);
29295574Smx205022 	}
29305574Smx205022 
29315574Smx205022 
29325574Smx205022 	/* Call ddi_intr_add_handler() */
29335574Smx205022 	for (i = 0; i < actual; i++) {
29345574Smx205022 		if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
29355574Smx205022 		    (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
29365574Smx205022 			nge_error(ngep, "ddi_intr_add_handler() "
29375574Smx205022 			    "failed %d\n", ret);
29385574Smx205022 
29395574Smx205022 			/* Free already allocated intr */
29405574Smx205022 			for (i = 0; i < actual; i++) {
29415574Smx205022 				(void) ddi_intr_free(ngep->htable[i]);
29425574Smx205022 			}
29435574Smx205022 
29445574Smx205022 			kmem_free(ngep->htable, intr_size);
29455574Smx205022 
29465574Smx205022 			return (DDI_FAILURE);
29475574Smx205022 		}
29485574Smx205022 	}
29495574Smx205022 
29505574Smx205022 	if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
29515574Smx205022 	    != DDI_SUCCESS) {
29525574Smx205022 		nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
29535574Smx205022 
29545574Smx205022 		for (i = 0; i < actual; i++) {
29555574Smx205022 			(void) ddi_intr_remove_handler(ngep->htable[i]);
29565574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
29575574Smx205022 		}
29585574Smx205022 
29595574Smx205022 		kmem_free(ngep->htable, intr_size);
29605574Smx205022 
29615574Smx205022 		return (DDI_FAILURE);
29625574Smx205022 	}
29635574Smx205022 
29645574Smx205022 	return (DDI_SUCCESS);
29655574Smx205022 }
29665574Smx205022 
29675574Smx205022 /*
29685574Smx205022  * nge_rem_intrs:
29695574Smx205022  *
29705574Smx205022  * Unregister FIXED or MSI interrupts
29715574Smx205022  */
29725574Smx205022 static void
29735574Smx205022 nge_rem_intrs(nge_t *ngep)
29745574Smx205022 {
29755574Smx205022 	int	i;
29765574Smx205022 
29775574Smx205022 	NGE_DEBUG(("nge_rem_intrs\n"));
29785574Smx205022 
29795574Smx205022 	/* Disable all interrupts */
29805574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
29815574Smx205022 		/* Call ddi_intr_block_disable() */
29825574Smx205022 		(void) ddi_intr_block_disable(ngep->htable,
29835574Smx205022 		    ngep->intr_actual_cnt);
29845574Smx205022 	} else {
29855574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
29865574Smx205022 			(void) ddi_intr_disable(ngep->htable[i]);
29875574Smx205022 		}
29885574Smx205022 	}
29895574Smx205022 
29905574Smx205022 	/* Call ddi_intr_remove_handler() */
29915574Smx205022 	for (i = 0; i < ngep->intr_actual_cnt; i++) {
29925574Smx205022 		(void) ddi_intr_remove_handler(ngep->htable[i]);
29935574Smx205022 		(void) ddi_intr_free(ngep->htable[i]);
29945574Smx205022 	}
29955574Smx205022 
29965574Smx205022 	kmem_free(ngep->htable,
29975574Smx205022 	    ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
29985574Smx205022 }
2999