xref: /onnv-gate/usr/src/uts/common/io/nge/nge_main.c (revision 5578:c0773208044e)
1*5578Smx205022 /*
2*5578Smx205022  * CDDL HEADER START
3*5578Smx205022  *
4*5578Smx205022  * The contents of this file are subject to the terms of the
5*5578Smx205022  * Common Development and Distribution License (the "License").
6*5578Smx205022  * You may not use this file except in compliance with the License.
7*5578Smx205022  *
8*5578Smx205022  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5578Smx205022  * or http://www.opensolaris.org/os/licensing.
10*5578Smx205022  * See the License for the specific language governing permissions
11*5578Smx205022  * and limitations under the License.
12*5578Smx205022  *
13*5578Smx205022  * When distributing Covered Code, include this CDDL HEADER in each
14*5578Smx205022  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5578Smx205022  * If applicable, add the following below this CDDL HEADER, with the
16*5578Smx205022  * fields enclosed by brackets "[]" replaced with your own identifying
17*5578Smx205022  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5578Smx205022  *
19*5578Smx205022  * CDDL HEADER END
20*5578Smx205022  */
21*5578Smx205022 
225574Smx205022 /*
235574Smx205022  * Copyright 2007 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 
1575574Smx205022 static char nge_ident[] = "nVidia 1Gb Ethernet %I%";
1585574Smx205022 static char clsize_propname[] = "cache-line-size";
1595574Smx205022 static char latency_propname[] = "latency-timer";
1605574Smx205022 static char debug_propname[]	= "nge-debug-flags";
1615574Smx205022 static char rx_data_hw[] = "rx-data-hw";
1625574Smx205022 static char rx_prd_lw[] = "rx-prd-lw";
1635574Smx205022 static char rx_prd_hw[] = "rx-prd-hw";
1645574Smx205022 static char sw_intr_intv[] = "sw-intr-intvl";
1655574Smx205022 static char nge_desc_mode[] = "desc-mode";
1665574Smx205022 static char default_mtu[] = "default_mtu";
1675574Smx205022 static char low_memory_mode[] = "minimal-memory-usage";
1685574Smx205022 extern kmutex_t nge_log_mutex[1];
1695574Smx205022 
1705574Smx205022 static int		nge_m_start(void *);
1715574Smx205022 static void		nge_m_stop(void *);
1725574Smx205022 static int		nge_m_promisc(void *, boolean_t);
1735574Smx205022 static int		nge_m_multicst(void *, boolean_t, const uint8_t *);
1745574Smx205022 static int		nge_m_unicst(void *, const uint8_t *);
1755574Smx205022 static void		nge_m_resources(void *);
1765574Smx205022 static void		nge_m_ioctl(void *, queue_t *, mblk_t *);
1775574Smx205022 static boolean_t	nge_m_getcapab(void *, mac_capab_t, void *);
1785574Smx205022 
1795574Smx205022 #define		NGE_M_CALLBACK_FLAGS	(MC_RESOURCES | MC_IOCTL | MC_GETCAPAB)
1805574Smx205022 
1815574Smx205022 static mac_callbacks_t nge_m_callbacks = {
1825574Smx205022 	NGE_M_CALLBACK_FLAGS,
1835574Smx205022 	nge_m_stat,
1845574Smx205022 	nge_m_start,
1855574Smx205022 	nge_m_stop,
1865574Smx205022 	nge_m_promisc,
1875574Smx205022 	nge_m_multicst,
1885574Smx205022 	nge_m_unicst,
1895574Smx205022 	nge_m_tx,
1905574Smx205022 	nge_m_resources,
1915574Smx205022 	nge_m_ioctl,
1925574Smx205022 	nge_m_getcapab
1935574Smx205022 };
1945574Smx205022 
1955574Smx205022 static int nge_add_intrs(nge_t *, int);
1965574Smx205022 static void nge_rem_intrs(nge_t *);
1975574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *);
1985574Smx205022 
1995574Smx205022 /*
2005574Smx205022  * NGE MSI tunable:
2015574Smx205022  */
2025574Smx205022 boolean_t nge_enable_msi = B_FALSE;
2035574Smx205022 
2045574Smx205022 static enum ioc_reply
2055574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode)
2065574Smx205022 {
2075574Smx205022 	/*
2085574Smx205022 	 * If the mode isn't being changed, there's nothing to do ...
2095574Smx205022 	 */
2105574Smx205022 	if (mode == ngep->param_loop_mode)
2115574Smx205022 		return (IOC_ACK);
2125574Smx205022 
2135574Smx205022 	/*
2145574Smx205022 	 * Validate the requested mode and prepare a suitable message
2155574Smx205022 	 * to explain the link down/up cycle that the change will
2165574Smx205022 	 * probably induce ...
2175574Smx205022 	 */
2185574Smx205022 	switch (mode) {
2195574Smx205022 	default:
2205574Smx205022 		return (IOC_INVAL);
2215574Smx205022 
2225574Smx205022 	case NGE_LOOP_NONE:
2235574Smx205022 	case NGE_LOOP_EXTERNAL_100:
2245574Smx205022 	case NGE_LOOP_EXTERNAL_10:
2255574Smx205022 	case NGE_LOOP_INTERNAL_PHY:
2265574Smx205022 		break;
2275574Smx205022 	}
2285574Smx205022 
2295574Smx205022 	/*
2305574Smx205022 	 * All OK; tell the caller to reprogram
2315574Smx205022 	 * the PHY and/or MAC for the new mode ...
2325574Smx205022 	 */
2335574Smx205022 	ngep->param_loop_mode = mode;
2345574Smx205022 	return (IOC_RESTART_ACK);
2355574Smx205022 }
2365574Smx205022 
2375574Smx205022 #undef	NGE_DBG
2385574Smx205022 #define	NGE_DBG		NGE_DBG_INIT
2395574Smx205022 
2405574Smx205022 /*
2415574Smx205022  * Utility routine to carve a slice off a chunk of allocated memory,
2425574Smx205022  * updating the chunk descriptor accordingly.  The size of the slice
2435574Smx205022  * is given by the product of the <qty> and <size> parameters.
2445574Smx205022  */
2455574Smx205022 void
2465574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
2475574Smx205022     uint32_t qty, uint32_t size)
2485574Smx205022 {
2495574Smx205022 	size_t totsize;
2505574Smx205022 
2515574Smx205022 	totsize = qty*size;
2525574Smx205022 	ASSERT(size > 0);
2535574Smx205022 	ASSERT(totsize <= chunk->alength);
2545574Smx205022 
2555574Smx205022 	*slice = *chunk;
2565574Smx205022 	slice->nslots = qty;
2575574Smx205022 	slice->size = size;
2585574Smx205022 	slice->alength = totsize;
2595574Smx205022 
2605574Smx205022 	chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
2615574Smx205022 	chunk->alength -= totsize;
2625574Smx205022 	chunk->offset += totsize;
2635574Smx205022 	chunk->cookie.dmac_laddress += totsize;
2645574Smx205022 	chunk->cookie.dmac_size -= totsize;
2655574Smx205022 }
2665574Smx205022 
2675574Smx205022 /*
2685574Smx205022  * Allocate an area of memory and a DMA handle for accessing it
2695574Smx205022  */
2705574Smx205022 int
2715574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p,
2725574Smx205022     uint_t dma_flags, dma_area_t *dma_p)
2735574Smx205022 {
2745574Smx205022 	int err;
2755574Smx205022 	caddr_t va;
2765574Smx205022 
2775574Smx205022 	NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
2785574Smx205022 	    (void *)ngep, memsize, attr_p, dma_flags, dma_p));
2795574Smx205022 	/*
2805574Smx205022 	 * Allocate handle
2815574Smx205022 	 */
2825574Smx205022 	err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr,
2835574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
2845574Smx205022 	if (err != DDI_SUCCESS)
2855574Smx205022 		goto fail;
2865574Smx205022 
2875574Smx205022 	/*
2885574Smx205022 	 * Allocate memory
2895574Smx205022 	 */
2905574Smx205022 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
2915574Smx205022 	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
2925574Smx205022 	    DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl);
2935574Smx205022 	if (err != DDI_SUCCESS)
2945574Smx205022 		goto fail;
2955574Smx205022 
2965574Smx205022 	/*
2975574Smx205022 	 * Bind the two together
2985574Smx205022 	 */
2995574Smx205022 	dma_p->mem_va = va;
3005574Smx205022 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
3015574Smx205022 	    va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
3025574Smx205022 	    &dma_p->cookie, &dma_p->ncookies);
3035574Smx205022 
3045574Smx205022 	if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
3055574Smx205022 		goto fail;
3065574Smx205022 
3075574Smx205022 	dma_p->nslots = ~0U;
3085574Smx205022 	dma_p->size = ~0U;
3095574Smx205022 	dma_p->offset = 0;
3105574Smx205022 
3115574Smx205022 	return (DDI_SUCCESS);
3125574Smx205022 
3135574Smx205022 fail:
3145574Smx205022 	nge_free_dma_mem(dma_p);
3155574Smx205022 	NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!"));
3165574Smx205022 
3175574Smx205022 	return (DDI_FAILURE);
3185574Smx205022 }
3195574Smx205022 
3205574Smx205022 /*
3215574Smx205022  * Free one allocated area of DMAable memory
3225574Smx205022  */
3235574Smx205022 void
3245574Smx205022 nge_free_dma_mem(dma_area_t *dma_p)
3255574Smx205022 {
3265574Smx205022 	if (dma_p->dma_hdl != NULL) {
3275574Smx205022 		if (dma_p->ncookies) {
3285574Smx205022 			(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
3295574Smx205022 			dma_p->ncookies = 0;
3305574Smx205022 		}
3315574Smx205022 	}
3325574Smx205022 	if (dma_p->acc_hdl != NULL) {
3335574Smx205022 		ddi_dma_mem_free(&dma_p->acc_hdl);
3345574Smx205022 		dma_p->acc_hdl = NULL;
3355574Smx205022 	}
3365574Smx205022 	if (dma_p->dma_hdl != NULL) {
3375574Smx205022 		ddi_dma_free_handle(&dma_p->dma_hdl);
3385574Smx205022 		dma_p->dma_hdl = NULL;
3395574Smx205022 	}
3405574Smx205022 }
3415574Smx205022 
3425574Smx205022 #define	ALLOC_TX_BUF	0x1
3435574Smx205022 #define	ALLOC_TX_DESC	0x2
3445574Smx205022 #define	ALLOC_RX_DESC	0x4
3455574Smx205022 
3465574Smx205022 int
3475574Smx205022 nge_alloc_bufs(nge_t *ngep)
3485574Smx205022 {
3495574Smx205022 	int err;
3505574Smx205022 	int split;
3515574Smx205022 	int progress;
3525574Smx205022 	size_t txbuffsize;
3535574Smx205022 	size_t rxdescsize;
3545574Smx205022 	size_t txdescsize;
3555574Smx205022 
3565574Smx205022 	txbuffsize = ngep->tx_desc * ngep->buf_size;
3575574Smx205022 	rxdescsize = ngep->rx_desc;
3585574Smx205022 	txdescsize = ngep->tx_desc;
3595574Smx205022 	rxdescsize *= ngep->desc_attr.rxd_size;
3605574Smx205022 	txdescsize *= ngep->desc_attr.txd_size;
3615574Smx205022 	progress = 0;
3625574Smx205022 
3635574Smx205022 	NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep));
3645574Smx205022 	/*
3655574Smx205022 	 * Allocate memory & handles for TX buffers
3665574Smx205022 	 */
3675574Smx205022 	ASSERT((txbuffsize % ngep->nge_split) == 0);
3685574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
3695574Smx205022 		err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split,
3705574Smx205022 		    &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE,
3715574Smx205022 		    &ngep->send->buf[split]);
3725574Smx205022 		if (err != DDI_SUCCESS)
3735574Smx205022 			goto fail;
3745574Smx205022 	}
3755574Smx205022 
3765574Smx205022 	progress |= ALLOC_TX_BUF;
3775574Smx205022 
3785574Smx205022 	/*
3795574Smx205022 	 * Allocate memory & handles for receive return rings and
3805574Smx205022 	 * buffer (producer) descriptor rings
3815574Smx205022 	 */
3825574Smx205022 	err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr,
3835574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc);
3845574Smx205022 	if (err != DDI_SUCCESS)
3855574Smx205022 		goto fail;
3865574Smx205022 	progress |= ALLOC_RX_DESC;
3875574Smx205022 
3885574Smx205022 	/*
3895574Smx205022 	 * Allocate memory & handles for TX descriptor rings,
3905574Smx205022 	 */
3915574Smx205022 	err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr,
3925574Smx205022 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc);
3935574Smx205022 	if (err != DDI_SUCCESS)
3945574Smx205022 		goto fail;
3955574Smx205022 	return (DDI_SUCCESS);
3965574Smx205022 
3975574Smx205022 fail:
3985574Smx205022 	if (progress & ALLOC_RX_DESC)
3995574Smx205022 		nge_free_dma_mem(&ngep->recv->desc);
4005574Smx205022 	if (progress & ALLOC_TX_BUF) {
4015574Smx205022 		for (split = 0; split < ngep->nge_split; ++split)
4025574Smx205022 			nge_free_dma_mem(&ngep->send->buf[split]);
4035574Smx205022 	}
4045574Smx205022 
4055574Smx205022 	return (DDI_FAILURE);
4065574Smx205022 }
4075574Smx205022 
4085574Smx205022 /*
4095574Smx205022  * This routine frees the transmit and receive buffers and descriptors.
4105574Smx205022  * Make sure the chip is stopped before calling it!
4115574Smx205022  */
4125574Smx205022 void
4135574Smx205022 nge_free_bufs(nge_t *ngep)
4145574Smx205022 {
4155574Smx205022 	int split;
4165574Smx205022 
4175574Smx205022 	NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep));
4185574Smx205022 
4195574Smx205022 	nge_free_dma_mem(&ngep->recv->desc);
4205574Smx205022 	nge_free_dma_mem(&ngep->send->desc);
4215574Smx205022 
4225574Smx205022 	for (split = 0; split < ngep->nge_split; ++split)
4235574Smx205022 		nge_free_dma_mem(&ngep->send->buf[split]);
4245574Smx205022 }
4255574Smx205022 
4265574Smx205022 /*
4275574Smx205022  * Clean up initialisation done above before the memory is freed
4285574Smx205022  */
4295574Smx205022 static void
4305574Smx205022 nge_fini_send_ring(nge_t *ngep)
4315574Smx205022 {
4325574Smx205022 	uint32_t slot;
4335574Smx205022 	size_t dmah_num;
4345574Smx205022 	send_ring_t *srp;
4355574Smx205022 	sw_tx_sbd_t *ssbdp;
4365574Smx205022 
4375574Smx205022 	srp = ngep->send;
4385574Smx205022 	ssbdp = srp->sw_sbds;
4395574Smx205022 
4405574Smx205022 	NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep));
4415574Smx205022 
4425574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
4435574Smx205022 
4445574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
4455574Smx205022 		if (srp->dmahndl[slot].hndl) {
4465574Smx205022 			(void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl);
4475574Smx205022 			ddi_dma_free_handle(&srp->dmahndl[slot].hndl);
4485574Smx205022 			srp->dmahndl[slot].hndl = NULL;
4495574Smx205022 			srp->dmahndl[slot].next = NULL;
4505574Smx205022 		}
4515574Smx205022 	}
4525574Smx205022 
4535574Smx205022 	srp->dmah_free.head = NULL;
4545574Smx205022 	srp->dmah_free.tail = NULL;
4555574Smx205022 
4565574Smx205022 	kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp));
4575574Smx205022 
4585574Smx205022 }
4595574Smx205022 
4605574Smx205022 /*
4615574Smx205022  * Initialise the specified Send Ring, using the information in the
4625574Smx205022  * <dma_area> descriptors that it contains to set up all the other
4635574Smx205022  * fields. This routine should be called only once for each ring.
4645574Smx205022  */
4655574Smx205022 static int
4665574Smx205022 nge_init_send_ring(nge_t *ngep)
4675574Smx205022 {
4685574Smx205022 	size_t dmah_num;
4695574Smx205022 	uint32_t nslots;
4705574Smx205022 	uint32_t err;
4715574Smx205022 	uint32_t slot;
4725574Smx205022 	uint32_t split;
4735574Smx205022 	send_ring_t *srp;
4745574Smx205022 	sw_tx_sbd_t *ssbdp;
4755574Smx205022 	dma_area_t desc;
4765574Smx205022 	dma_area_t pbuf;
4775574Smx205022 
4785574Smx205022 	srp = ngep->send;
4795574Smx205022 	srp->desc.nslots = ngep->tx_desc;
4805574Smx205022 	nslots = srp->desc.nslots;
4815574Smx205022 
4825574Smx205022 	NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep));
4835574Smx205022 	/*
4845574Smx205022 	 * Other one-off initialisation of per-ring data
4855574Smx205022 	 */
4865574Smx205022 	srp->ngep = ngep;
4875574Smx205022 
4885574Smx205022 	/*
4895574Smx205022 	 * Allocate the array of s/w Send Buffer Descriptors
4905574Smx205022 	 */
4915574Smx205022 	ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
4925574Smx205022 	srp->sw_sbds = ssbdp;
4935574Smx205022 
4945574Smx205022 	/*
4955574Smx205022 	 * Now initialise each array element once and for all
4965574Smx205022 	 */
4975574Smx205022 	desc = srp->desc;
4985574Smx205022 	for (split = 0; split < ngep->nge_split; ++split) {
4995574Smx205022 		pbuf = srp->buf[split];
5005574Smx205022 		for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) {
5015574Smx205022 			nge_slice_chunk(&ssbdp->desc, &desc, 1,
5025574Smx205022 			    ngep->desc_attr.txd_size);
5035574Smx205022 			nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1,
5045574Smx205022 			    ngep->buf_size);
5055574Smx205022 		}
5065574Smx205022 		ASSERT(pbuf.alength == 0);
5075574Smx205022 	}
5085574Smx205022 	ASSERT(desc.alength == 0);
5095574Smx205022 
5105574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5115574Smx205022 
5125574Smx205022 	/* preallocate dma handles for tx buffer */
5135574Smx205022 	for (slot = 0; slot < dmah_num; ++slot) {
5145574Smx205022 
5155574Smx205022 		err = ddi_dma_alloc_handle(ngep->devinfo,
5165574Smx205022 		    ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT,
5175574Smx205022 		    NULL, &srp->dmahndl[slot].hndl);
5185574Smx205022 
5195574Smx205022 		if (err != DDI_SUCCESS) {
5205574Smx205022 			nge_fini_send_ring(ngep);
5215574Smx205022 			nge_error(ngep,
5225574Smx205022 			    "nge_init_send_ring: alloc dma handle fails");
5235574Smx205022 			return (DDI_FAILURE);
5245574Smx205022 		}
5255574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5265574Smx205022 	}
5275574Smx205022 
5285574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5295574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5305574Smx205022 	srp->dmah_free.tail->next = NULL;
5315574Smx205022 
5325574Smx205022 	return (DDI_SUCCESS);
5335574Smx205022 }
5345574Smx205022 
5355574Smx205022 /*
5365574Smx205022  * Intialize the tx recycle pointer and tx sending pointer of tx ring
5375574Smx205022  * and set the type of tx's data descriptor by default.
5385574Smx205022  */
5395574Smx205022 static void
5405574Smx205022 nge_reinit_send_ring(nge_t *ngep)
5415574Smx205022 {
5425574Smx205022 	size_t dmah_num;
5435574Smx205022 	uint32_t slot;
5445574Smx205022 	send_ring_t *srp;
5455574Smx205022 	sw_tx_sbd_t *ssbdp;
5465574Smx205022 
5475574Smx205022 	srp = ngep->send;
5485574Smx205022 
5495574Smx205022 	/*
5505574Smx205022 	 * Reinitialise control variables ...
5515574Smx205022 	 */
5525574Smx205022 
5535574Smx205022 	srp->tx_hwmark = NGE_DESC_MIN;
5545574Smx205022 	srp->tx_lwmark = NGE_DESC_MIN;
5555574Smx205022 
5565574Smx205022 	srp->tx_next = 0;
5575574Smx205022 	srp->tx_free = srp->desc.nslots;
5585574Smx205022 	srp->tc_next = 0;
5595574Smx205022 
5605574Smx205022 	dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]);
5615574Smx205022 
5625574Smx205022 	for (slot = 0; slot - dmah_num != 0; ++slot)
5635574Smx205022 		srp->dmahndl[slot].next = srp->dmahndl + slot + 1;
5645574Smx205022 
5655574Smx205022 	srp->dmah_free.head = srp->dmahndl;
5665574Smx205022 	srp->dmah_free.tail = srp->dmahndl + dmah_num - 1;
5675574Smx205022 	srp->dmah_free.tail->next = NULL;
5685574Smx205022 
5695574Smx205022 	/*
5705574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
5715574Smx205022 	 */
5725574Smx205022 	for (slot = 0; slot < srp->desc.nslots; ++slot) {
5735574Smx205022 		ssbdp = &srp->sw_sbds[slot];
5745574Smx205022 		ssbdp->flags = HOST_OWN;
5755574Smx205022 	}
5765574Smx205022 
5775574Smx205022 	DMA_ZERO(srp->desc);
5785574Smx205022 	DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
5795574Smx205022 }
5805574Smx205022 
5815574Smx205022 /*
5825574Smx205022  * Initialize the slot number of rx's ring
5835574Smx205022  */
5845574Smx205022 static void
5855574Smx205022 nge_init_recv_ring(nge_t *ngep)
5865574Smx205022 {
5875574Smx205022 	recv_ring_t *rrp;
5885574Smx205022 
5895574Smx205022 	rrp = ngep->recv;
5905574Smx205022 	rrp->desc.nslots = ngep->rx_desc;
5915574Smx205022 	rrp->ngep = ngep;
5925574Smx205022 }
5935574Smx205022 
5945574Smx205022 /*
5955574Smx205022  * Intialize the rx recycle pointer and rx sending pointer of rx ring
5965574Smx205022  */
5975574Smx205022 static void
5985574Smx205022 nge_reinit_recv_ring(nge_t *ngep)
5995574Smx205022 {
6005574Smx205022 	recv_ring_t *rrp;
6015574Smx205022 
6025574Smx205022 	rrp = ngep->recv;
6035574Smx205022 
6045574Smx205022 	/*
6055574Smx205022 	 * Reinitialise control variables ...
6065574Smx205022 	 */
6075574Smx205022 	rrp->prod_index = 0;
6085574Smx205022 	/*
6095574Smx205022 	 * Zero and sync all the h/w Send Buffer Descriptors
6105574Smx205022 	 */
6115574Smx205022 	DMA_ZERO(rrp->desc);
6125574Smx205022 	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV);
6135574Smx205022 }
6145574Smx205022 
6155574Smx205022 /*
6165574Smx205022  * Clean up initialisation done above before the memory is freed
6175574Smx205022  */
6185574Smx205022 static void
6195574Smx205022 nge_fini_buff_ring(nge_t *ngep)
6205574Smx205022 {
6215574Smx205022 	uint32_t i;
6225574Smx205022 	buff_ring_t *brp;
6235574Smx205022 	dma_area_t *bufp;
6245574Smx205022 	sw_rx_sbd_t *bsbdp;
6255574Smx205022 
6265574Smx205022 	brp = ngep->buff;
6275574Smx205022 	bsbdp = brp->sw_rbds;
6285574Smx205022 
6295574Smx205022 	NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep));
6305574Smx205022 
6315574Smx205022 	mutex_enter(brp->recycle_lock);
6325574Smx205022 	brp->buf_sign++;
6335574Smx205022 	mutex_exit(brp->recycle_lock);
6345574Smx205022 	for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) {
6355574Smx205022 		if (bsbdp->bufp) {
6365574Smx205022 			if (bsbdp->bufp->mp)
6375574Smx205022 				freemsg(bsbdp->bufp->mp);
6385574Smx205022 			nge_free_dma_mem(bsbdp->bufp);
6395574Smx205022 			kmem_free(bsbdp->bufp, sizeof (dma_area_t));
6405574Smx205022 			bsbdp->bufp = NULL;
6415574Smx205022 		}
6425574Smx205022 	}
6435574Smx205022 	while (brp->free_list != NULL) {
6445574Smx205022 		bufp = brp->free_list;
6455574Smx205022 		brp->free_list = bufp->next;
6465574Smx205022 		bufp->next = NULL;
6475574Smx205022 		if (bufp->mp)
6485574Smx205022 			freemsg(bufp->mp);
6495574Smx205022 		nge_free_dma_mem(bufp);
6505574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6515574Smx205022 	}
6525574Smx205022 	while (brp->recycle_list != NULL) {
6535574Smx205022 		bufp = brp->recycle_list;
6545574Smx205022 		brp->recycle_list = bufp->next;
6555574Smx205022 		bufp->next = NULL;
6565574Smx205022 		if (bufp->mp)
6575574Smx205022 			freemsg(bufp->mp);
6585574Smx205022 		nge_free_dma_mem(bufp);
6595574Smx205022 		kmem_free(bufp, sizeof (dma_area_t));
6605574Smx205022 	}
6615574Smx205022 
6625574Smx205022 
6635574Smx205022 	kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp)));
6645574Smx205022 	brp->sw_rbds = NULL;
6655574Smx205022 }
6665574Smx205022 
6675574Smx205022 /*
6685574Smx205022  * Intialize the Rx's data ring and free ring
6695574Smx205022  */
6705574Smx205022 static int
6715574Smx205022 nge_init_buff_ring(nge_t *ngep)
6725574Smx205022 {
6735574Smx205022 	uint32_t err;
6745574Smx205022 	uint32_t slot;
6755574Smx205022 	uint32_t nslots_buff;
6765574Smx205022 	uint32_t nslots_recv;
6775574Smx205022 	buff_ring_t *brp;
6785574Smx205022 	recv_ring_t *rrp;
6795574Smx205022 	dma_area_t desc;
6805574Smx205022 	dma_area_t *bufp;
6815574Smx205022 	sw_rx_sbd_t *bsbdp;
6825574Smx205022 
6835574Smx205022 	rrp = ngep->recv;
6845574Smx205022 	brp = ngep->buff;
6855574Smx205022 	brp->nslots = ngep->rx_buf;
6865574Smx205022 	brp->rx_bcopy = B_FALSE;
6875574Smx205022 	nslots_recv = rrp->desc.nslots;
6885574Smx205022 	nslots_buff = brp->nslots;
6895574Smx205022 	brp->ngep = ngep;
6905574Smx205022 
6915574Smx205022 	NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep));
6925574Smx205022 
6935574Smx205022 	/*
6945574Smx205022 	 * Allocate the array of s/w Recv Buffer Descriptors
6955574Smx205022 	 */
6965574Smx205022 	bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP);
6975574Smx205022 	brp->sw_rbds = bsbdp;
6985574Smx205022 	brp->free_list = NULL;
6995574Smx205022 	brp->recycle_list = NULL;
7005574Smx205022 	for (slot = 0; slot < nslots_buff; ++slot) {
7015574Smx205022 		bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP);
7025574Smx205022 		err = nge_alloc_dma_mem(ngep, (ngep->buf_size
7035574Smx205022 		    + NGE_HEADROOM),
7045574Smx205022 		    &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp);
7055574Smx205022 		if (err != DDI_SUCCESS) {
7065574Smx205022 			kmem_free(bufp, sizeof (dma_area_t));
7075574Smx205022 			return (DDI_FAILURE);
7085574Smx205022 		}
7095574Smx205022 
7105574Smx205022 		bufp->alength -= NGE_HEADROOM;
7115574Smx205022 		bufp->offset += NGE_HEADROOM;
7125574Smx205022 		bufp->private = (caddr_t)ngep;
7135574Smx205022 		bufp->rx_recycle.free_func = nge_recv_recycle;
7145574Smx205022 		bufp->rx_recycle.free_arg = (caddr_t)bufp;
7155574Smx205022 		bufp->signature = brp->buf_sign;
7165574Smx205022 		bufp->rx_delivered = B_FALSE;
7175574Smx205022 		bufp->mp = desballoc(DMA_VPTR(*bufp),
7185574Smx205022 		    ngep->buf_size + NGE_HEADROOM,
7195574Smx205022 		    0, &bufp->rx_recycle);
7205574Smx205022 
7215574Smx205022 		if (bufp->mp == NULL) {
7225574Smx205022 			return (DDI_FAILURE);
7235574Smx205022 		}
7245574Smx205022 		bufp->next = brp->free_list;
7255574Smx205022 		brp->free_list = bufp;
7265574Smx205022 	}
7275574Smx205022 
7285574Smx205022 	/*
7295574Smx205022 	 * Now initialise each array element once and for all
7305574Smx205022 	 */
7315574Smx205022 	desc = rrp->desc;
7325574Smx205022 	for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) {
7335574Smx205022 		nge_slice_chunk(&bsbdp->desc, &desc, 1,
7345574Smx205022 		    ngep->desc_attr.rxd_size);
7355574Smx205022 		bufp = brp->free_list;
7365574Smx205022 		brp->free_list = bufp->next;
7375574Smx205022 		bsbdp->bufp = bufp;
7385574Smx205022 		bsbdp->flags = CONTROLER_OWN;
7395574Smx205022 		bufp->next = NULL;
7405574Smx205022 	}
7415574Smx205022 
7425574Smx205022 	ASSERT(desc.alength == 0);
7435574Smx205022 	return (DDI_SUCCESS);
7445574Smx205022 }
7455574Smx205022 
7465574Smx205022 /*
7475574Smx205022  * Fill the host address of data in rx' descriptor
7485574Smx205022  * and initialize free pointers of rx free ring
7495574Smx205022  */
7505574Smx205022 static int
7515574Smx205022 nge_reinit_buff_ring(nge_t *ngep)
7525574Smx205022 {
7535574Smx205022 	uint32_t slot;
7545574Smx205022 	uint32_t nslots_recv;
7555574Smx205022 	buff_ring_t *brp;
7565574Smx205022 	recv_ring_t *rrp;
7575574Smx205022 	sw_rx_sbd_t *bsbdp;
7585574Smx205022 	void *hw_bd_p;
7595574Smx205022 
7605574Smx205022 	brp = ngep->buff;
7615574Smx205022 	rrp = ngep->recv;
7625574Smx205022 	bsbdp = brp->sw_rbds;
7635574Smx205022 	nslots_recv = rrp->desc.nslots;
7645574Smx205022 	for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) {
7655574Smx205022 		hw_bd_p = DMA_VPTR(bsbdp->desc);
7665574Smx205022 	/*
7675574Smx205022 	 * There is a scenario: When the traffic of small tcp
7685574Smx205022 	 * packet is heavy, suspending the tcp traffic will
7695574Smx205022 	 * cause the preallocated buffers for rx not to be
7705574Smx205022 	 * released in time by tcp taffic and cause rx's buffer
7715574Smx205022 	 * pointers not to be refilled in time.
7725574Smx205022 	 *
7735574Smx205022 	 * At this point, if we reinitialize the driver, the bufp
7745574Smx205022 	 * pointer for rx's traffic will be NULL.
7755574Smx205022 	 * So the result of the reinitializion fails.
7765574Smx205022 	 */
7775574Smx205022 		if (bsbdp->bufp == NULL)
7785574Smx205022 			return (DDI_FAILURE);
7795574Smx205022 
7805574Smx205022 		ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie,
7815574Smx205022 		    bsbdp->bufp->alength);
7825574Smx205022 	}
7835574Smx205022 	return (DDI_SUCCESS);
7845574Smx205022 }
7855574Smx205022 
7865574Smx205022 static void
7875574Smx205022 nge_init_ring_param_lock(nge_t *ngep)
7885574Smx205022 {
7895574Smx205022 	buff_ring_t *brp;
7905574Smx205022 	send_ring_t *srp;
7915574Smx205022 
7925574Smx205022 	srp = ngep->send;
7935574Smx205022 	brp = ngep->buff;
7945574Smx205022 
7955574Smx205022 	/* Init the locks for send ring */
7965574Smx205022 	mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
7975574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
7985574Smx205022 	mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
7995574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8005574Smx205022 	mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER,
8015574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8025574Smx205022 
8035574Smx205022 	/* Init parameters of buffer ring */
8045574Smx205022 	brp->free_list = NULL;
8055574Smx205022 	brp->recycle_list = NULL;
8065574Smx205022 	brp->rx_hold = 0;
8075574Smx205022 	brp->buf_sign = 0;
8085574Smx205022 
8095574Smx205022 	/* Init recycle list lock */
8105574Smx205022 	mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER,
8115574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
8125574Smx205022 }
8135574Smx205022 
8145574Smx205022 int
8155574Smx205022 nge_init_rings(nge_t *ngep)
8165574Smx205022 {
8175574Smx205022 	uint32_t err;
8185574Smx205022 
8195574Smx205022 	err = nge_init_send_ring(ngep);
8205574Smx205022 	if (err != DDI_SUCCESS) {
8215574Smx205022 		return (err);
8225574Smx205022 	}
8235574Smx205022 	nge_init_recv_ring(ngep);
8245574Smx205022 
8255574Smx205022 	err = nge_init_buff_ring(ngep);
8265574Smx205022 	if (err != DDI_SUCCESS) {
8275574Smx205022 		nge_fini_send_ring(ngep);
8285574Smx205022 		return (DDI_FAILURE);
8295574Smx205022 	}
8305574Smx205022 
8315574Smx205022 	return (err);
8325574Smx205022 }
8335574Smx205022 
8345574Smx205022 static int
8355574Smx205022 nge_reinit_ring(nge_t *ngep)
8365574Smx205022 {
8375574Smx205022 	int err;
8385574Smx205022 
8395574Smx205022 	nge_reinit_recv_ring(ngep);
8405574Smx205022 	nge_reinit_send_ring(ngep);
8415574Smx205022 	err = nge_reinit_buff_ring(ngep);
8425574Smx205022 	return (err);
8435574Smx205022 }
8445574Smx205022 
8455574Smx205022 
8465574Smx205022 void
8475574Smx205022 nge_fini_rings(nge_t *ngep)
8485574Smx205022 {
8495574Smx205022 	/*
8505574Smx205022 	 * For receive ring, nothing need to be finished.
8515574Smx205022 	 * So only finish buffer ring and send ring here.
8525574Smx205022 	 */
8535574Smx205022 	nge_fini_buff_ring(ngep);
8545574Smx205022 	nge_fini_send_ring(ngep);
8555574Smx205022 }
8565574Smx205022 
8575574Smx205022 /*
8585574Smx205022  * Loopback ioctl code
8595574Smx205022  */
8605574Smx205022 
8615574Smx205022 static lb_property_t loopmodes[] = {
8625574Smx205022 	{ normal,	"normal",	NGE_LOOP_NONE		},
8635574Smx205022 	{ external,	"100Mbps",	NGE_LOOP_EXTERNAL_100	},
8645574Smx205022 	{ external,	"10Mbps",	NGE_LOOP_EXTERNAL_10	},
8655574Smx205022 	{ internal,	"PHY",		NGE_LOOP_INTERNAL_PHY	},
8665574Smx205022 };
8675574Smx205022 
8685574Smx205022 enum ioc_reply
8695574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp)
8705574Smx205022 {
8715574Smx205022 	int cmd;
8725574Smx205022 	uint32_t *lbmp;
8735574Smx205022 	lb_info_sz_t *lbsp;
8745574Smx205022 	lb_property_t *lbpp;
8755574Smx205022 
8765574Smx205022 	/*
8775574Smx205022 	 * Validate format of ioctl
8785574Smx205022 	 */
8795574Smx205022 	if (mp->b_cont == NULL)
8805574Smx205022 		return (IOC_INVAL);
8815574Smx205022 
8825574Smx205022 	cmd = iocp->ioc_cmd;
8835574Smx205022 
8845574Smx205022 	switch (cmd) {
8855574Smx205022 	default:
8865574Smx205022 		return (IOC_INVAL);
8875574Smx205022 
8885574Smx205022 	case LB_GET_INFO_SIZE:
8895574Smx205022 		if (iocp->ioc_count != sizeof (lb_info_sz_t))
8905574Smx205022 			return (IOC_INVAL);
8915574Smx205022 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
8925574Smx205022 		*lbsp = sizeof (loopmodes);
8935574Smx205022 		return (IOC_REPLY);
8945574Smx205022 
8955574Smx205022 	case LB_GET_INFO:
8965574Smx205022 		if (iocp->ioc_count != sizeof (loopmodes))
8975574Smx205022 			return (IOC_INVAL);
8985574Smx205022 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
8995574Smx205022 		bcopy(loopmodes, lbpp, sizeof (loopmodes));
9005574Smx205022 		return (IOC_REPLY);
9015574Smx205022 
9025574Smx205022 	case LB_GET_MODE:
9035574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9045574Smx205022 			return (IOC_INVAL);
9055574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9065574Smx205022 		*lbmp = ngep->param_loop_mode;
9075574Smx205022 		return (IOC_REPLY);
9085574Smx205022 
9095574Smx205022 	case LB_SET_MODE:
9105574Smx205022 		if (iocp->ioc_count != sizeof (uint32_t))
9115574Smx205022 			return (IOC_INVAL);
9125574Smx205022 		lbmp = (uint32_t *)mp->b_cont->b_rptr;
9135574Smx205022 		return (nge_set_loop_mode(ngep, *lbmp));
9145574Smx205022 	}
9155574Smx205022 }
9165574Smx205022 
9175574Smx205022 #undef	NGE_DBG
9185574Smx205022 #define	NGE_DBG	NGE_DBG_NEMO
9195574Smx205022 
9205574Smx205022 
9215574Smx205022 static void
9225574Smx205022 nge_check_desc_prop(nge_t *ngep)
9235574Smx205022 {
9245574Smx205022 	if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD)
9255574Smx205022 		ngep->desc_mode = DESC_HOT;
9265574Smx205022 
9275574Smx205022 	if (ngep->desc_mode == DESC_OFFLOAD)	{
9285574Smx205022 
9295574Smx205022 		ngep->desc_attr = nge_sum_desc;
9305574Smx205022 
9315574Smx205022 	}	else if (ngep->desc_mode == DESC_HOT)	{
9325574Smx205022 
9335574Smx205022 		ngep->desc_attr = nge_hot_desc;
9345574Smx205022 	}
9355574Smx205022 }
9365574Smx205022 
9375574Smx205022 /*
9385574Smx205022  * nge_get_props -- get the parameters to tune the driver
9395574Smx205022  */
9405574Smx205022 static void
9415574Smx205022 nge_get_props(nge_t *ngep)
9425574Smx205022 {
9435574Smx205022 	chip_info_t *infop;
9445574Smx205022 	dev_info_t *devinfo;
9455574Smx205022 	nge_dev_spec_param_t *dev_param_p;
9465574Smx205022 
9475574Smx205022 	devinfo = ngep->devinfo;
9485574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
9495574Smx205022 	dev_param_p = &ngep->dev_spec_param;
9505574Smx205022 
9515574Smx205022 	infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9525574Smx205022 	    DDI_PROP_DONTPASS, clsize_propname, 32);
9535574Smx205022 
9545574Smx205022 	infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9555574Smx205022 	    DDI_PROP_DONTPASS, latency_propname, 64);
9565574Smx205022 	ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9575574Smx205022 	    DDI_PROP_DONTPASS, rx_data_hw, 0x20);
9585574Smx205022 	ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9595574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_lw, 0x4);
9605574Smx205022 	ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9615574Smx205022 	    DDI_PROP_DONTPASS, rx_prd_hw, 0xc);
9625574Smx205022 
9635574Smx205022 	ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9645574Smx205022 	    DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC);
9655574Smx205022 	ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9665574Smx205022 	    DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP);
9675574Smx205022 	ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9685574Smx205022 	    DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type);
9695574Smx205022 	ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9705574Smx205022 	    DDI_PROP_DONTPASS, low_memory_mode, 0);
9715574Smx205022 
9725574Smx205022 	if (dev_param_p->jumbo) {
9735574Smx205022 		ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
9745574Smx205022 		    DDI_PROP_DONTPASS, default_mtu, ETHERMTU);
9755574Smx205022 	} else
9765574Smx205022 		ngep->default_mtu = ETHERMTU;
9775574Smx205022 
9785574Smx205022 	if (ngep->default_mtu > ETHERMTU &&
9795574Smx205022 	    ngep->default_mtu <= NGE_MTU_2500) {
9805574Smx205022 		ngep->buf_size = NGE_JB2500_BUFSZ;
9815574Smx205022 		ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC;
9825574Smx205022 		ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC;
9835574Smx205022 		ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2;
9845574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
9855574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_2500 &&
9865574Smx205022 	    ngep->default_mtu <= NGE_MTU_4500) {
9875574Smx205022 		ngep->buf_size = NGE_JB4500_BUFSZ;
9885574Smx205022 		ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC;
9895574Smx205022 		ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC;
9905574Smx205022 		ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2;
9915574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
9925574Smx205022 	} else if (ngep->default_mtu > NGE_MTU_4500 &&
9935574Smx205022 	    ngep->default_mtu <= NGE_MAX_MTU) {
9945574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
9955574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
9965574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
9975574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
9985574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
9995574Smx205022 	} else if (ngep->default_mtu > NGE_MAX_MTU) {
10005574Smx205022 		ngep->default_mtu = NGE_MAX_MTU;
10015574Smx205022 		ngep->buf_size = NGE_JB9000_BUFSZ;
10025574Smx205022 		ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC;
10035574Smx205022 		ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC;
10045574Smx205022 		ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2;
10055574Smx205022 		ngep->nge_split = NGE_SPLIT_256;
10065574Smx205022 	} else if (ngep->lowmem_mode != 0) {
10075574Smx205022 		ngep->default_mtu = ETHERMTU;
10085574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10095574Smx205022 		ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC;
10105574Smx205022 		ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC;
10115574Smx205022 		ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2;
10125574Smx205022 		ngep->nge_split = NGE_SPLIT_32;
10135574Smx205022 	} else {
10145574Smx205022 		ngep->default_mtu = ETHERMTU;
10155574Smx205022 		ngep->buf_size = NGE_STD_BUFSZ;
10165574Smx205022 		ngep->tx_desc = dev_param_p->tx_desc_num;
10175574Smx205022 		ngep->rx_desc = dev_param_p->rx_desc_num;
10185574Smx205022 		ngep->rx_buf = dev_param_p->rx_desc_num * 2;
10195574Smx205022 		ngep->nge_split = dev_param_p->nge_split;
10205574Smx205022 	}
10215574Smx205022 
10225574Smx205022 	nge_check_desc_prop(ngep);
10235574Smx205022 }
10245574Smx205022 
10255574Smx205022 
10265574Smx205022 static int
10275574Smx205022 nge_reset(nge_t *ngep)
10285574Smx205022 {
10295574Smx205022 	int err;
10305574Smx205022 	send_ring_t *srp = ngep->send;
10315574Smx205022 
10325574Smx205022 	ASSERT(mutex_owned(ngep->genlock));
10335574Smx205022 	mutex_enter(srp->tc_lock);
10345574Smx205022 	mutex_enter(srp->tx_lock);
10355574Smx205022 
10365574Smx205022 	nge_tx_recycle_all(ngep);
10375574Smx205022 	err = nge_reinit_ring(ngep);
10385574Smx205022 	if (err == DDI_FAILURE) {
10395574Smx205022 		mutex_exit(srp->tx_lock);
10405574Smx205022 		mutex_exit(srp->tc_lock);
10415574Smx205022 		return (err);
10425574Smx205022 	}
10435574Smx205022 	err = nge_chip_reset(ngep);
10445574Smx205022 	mutex_exit(srp->tx_lock);
10455574Smx205022 	mutex_exit(srp->tc_lock);
10465574Smx205022 	if (err == DDI_FAILURE)
10475574Smx205022 		return (err);
10485574Smx205022 	ngep->watchdog = 0;
10495574Smx205022 	ngep->resched_needed = B_FALSE;
10505574Smx205022 	ngep->promisc = B_FALSE;
10515574Smx205022 	ngep->param_loop_mode = NGE_LOOP_NONE;
10525574Smx205022 	ngep->factotum_flag = 0;
10535574Smx205022 	ngep->resched_needed = 0;
10545574Smx205022 	ngep->nge_mac_state = NGE_MAC_RESET;
10555574Smx205022 	ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
10565574Smx205022 	ngep->max_sdu += VTAG_SIZE;
10575574Smx205022 	ngep->rx_def = 0x16;
10585574Smx205022 	return (DDI_SUCCESS);
10595574Smx205022 }
10605574Smx205022 
10615574Smx205022 static void
10625574Smx205022 nge_m_stop(void *arg)
10635574Smx205022 {
10645574Smx205022 	nge_t *ngep = arg;		/* private device info	*/
10655574Smx205022 
10665574Smx205022 	NGE_TRACE(("nge_m_stop($%p)", arg));
10675574Smx205022 
10685574Smx205022 	/*
10695574Smx205022 	 * If suspended, adapter is already stopped, just return.
10705574Smx205022 	 */
10715574Smx205022 	if (ngep->suspended) {
10725574Smx205022 		ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
10735574Smx205022 		return;
10745574Smx205022 	}
10755574Smx205022 
10765574Smx205022 	/*
10775574Smx205022 	 * Just stop processing, then record new MAC state
10785574Smx205022 	 */
10795574Smx205022 	mutex_enter(ngep->genlock);
10805574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
10815574Smx205022 
10825574Smx205022 	(void) nge_chip_stop(ngep, B_FALSE);
10835574Smx205022 	/* Try to wait all the buffer post to upper layer be released */
10845574Smx205022 	ngep->nge_mac_state = NGE_MAC_STOPPED;
10855574Smx205022 
10865574Smx205022 	/* Recycle all the TX BD */
10875574Smx205022 	nge_tx_recycle_all(ngep);
10885574Smx205022 	nge_fini_rings(ngep);
10895574Smx205022 	nge_free_bufs(ngep);
10905574Smx205022 
10915574Smx205022 	NGE_DEBUG(("nge_m_stop($%p) done", arg));
10925574Smx205022 
10935574Smx205022 	rw_exit(ngep->rwlock);
10945574Smx205022 	mutex_exit(ngep->genlock);
10955574Smx205022 }
10965574Smx205022 
10975574Smx205022 static int
10985574Smx205022 nge_m_start(void *arg)
10995574Smx205022 {
11005574Smx205022 	int err;
11015574Smx205022 	nge_t *ngep = arg;
11025574Smx205022 
11035574Smx205022 	NGE_TRACE(("nge_m_start($%p)", arg));
11045574Smx205022 	/*
11055574Smx205022 	 * If suspended, don't start, as the resume processing
11065574Smx205022 	 * will recall this function with the suspended flag off.
11075574Smx205022 	 */
11085574Smx205022 	if (ngep->suspended)
11095574Smx205022 		return (DDI_FAILURE);
11105574Smx205022 	/*
11115574Smx205022 	 * Start processing and record new MAC state
11125574Smx205022 	 */
11135574Smx205022 	mutex_enter(ngep->genlock);
11145574Smx205022 	rw_enter(ngep->rwlock, RW_WRITER);
11155574Smx205022 	err = nge_alloc_bufs(ngep);
11165574Smx205022 	if (err != DDI_SUCCESS) {
11175574Smx205022 		nge_problem(ngep, "nge_m_start: DMA buffer allocation failed");
11185574Smx205022 		goto finish;
11195574Smx205022 	}
11205574Smx205022 	err = nge_init_rings(ngep);
11215574Smx205022 	if (err != DDI_SUCCESS) {
11225574Smx205022 		nge_free_bufs(ngep);
11235574Smx205022 		nge_problem(ngep, "nge_init_rings() failed,err=%x");
11245574Smx205022 		goto finish;
11255574Smx205022 	}
11265574Smx205022 	err = nge_restart(ngep);
11275574Smx205022 
11285574Smx205022 	NGE_DEBUG(("nge_m_start($%p) done", arg));
11295574Smx205022 	finish:
11305574Smx205022 		rw_exit(ngep->rwlock);
11315574Smx205022 		mutex_exit(ngep->genlock);
11325574Smx205022 
11335574Smx205022 		return (err);
11345574Smx205022 }
11355574Smx205022 
11365574Smx205022 static int
11375574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr)
11385574Smx205022 {
11395574Smx205022 	nge_t *ngep = arg;
11405574Smx205022 
11415574Smx205022 	NGE_TRACE(("nge_m_unicst($%p)", arg));
11425574Smx205022 	/*
11435574Smx205022 	 * Remember the new current address in the driver state
11445574Smx205022 	 * Sync the chip's idea of the address too ...
11455574Smx205022 	 */
11465574Smx205022 	mutex_enter(ngep->genlock);
11475574Smx205022 
11485574Smx205022 	ethaddr_copy(macaddr, ngep->cur_uni_addr.addr);
11495574Smx205022 	ngep->cur_uni_addr.set = 1;
11505574Smx205022 
11515574Smx205022 	/*
11525574Smx205022 	 * If we are suspended, we want to quit now, and not update
11535574Smx205022 	 * the chip.  Doing so might put it in a bad state, but the
11545574Smx205022 	 * resume will get the unicast address installed.
11555574Smx205022 	 */
11565574Smx205022 	if (ngep->suspended)
11575574Smx205022 		return (DDI_SUCCESS);
11585574Smx205022 
11595574Smx205022 	nge_chip_sync(ngep);
11605574Smx205022 
11615574Smx205022 	NGE_DEBUG(("nge_m_unicst($%p) done", arg));
11625574Smx205022 	mutex_exit(ngep->genlock);
11635574Smx205022 
11645574Smx205022 	return (0);
11655574Smx205022 }
11665574Smx205022 
11675574Smx205022 static int
11685574Smx205022 nge_m_promisc(void *arg, boolean_t on)
11695574Smx205022 {
11705574Smx205022 	nge_t *ngep = arg;
11715574Smx205022 
11725574Smx205022 	NGE_TRACE(("nge_m_promisc($%p)", arg));
11735574Smx205022 	/*
11745574Smx205022 	 * If suspended, we don't do anything, even record the promiscuious
11755574Smx205022 	 * mode, as we won't properly set it on resume.  Just fail.
11765574Smx205022 	 */
11775574Smx205022 	if (ngep->suspended)
11785574Smx205022 		return (DDI_FAILURE);
11795574Smx205022 
11805574Smx205022 	/*
11815574Smx205022 	 * Store specified mode and pass to chip layer to update h/w
11825574Smx205022 	 */
11835574Smx205022 	mutex_enter(ngep->genlock);
11845574Smx205022 	if (ngep->promisc == on) {
11855574Smx205022 		mutex_exit(ngep->genlock);
11865574Smx205022 		NGE_DEBUG(("nge_m_promisc($%p) done", arg));
11875574Smx205022 		return (0);
11885574Smx205022 	}
11895574Smx205022 	ngep->promisc = on;
11905574Smx205022 	nge_chip_sync(ngep);
11915574Smx205022 	NGE_DEBUG(("nge_m_promisc($%p) done", arg));
11925574Smx205022 	mutex_exit(ngep->genlock);
11935574Smx205022 
11945574Smx205022 	return (0);
11955574Smx205022 }
11965574Smx205022 
11975574Smx205022 static void nge_mulparam(nge_t *ngep)
11985574Smx205022 {
11995574Smx205022 	uint8_t number;
12005574Smx205022 	ether_addr_t pand;
12015574Smx205022 	ether_addr_t por;
12025574Smx205022 	mul_item *plist;
12035574Smx205022 
12045574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12055574Smx205022 		pand[number] = 0x00;
12065574Smx205022 		por[number] = 0x00;
12075574Smx205022 	}
12085574Smx205022 	for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) {
12095574Smx205022 		for (number = 0; number < ETHERADDRL; number++) {
12105574Smx205022 			pand[number] &= plist->mul_addr[number];
12115574Smx205022 			por[number] |= plist->mul_addr[number];
12125574Smx205022 		}
12135574Smx205022 	}
12145574Smx205022 	for (number = 0; number < ETHERADDRL; number++) {
12155574Smx205022 		ngep->cur_mul_addr.addr[number]
12165574Smx205022 		    = pand[number] & por[number];
12175574Smx205022 		ngep->cur_mul_mask.addr[number]
12185574Smx205022 		    = pand [number] | (~por[number]);
12195574Smx205022 	}
12205574Smx205022 }
12215574Smx205022 static int
12225574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
12235574Smx205022 {
12245574Smx205022 	boolean_t update;
12255574Smx205022 	boolean_t b_eq;
12265574Smx205022 	nge_t *ngep = arg;
12275574Smx205022 	mul_item *plist;
12285574Smx205022 	mul_item *plist_prev;
12295574Smx205022 	mul_item *pitem;
12305574Smx205022 
12315574Smx205022 	NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg,
12325574Smx205022 	    (add) ? "add" : "remove", ether_sprintf((void *)mca)));
12335574Smx205022 
12345574Smx205022 	update = B_FALSE;
12355574Smx205022 	plist = plist_prev = NULL;
12365574Smx205022 	mutex_enter(ngep->genlock);
12375574Smx205022 	if (add) {
12385574Smx205022 		if (ngep->pcur_mulist != NULL) {
12395574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
12405574Smx205022 			    plist = plist->next) {
12415574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
12425574Smx205022 				if (b_eq) {
12435574Smx205022 					plist->ref_cnt++;
12445574Smx205022 					break;
12455574Smx205022 				}
12465574Smx205022 				plist_prev = plist;
12475574Smx205022 			}
12485574Smx205022 		}
12495574Smx205022 
12505574Smx205022 		if (plist == NULL) {
12515574Smx205022 			pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP);
12525574Smx205022 			ether_copy(mca, pitem->mul_addr);
12535574Smx205022 			pitem ->ref_cnt++;
12545574Smx205022 			pitem ->next = NULL;
12555574Smx205022 			if (plist_prev == NULL)
12565574Smx205022 				ngep->pcur_mulist = pitem;
12575574Smx205022 			else
12585574Smx205022 				plist_prev->next = pitem;
12595574Smx205022 			update = B_TRUE;
12605574Smx205022 		}
12615574Smx205022 	} else {
12625574Smx205022 		if (ngep->pcur_mulist != NULL) {
12635574Smx205022 			for (plist = ngep->pcur_mulist; plist != NULL;
12645574Smx205022 			    plist = plist->next) {
12655574Smx205022 				b_eq = ether_eq(plist->mul_addr, mca);
12665574Smx205022 				if (b_eq) {
12675574Smx205022 					update = B_TRUE;
12685574Smx205022 					break;
12695574Smx205022 				}
12705574Smx205022 				plist_prev = plist;
12715574Smx205022 			}
12725574Smx205022 
12735574Smx205022 			if (update) {
12745574Smx205022 				if ((plist_prev == NULL) &&
12755574Smx205022 				    (plist->next == NULL))
12765574Smx205022 					ngep->pcur_mulist = NULL;
12775574Smx205022 				else if ((plist_prev == NULL) &&
12785574Smx205022 				    (plist->next != NULL))
12795574Smx205022 					ngep->pcur_mulist = plist->next;
12805574Smx205022 				else
12815574Smx205022 					plist_prev->next = plist->next;
12825574Smx205022 				kmem_free(plist, sizeof (mul_item));
12835574Smx205022 			}
12845574Smx205022 		}
12855574Smx205022 	}
12865574Smx205022 
12875574Smx205022 	if (update || !ngep->suspended) {
12885574Smx205022 		nge_mulparam(ngep);
12895574Smx205022 		nge_chip_sync(ngep);
12905574Smx205022 	}
12915574Smx205022 	NGE_DEBUG(("nge_m_multicst($%p) done", arg));
12925574Smx205022 	mutex_exit(ngep->genlock);
12935574Smx205022 
12945574Smx205022 	return (0);
12955574Smx205022 }
12965574Smx205022 
12975574Smx205022 static void
12985574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
12995574Smx205022 {
13005574Smx205022 	int err;
13015574Smx205022 	int cmd;
13025574Smx205022 	nge_t *ngep = arg;
13035574Smx205022 	struct iocblk *iocp;
13045574Smx205022 	enum ioc_reply status;
13055574Smx205022 	boolean_t need_privilege;
13065574Smx205022 
13075574Smx205022 	/*
13085574Smx205022 	 * If suspended, we might actually be able to do some of
13095574Smx205022 	 * these ioctls, but it is harder to make sure they occur
13105574Smx205022 	 * without actually putting the hardware in an undesireable
13115574Smx205022 	 * state.  So just NAK it.
13125574Smx205022 	 */
13135574Smx205022 	if (ngep->suspended) {
13145574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13155574Smx205022 		return;
13165574Smx205022 	}
13175574Smx205022 
13185574Smx205022 	/*
13195574Smx205022 	 * Validate the command before bothering with the mutex ...
13205574Smx205022 	 */
13215574Smx205022 	iocp = (struct iocblk *)mp->b_rptr;
13225574Smx205022 	iocp->ioc_error = 0;
13235574Smx205022 	need_privilege = B_TRUE;
13245574Smx205022 	cmd = iocp->ioc_cmd;
13255574Smx205022 
13265574Smx205022 	NGE_DEBUG(("nge_m_ioctl:  cmd 0x%x", cmd));
13275574Smx205022 	switch (cmd) {
13285574Smx205022 	default:
13295574Smx205022 		NGE_LDB(NGE_DBG_BADIOC,
13305574Smx205022 		    ("nge_m_ioctl: unknown cmd 0x%x", cmd));
13315574Smx205022 
13325574Smx205022 		miocnak(wq, mp, 0, EINVAL);
13335574Smx205022 		return;
13345574Smx205022 
13355574Smx205022 	case NGE_MII_READ:
13365574Smx205022 	case NGE_MII_WRITE:
13375574Smx205022 	case NGE_SEE_READ:
13385574Smx205022 	case NGE_SEE_WRITE:
13395574Smx205022 	case NGE_DIAG:
13405574Smx205022 	case NGE_PEEK:
13415574Smx205022 	case NGE_POKE:
13425574Smx205022 	case NGE_PHY_RESET:
13435574Smx205022 	case NGE_SOFT_RESET:
13445574Smx205022 	case NGE_HARD_RESET:
13455574Smx205022 		break;
13465574Smx205022 
13475574Smx205022 	case LB_GET_INFO_SIZE:
13485574Smx205022 	case LB_GET_INFO:
13495574Smx205022 	case LB_GET_MODE:
13505574Smx205022 		need_privilege = B_FALSE;
13515574Smx205022 		break;
13525574Smx205022 	case LB_SET_MODE:
13535574Smx205022 		break;
13545574Smx205022 
13555574Smx205022 	case ND_GET:
13565574Smx205022 		need_privilege = B_FALSE;
13575574Smx205022 		break;
13585574Smx205022 	case ND_SET:
13595574Smx205022 		break;
13605574Smx205022 	}
13615574Smx205022 
13625574Smx205022 	if (need_privilege) {
13635574Smx205022 		/*
13645574Smx205022 		 * Check for specific net_config privilege.
13655574Smx205022 		 */
13665574Smx205022 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
13675574Smx205022 		if (err != 0) {
13685574Smx205022 			NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d",
13695574Smx205022 			    cmd, err));
13705574Smx205022 			miocnak(wq, mp, 0, err);
13715574Smx205022 			return;
13725574Smx205022 		}
13735574Smx205022 	}
13745574Smx205022 
13755574Smx205022 	mutex_enter(ngep->genlock);
13765574Smx205022 
13775574Smx205022 	switch (cmd) {
13785574Smx205022 	default:
13795574Smx205022 		_NOTE(NOTREACHED)
13805574Smx205022 		status = IOC_INVAL;
13815574Smx205022 	break;
13825574Smx205022 
13835574Smx205022 	case NGE_MII_READ:
13845574Smx205022 	case NGE_MII_WRITE:
13855574Smx205022 	case NGE_SEE_READ:
13865574Smx205022 	case NGE_SEE_WRITE:
13875574Smx205022 	case NGE_DIAG:
13885574Smx205022 	case NGE_PEEK:
13895574Smx205022 	case NGE_POKE:
13905574Smx205022 	case NGE_PHY_RESET:
13915574Smx205022 	case NGE_SOFT_RESET:
13925574Smx205022 	case NGE_HARD_RESET:
13935574Smx205022 		status = nge_chip_ioctl(ngep, mp, iocp);
13945574Smx205022 	break;
13955574Smx205022 
13965574Smx205022 	case LB_GET_INFO_SIZE:
13975574Smx205022 	case LB_GET_INFO:
13985574Smx205022 	case LB_GET_MODE:
13995574Smx205022 	case LB_SET_MODE:
14005574Smx205022 		status = nge_loop_ioctl(ngep, mp, iocp);
14015574Smx205022 	break;
14025574Smx205022 
14035574Smx205022 	case ND_GET:
14045574Smx205022 	case ND_SET:
14055574Smx205022 		status = nge_nd_ioctl(ngep, wq, mp, iocp);
14065574Smx205022 	break;
14075574Smx205022 
14085574Smx205022 	}
14095574Smx205022 
14105574Smx205022 	/*
14115574Smx205022 	 * Do we need to reprogram the PHY and/or the MAC?
14125574Smx205022 	 * Do it now, while we still have the mutex.
14135574Smx205022 	 *
14145574Smx205022 	 * Note: update the PHY first, 'cos it controls the
14155574Smx205022 	 * speed/duplex parameters that the MAC code uses.
14165574Smx205022 	 */
14175574Smx205022 
14185574Smx205022 	NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status));
14195574Smx205022 
14205574Smx205022 	switch (status) {
14215574Smx205022 	case IOC_RESTART_REPLY:
14225574Smx205022 	case IOC_RESTART_ACK:
14235574Smx205022 		(*ngep->physops->phys_update)(ngep);
14245574Smx205022 		nge_chip_sync(ngep);
14255574Smx205022 		break;
14265574Smx205022 
14275574Smx205022 	default:
14285574Smx205022 	break;
14295574Smx205022 	}
14305574Smx205022 
14315574Smx205022 	mutex_exit(ngep->genlock);
14325574Smx205022 
14335574Smx205022 	/*
14345574Smx205022 	 * Finally, decide how to reply
14355574Smx205022 	 */
14365574Smx205022 	switch (status) {
14375574Smx205022 
14385574Smx205022 	default:
14395574Smx205022 	case IOC_INVAL:
14405574Smx205022 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
14415574Smx205022 		    EINVAL : iocp->ioc_error);
14425574Smx205022 		break;
14435574Smx205022 
14445574Smx205022 	case IOC_DONE:
14455574Smx205022 		break;
14465574Smx205022 
14475574Smx205022 	case IOC_RESTART_ACK:
14485574Smx205022 	case IOC_ACK:
14495574Smx205022 		miocack(wq, mp, 0, 0);
14505574Smx205022 		break;
14515574Smx205022 
14525574Smx205022 	case IOC_RESTART_REPLY:
14535574Smx205022 	case IOC_REPLY:
14545574Smx205022 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
14555574Smx205022 		    M_IOCACK : M_IOCNAK;
14565574Smx205022 		qreply(wq, mp);
14575574Smx205022 		break;
14585574Smx205022 	}
14595574Smx205022 }
14605574Smx205022 
14615574Smx205022 static void
14625574Smx205022 nge_chip_blank(void *arg, time_t ticks, uint_t count)
14635574Smx205022 {
14645574Smx205022 	_NOTE(ARGUNUSED(arg, ticks, count));
14655574Smx205022 }
14665574Smx205022 
14675574Smx205022 static void
14685574Smx205022 nge_m_resources(void *arg)
14695574Smx205022 {
14705574Smx205022 	nge_t *ngep = arg;
14715574Smx205022 	recv_ring_t *rrp;
14725574Smx205022 	mac_rx_fifo_t mrf;
14735574Smx205022 
14745574Smx205022 	mutex_enter(ngep->genlock);
14755574Smx205022 
14765574Smx205022 	/*
14775574Smx205022 	 * Register Rx rings as resources and save mac
14785574Smx205022 	 * resource id for future reference
14795574Smx205022 	 */
14805574Smx205022 	mrf.mrf_type = MAC_RX_FIFO;
14815574Smx205022 	mrf.mrf_blank = nge_chip_blank;
14825574Smx205022 	mrf.mrf_arg = (void *)ngep;
14835574Smx205022 	mrf.mrf_normal_blank_time = NGE_TICKS_CNT;
14845574Smx205022 	mrf.mrf_normal_pkt_count = NGE_RX_PKT_CNT;
14855574Smx205022 
14865574Smx205022 	rrp = ngep->recv;
14875574Smx205022 	rrp->handle = mac_resource_add(ngep->mh, (mac_resource_t *)&mrf);
14885574Smx205022 	mutex_exit(ngep->genlock);
14895574Smx205022 }
14905574Smx205022 
14915574Smx205022 /* ARGSUSED */
14925574Smx205022 static boolean_t
14935574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
14945574Smx205022 {
14955574Smx205022 	nge_t	*ngep = arg;
14965574Smx205022 	nge_dev_spec_param_t *dev_param_p;
14975574Smx205022 
14985574Smx205022 	dev_param_p = &ngep->dev_spec_param;
14995574Smx205022 
15005574Smx205022 	switch (cap) {
15015574Smx205022 	case MAC_CAPAB_HCKSUM: {
15025574Smx205022 		uint32_t *hcksum_txflags = cap_data;
15035574Smx205022 
15045574Smx205022 		if (dev_param_p->tx_hw_checksum) {
15055574Smx205022 			*hcksum_txflags = dev_param_p->tx_hw_checksum;
15065574Smx205022 		} else
15075574Smx205022 			return (B_FALSE);
15085574Smx205022 		break;
15095574Smx205022 	}
15105574Smx205022 	case MAC_CAPAB_POLL:
15115574Smx205022 		/*
15125574Smx205022 		 * There's nothing for us to fill in, simply returning
15135574Smx205022 		 * B_TRUE, stating that we support polling is sufficient.
15145574Smx205022 		 */
15155574Smx205022 		break;
15165574Smx205022 	default:
15175574Smx205022 		return (B_FALSE);
15185574Smx205022 	}
15195574Smx205022 	return (B_TRUE);
15205574Smx205022 }
15215574Smx205022 
15225574Smx205022 #undef	NGE_DBG
15235574Smx205022 #define	NGE_DBG	NGE_DBG_INIT	/* debug flag for this code	*/
15245574Smx205022 int
15255574Smx205022 nge_restart(nge_t *ngep)
15265574Smx205022 {
15275574Smx205022 	int err = 0;
15285574Smx205022 	err += nge_reset(ngep);
15295574Smx205022 	err += nge_chip_start(ngep);
15305574Smx205022 
15315574Smx205022 	if (err) {
15325574Smx205022 		ngep->nge_mac_state = NGE_MAC_STOPPED;
15335574Smx205022 		return (DDI_FAILURE);
15345574Smx205022 	} else {
15355574Smx205022 		ngep->nge_mac_state = NGE_MAC_STARTED;
15365574Smx205022 		return (DDI_SUCCESS);
15375574Smx205022 	}
15385574Smx205022 }
15395574Smx205022 
15405574Smx205022 void
15415574Smx205022 nge_wake_factotum(nge_t *ngep)
15425574Smx205022 {
15435574Smx205022 	mutex_enter(ngep->softlock);
15445574Smx205022 	if (ngep->factotum_flag == 0) {
15455574Smx205022 		ngep->factotum_flag = 1;
15465574Smx205022 		(void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL);
15475574Smx205022 	}
15485574Smx205022 	mutex_exit(ngep->softlock);
15495574Smx205022 }
15505574Smx205022 
15515574Smx205022 /*
15525574Smx205022  * High-level cyclic handler
15535574Smx205022  *
15545574Smx205022  * This routine schedules a (low-level) softint callback to the
15555574Smx205022  * factotum.
15565574Smx205022  */
15575574Smx205022 
15585574Smx205022 static void
15595574Smx205022 nge_chip_cyclic(void *arg)
15605574Smx205022 {
15615574Smx205022 	nge_t *ngep;
15625574Smx205022 
15635574Smx205022 	ngep = (nge_t *)arg;
15645574Smx205022 
15655574Smx205022 	switch (ngep->nge_chip_state) {
15665574Smx205022 	default:
15675574Smx205022 		return;
15685574Smx205022 
15695574Smx205022 	case NGE_CHIP_RUNNING:
15705574Smx205022 		break;
15715574Smx205022 
15725574Smx205022 	case NGE_CHIP_FAULT:
15735574Smx205022 	case NGE_CHIP_ERROR:
15745574Smx205022 		break;
15755574Smx205022 	}
15765574Smx205022 
15775574Smx205022 	nge_wake_factotum(ngep);
15785574Smx205022 }
15795574Smx205022 
15805574Smx205022 static void
15815574Smx205022 nge_unattach(nge_t *ngep)
15825574Smx205022 {
15835574Smx205022 	send_ring_t *srp;
15845574Smx205022 	buff_ring_t *brp;
15855574Smx205022 
15865574Smx205022 	srp = ngep->send;
15875574Smx205022 	brp = ngep->buff;
15885574Smx205022 	NGE_TRACE(("nge_unattach($%p)", (void *)ngep));
15895574Smx205022 
15905574Smx205022 	/*
15915574Smx205022 	 * Flag that no more activity may be initiated
15925574Smx205022 	 */
15935574Smx205022 	ngep->progress &= ~PROGRESS_READY;
15945574Smx205022 	ngep->nge_mac_state = NGE_MAC_UNATTACH;
15955574Smx205022 
15965574Smx205022 	/*
15975574Smx205022 	 * Quiesce the PHY and MAC (leave it reset but still powered).
15985574Smx205022 	 * Clean up and free all NGE data structures
15995574Smx205022 	 */
16005574Smx205022 	if (ngep->periodic_id != NULL) {
16015574Smx205022 		ddi_periodic_delete(ngep->periodic_id);
16025574Smx205022 		ngep->periodic_id = NULL;
16035574Smx205022 	}
16045574Smx205022 
16055574Smx205022 	if (ngep->progress & PROGRESS_KSTATS)
16065574Smx205022 		nge_fini_kstats(ngep);
16075574Smx205022 
16085574Smx205022 	if (ngep->progress & PROGRESS_NDD)
16095574Smx205022 		nge_nd_cleanup(ngep);
16105574Smx205022 
16115574Smx205022 	if (ngep->progress & PROGRESS_HWINT) {
16125574Smx205022 		mutex_enter(ngep->genlock);
16135574Smx205022 		nge_restore_mac_addr(ngep);
16145574Smx205022 		(void) nge_chip_stop(ngep, B_FALSE);
16155574Smx205022 		mutex_exit(ngep->genlock);
16165574Smx205022 	}
16175574Smx205022 
16185574Smx205022 	if (ngep->progress & PROGRESS_SWINT)
16195574Smx205022 		nge_rem_intrs(ngep);
16205574Smx205022 
16215574Smx205022 	if (ngep->progress & PROGRESS_FACTOTUM)
16225574Smx205022 		(void) ddi_intr_remove_softint(ngep->factotum_hdl);
16235574Smx205022 
16245574Smx205022 	if (ngep->progress & PROGRESS_RESCHED)
16255574Smx205022 		(void) ddi_intr_remove_softint(ngep->resched_hdl);
16265574Smx205022 
16275574Smx205022 	if (ngep->progress & PROGRESS_INTR) {
16285574Smx205022 		mutex_destroy(srp->tx_lock);
16295574Smx205022 		mutex_destroy(srp->tc_lock);
16305574Smx205022 		mutex_destroy(&srp->dmah_lock);
16315574Smx205022 		mutex_destroy(brp->recycle_lock);
16325574Smx205022 
16335574Smx205022 		mutex_destroy(ngep->genlock);
16345574Smx205022 		mutex_destroy(ngep->softlock);
16355574Smx205022 		rw_destroy(ngep->rwlock);
16365574Smx205022 	}
16375574Smx205022 
16385574Smx205022 	if (ngep->progress & PROGRESS_REGS)
16395574Smx205022 		ddi_regs_map_free(&ngep->io_handle);
16405574Smx205022 
16415574Smx205022 	if (ngep->progress & PROGRESS_CFG)
16425574Smx205022 		pci_config_teardown(&ngep->cfg_handle);
16435574Smx205022 
16445574Smx205022 	ddi_remove_minor_node(ngep->devinfo, NULL);
16455574Smx205022 
16465574Smx205022 	kmem_free(ngep, sizeof (*ngep));
16475574Smx205022 }
16485574Smx205022 
16495574Smx205022 static int
16505574Smx205022 nge_resume(dev_info_t *devinfo)
16515574Smx205022 {
16525574Smx205022 	nge_t		*ngep;
16535574Smx205022 	chip_info_t	*infop;
16545574Smx205022 
16555574Smx205022 	ASSERT(devinfo != NULL);
16565574Smx205022 
16575574Smx205022 	ngep = ddi_get_driver_private(devinfo);
16585574Smx205022 	/*
16595574Smx205022 	 * If there are state inconsistancies, this is bad.  Returning
16605574Smx205022 	 * DDI_FAILURE here will eventually cause the machine to panic,
16615574Smx205022 	 * so it is best done here so that there is a possibility of
16625574Smx205022 	 * debugging the problem.
16635574Smx205022 	 */
16645574Smx205022 	if (ngep == NULL)
16655574Smx205022 		cmn_err(CE_PANIC,
16665574Smx205022 		    "nge: ngep returned from ddi_get_driver_private was NULL");
16675574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
16685574Smx205022 
16695574Smx205022 	if (ngep->devinfo != devinfo)
16705574Smx205022 		cmn_err(CE_PANIC,
16715574Smx205022 		    "nge: passed devinfo not the same as saved definfo");
16725574Smx205022 
16735574Smx205022 	ngep->suspended = B_FALSE;
16745574Smx205022 
16755574Smx205022 	/*
16765574Smx205022 	 * Fetch the config space.  Even though we have most of it cached,
16775574Smx205022 	 * some values *might* change across a suspend/resume.
16785574Smx205022 	 */
16795574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
16805574Smx205022 
16815574Smx205022 	/*
16825574Smx205022 	 * Start the controller.  In this case (and probably most GLDv3
16835574Smx205022 	 * devices), it is sufficient to call nge_m_start().
16845574Smx205022 	 */
16855574Smx205022 	if (nge_m_start((void *)ngep) != DDI_SUCCESS) {
16865574Smx205022 		/*
16875574Smx205022 		 * We note the failure, but return success, as the
16885574Smx205022 		 * system is still usable without this controller.
16895574Smx205022 		 */
16905574Smx205022 		cmn_err(CE_WARN, "nge: resume: failed to restart controller");
16915574Smx205022 	}
16925574Smx205022 	return (DDI_SUCCESS);
16935574Smx205022 }
16945574Smx205022 
16955574Smx205022 /*
16965574Smx205022  * attach(9E) -- Attach a device to the system
16975574Smx205022  *
16985574Smx205022  * Called once for each board successfully probed.
16995574Smx205022  */
17005574Smx205022 static int
17015574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
17025574Smx205022 {
17035574Smx205022 	int		err;
17045574Smx205022 	int		i;
17055574Smx205022 	int		instance;
17065574Smx205022 	caddr_t		regs;
17075574Smx205022 	nge_t		*ngep;
17085574Smx205022 	chip_info_t	*infop;
17095574Smx205022 	mac_register_t	*macp;
17105574Smx205022 
17115574Smx205022 	switch (cmd) {
17125574Smx205022 	default:
17135574Smx205022 		return (DDI_FAILURE);
17145574Smx205022 
17155574Smx205022 	case DDI_RESUME:
17165574Smx205022 		return (nge_resume(devinfo));
17175574Smx205022 
17185574Smx205022 	case DDI_ATTACH:
17195574Smx205022 		break;
17205574Smx205022 	}
17215574Smx205022 
17225574Smx205022 	ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP);
17235574Smx205022 	instance = ddi_get_instance(devinfo);
17245574Smx205022 	ddi_set_driver_private(devinfo, ngep);
17255574Smx205022 	ngep->devinfo = devinfo;
17265574Smx205022 
17275574Smx205022 	(void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d",
17285574Smx205022 	    NGE_DRIVER_NAME, instance);
17295574Smx205022 	err = pci_config_setup(devinfo, &ngep->cfg_handle);
17305574Smx205022 	if (err != DDI_SUCCESS) {
17315574Smx205022 		nge_problem(ngep, "nge_attach: pci_config_setup() failed");
17325574Smx205022 		goto attach_fail;
17335574Smx205022 	}
17345574Smx205022 	infop = (chip_info_t *)&ngep->chipinfo;
17355574Smx205022 	nge_chip_cfg_init(ngep, infop, B_FALSE);
17365574Smx205022 	nge_init_dev_spec_param(ngep);
17375574Smx205022 	nge_get_props(ngep);
17385574Smx205022 	ngep->progress |= PROGRESS_CFG;
17395574Smx205022 
17405574Smx205022 	err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER,
17415574Smx205022 	    &regs, 0, 0, &nge_reg_accattr, &ngep->io_handle);
17425574Smx205022 	if (err != DDI_SUCCESS) {
17435574Smx205022 		nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed");
17445574Smx205022 		goto attach_fail;
17455574Smx205022 	}
17465574Smx205022 	ngep->io_regs = regs;
17475574Smx205022 	ngep->progress |= PROGRESS_REGS;
17485574Smx205022 
17495574Smx205022 	err = nge_register_intrs_and_init_locks(ngep);
17505574Smx205022 	if (err != DDI_SUCCESS) {
17515574Smx205022 		nge_problem(ngep, "nge_attach:"
17525574Smx205022 		    " register intrs and init locks failed");
17535574Smx205022 		goto attach_fail;
17545574Smx205022 	}
17555574Smx205022 	nge_init_ring_param_lock(ngep);
17565574Smx205022 	ngep->progress |= PROGRESS_INTR;
17575574Smx205022 
17585574Smx205022 	mutex_enter(ngep->genlock);
17595574Smx205022 
17605574Smx205022 	/*
17615574Smx205022 	 * Initialise link state variables
17625574Smx205022 	 * Stop, reset & reinitialise the chip.
17635574Smx205022 	 * Initialise the (internal) PHY.
17645574Smx205022 	 */
17655574Smx205022 	nge_phys_init(ngep);
17665574Smx205022 	err = nge_chip_reset(ngep);
17675574Smx205022 	if (err != DDI_SUCCESS) {
17685574Smx205022 		nge_problem(ngep, "nge_attach: nge_chip_reset() failed");
17695574Smx205022 		mutex_exit(ngep->genlock);
17705574Smx205022 		goto attach_fail;
17715574Smx205022 	}
17725574Smx205022 	nge_chip_sync(ngep);
17735574Smx205022 
17745574Smx205022 	/*
17755574Smx205022 	 * Now that mutex locks are initialized, enable interrupts.
17765574Smx205022 	 */
17775574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
17785574Smx205022 		/* Call ddi_intr_block_enable() for MSI interrupts */
17795574Smx205022 		(void) ddi_intr_block_enable(ngep->htable,
17805574Smx205022 		    ngep->intr_actual_cnt);
17815574Smx205022 	} else {
17825574Smx205022 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
17835574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
17845574Smx205022 			(void) ddi_intr_enable(ngep->htable[i]);
17855574Smx205022 		}
17865574Smx205022 	}
17875574Smx205022 
17885574Smx205022 	ngep->link_state = LINK_STATE_UNKNOWN;
17895574Smx205022 	ngep->progress |= PROGRESS_HWINT;
17905574Smx205022 
17915574Smx205022 	/*
17925574Smx205022 	 * Register NDD-tweakable parameters
17935574Smx205022 	 */
17945574Smx205022 	if (nge_nd_init(ngep)) {
17955574Smx205022 		nge_problem(ngep, "nge_attach: nge_nd_init() failed");
17965574Smx205022 		mutex_exit(ngep->genlock);
17975574Smx205022 		goto attach_fail;
17985574Smx205022 	}
17995574Smx205022 	ngep->progress |= PROGRESS_NDD;
18005574Smx205022 
18015574Smx205022 	/*
18025574Smx205022 	 * Create & initialise named kstats
18035574Smx205022 	 */
18045574Smx205022 	nge_init_kstats(ngep, instance);
18055574Smx205022 	ngep->progress |= PROGRESS_KSTATS;
18065574Smx205022 
18075574Smx205022 	mutex_exit(ngep->genlock);
18085574Smx205022 
18095574Smx205022 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
18105574Smx205022 		goto attach_fail;
18115574Smx205022 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
18125574Smx205022 	macp->m_driver = ngep;
18135574Smx205022 	macp->m_dip = devinfo;
18145574Smx205022 	macp->m_src_addr = infop->vendor_addr.addr;
18155574Smx205022 	macp->m_callbacks = &nge_m_callbacks;
18165574Smx205022 	macp->m_min_sdu = 0;
18175574Smx205022 	macp->m_max_sdu = ngep->default_mtu;
18185574Smx205022 	/*
18195574Smx205022 	 * Finally, we're ready to register ourselves with the mac
18205574Smx205022 	 * interface; if this succeeds, we're all ready to start()
18215574Smx205022 	 */
18225574Smx205022 	err = mac_register(macp, &ngep->mh);
18235574Smx205022 	mac_free(macp);
18245574Smx205022 	if (err != 0)
18255574Smx205022 		goto attach_fail;
18265574Smx205022 
18275574Smx205022 	/*
18285574Smx205022 	 * Register a periodical handler.
18295574Smx205022 	 * nge_chip_cyclic() is invoked in kernel context.
18305574Smx205022 	 */
18315574Smx205022 	ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep,
18325574Smx205022 	    NGE_CYCLIC_PERIOD, DDI_IPL_0);
18335574Smx205022 
18345574Smx205022 	ngep->progress |= PROGRESS_READY;
18355574Smx205022 	return (DDI_SUCCESS);
18365574Smx205022 
18375574Smx205022 attach_fail:
18385574Smx205022 	nge_unattach(ngep);
18395574Smx205022 	return (DDI_FAILURE);
18405574Smx205022 }
18415574Smx205022 
18425574Smx205022 /*
18435574Smx205022  * detach(9E) -- Detach a device from the system
18445574Smx205022  */
18455574Smx205022 static int
18465574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
18475574Smx205022 {
18485574Smx205022 	int i;
18495574Smx205022 	nge_t *ngep;
18505574Smx205022 	mul_item *p, *nextp;
18515574Smx205022 	buff_ring_t *brp;
18525574Smx205022 
18535574Smx205022 	NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd));
18545574Smx205022 
18555574Smx205022 	ngep = ddi_get_driver_private(devinfo);
18565574Smx205022 	brp = ngep->buff;
18575574Smx205022 
18585574Smx205022 	switch (cmd) {
18595574Smx205022 	default:
18605574Smx205022 		return (DDI_FAILURE);
18615574Smx205022 
18625574Smx205022 	case DDI_SUSPEND:
18635574Smx205022 		/*
18645574Smx205022 		 * Stop the NIC
18655574Smx205022 		 * I suspect that we can actually suspend if the stop
18665574Smx205022 		 * routine returns a failure, as the resume will
18675574Smx205022 		 * effectively fully reset the hardware (i.e. we don't
18685574Smx205022 		 * really save any hardware state).  However, nge_m_stop
18695574Smx205022 		 * doesn't return an error code.
18705574Smx205022 		 * Note: This driver doesn't currently support WOL, but
18715574Smx205022 		 *	should it in the future, it is important to
18725574Smx205022 		 *	make sure the PHY remains powered so that the
18735574Smx205022 		 *	wakeup packet can actually be recieved.
18745574Smx205022 		 */
18755574Smx205022 		nge_m_stop(ngep);
18765574Smx205022 		ngep->suspended = B_TRUE;
18775574Smx205022 		return (DDI_SUCCESS);
18785574Smx205022 
18795574Smx205022 	case DDI_DETACH:
18805574Smx205022 		break;
18815574Smx205022 	}
18825574Smx205022 
18835574Smx205022 	/* Try to wait all the buffer post to upper layer be released */
18845574Smx205022 	for (i = 0; i < 1000; i++) {
18855574Smx205022 		if (brp->rx_hold == 0)
18865574Smx205022 			break;
18875574Smx205022 		drv_usecwait(1000);
18885574Smx205022 	}
18895574Smx205022 
18905574Smx205022 	/* If there is any posted buffer, reject to detach */
18915574Smx205022 	if (brp->rx_hold != 0)
18925574Smx205022 		return (DDI_FAILURE);
18935574Smx205022 
18945574Smx205022 	/* Recycle the multicast table */
18955574Smx205022 	for (p = ngep->pcur_mulist; p != NULL; p = nextp) {
18965574Smx205022 		nextp = p->next;
18975574Smx205022 		kmem_free(p, sizeof (mul_item));
18985574Smx205022 	}
18995574Smx205022 	ngep->pcur_mulist = NULL;
19005574Smx205022 
19015574Smx205022 	/*
19025574Smx205022 	 * Unregister from the GLD subsystem.  This can fail, in
19035574Smx205022 	 * particular if there are DLPI style-2 streams still open -
19045574Smx205022 	 * in which case we just return failure without shutting
19055574Smx205022 	 * down chip operations.
19065574Smx205022 	 */
19075574Smx205022 	if (mac_unregister(ngep->mh) != DDI_SUCCESS)
19085574Smx205022 		return (DDI_FAILURE);
19095574Smx205022 
19105574Smx205022 	/*
19115574Smx205022 	 * All activity stopped, so we can clean up & exit
19125574Smx205022 	 */
19135574Smx205022 	nge_unattach(ngep);
19145574Smx205022 	return (DDI_SUCCESS);
19155574Smx205022 }
19165574Smx205022 
19175574Smx205022 
19185574Smx205022 /*
19195574Smx205022  * ========== Module Loading Data & Entry Points ==========
19205574Smx205022  */
19215574Smx205022 
19225574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach,
19235574Smx205022     nodev, NULL, D_MP, NULL);
19245574Smx205022 
19255574Smx205022 
19265574Smx205022 static struct modldrv nge_modldrv = {
19275574Smx205022 	&mod_driverops,		/* Type of module.  This one is a driver */
19285574Smx205022 	nge_ident,		/* short description */
19295574Smx205022 	&nge_dev_ops		/* driver specific ops */
19305574Smx205022 };
19315574Smx205022 
19325574Smx205022 static struct modlinkage modlinkage = {
19335574Smx205022 	MODREV_1, (void *)&nge_modldrv, NULL
19345574Smx205022 };
19355574Smx205022 
19365574Smx205022 
19375574Smx205022 int
19385574Smx205022 _info(struct modinfo *modinfop)
19395574Smx205022 {
19405574Smx205022 	return (mod_info(&modlinkage, modinfop));
19415574Smx205022 }
19425574Smx205022 
19435574Smx205022 int
19445574Smx205022 _init(void)
19455574Smx205022 {
19465574Smx205022 	int status;
19475574Smx205022 
19485574Smx205022 	mac_init_ops(&nge_dev_ops, "nge");
19495574Smx205022 	status = mod_install(&modlinkage);
19505574Smx205022 	if (status != DDI_SUCCESS)
19515574Smx205022 		mac_fini_ops(&nge_dev_ops);
19525574Smx205022 	else
19535574Smx205022 		mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL);
19545574Smx205022 
19555574Smx205022 	return (status);
19565574Smx205022 }
19575574Smx205022 
19585574Smx205022 int
19595574Smx205022 _fini(void)
19605574Smx205022 {
19615574Smx205022 	int status;
19625574Smx205022 
19635574Smx205022 	status = mod_remove(&modlinkage);
19645574Smx205022 	if (status == DDI_SUCCESS) {
19655574Smx205022 		mac_fini_ops(&nge_dev_ops);
19665574Smx205022 		mutex_destroy(nge_log_mutex);
19675574Smx205022 	}
19685574Smx205022 
19695574Smx205022 	return (status);
19705574Smx205022 }
19715574Smx205022 
19725574Smx205022 /*
19735574Smx205022  * ============ Init MSI/Fixed/SoftInterrupt routines ==============
19745574Smx205022  */
19755574Smx205022 
19765574Smx205022 /*
19775574Smx205022  * Register interrupts and initialize each mutex and condition variables
19785574Smx205022  */
19795574Smx205022 
19805574Smx205022 static int
19815574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep)
19825574Smx205022 {
19835574Smx205022 	int		err;
19845574Smx205022 	int		intr_types;
19855574Smx205022 	uint_t		soft_prip;
19865574Smx205022 	nge_msi_mask	msi_mask;
19875574Smx205022 	nge_msi_map0_vec map0_vec;
19885574Smx205022 	nge_msi_map1_vec map1_vec;
19895574Smx205022 
19905574Smx205022 	/*
19915574Smx205022 	 * Add the softint handlers:
19925574Smx205022 	 *
19935574Smx205022 	 * Both of these handlers are used to avoid restrictions on the
19945574Smx205022 	 * context and/or mutexes required for some operations.  In
19955574Smx205022 	 * particular, the hardware interrupt handler and its subfunctions
19965574Smx205022 	 * can detect a number of conditions that we don't want to handle
19975574Smx205022 	 * in that context or with that set of mutexes held.  So, these
19985574Smx205022 	 * softints are triggered instead:
19995574Smx205022 	 *
20005574Smx205022 	 * the <resched> softint is triggered if if we have previously
20015574Smx205022 	 * had to refuse to send a packet because of resource shortage
20025574Smx205022 	 * (we've run out of transmit buffers), but the send completion
20035574Smx205022 	 * interrupt handler has now detected that more buffers have
20045574Smx205022 	 * become available.  Its only purpose is to call gld_sched()
20055574Smx205022 	 * to retry the pending transmits (we're not allowed to hold
20065574Smx205022 	 * driver-defined mutexes across gld_sched()).
20075574Smx205022 	 *
20085574Smx205022 	 * the <factotum> is triggered if the h/w interrupt handler
20095574Smx205022 	 * sees the <link state changed> or <error> bits in the status
20105574Smx205022 	 * block.  It's also triggered periodically to poll the link
20115574Smx205022 	 * state, just in case we aren't getting link status change
20125574Smx205022 	 * interrupts ...
20135574Smx205022 	 */
20145574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl,
20155574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep);
20165574Smx205022 	if (err != DDI_SUCCESS) {
20175574Smx205022 		nge_problem(ngep,
20185574Smx205022 		    "nge_attach: add nge_reschedule softintr failed");
20195574Smx205022 
20205574Smx205022 		return (DDI_FAILURE);
20215574Smx205022 	}
20225574Smx205022 	ngep->progress |= PROGRESS_RESCHED;
20235574Smx205022 	err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl,
20245574Smx205022 	    DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep);
20255574Smx205022 	if (err != DDI_SUCCESS) {
20265574Smx205022 		nge_problem(ngep,
20275574Smx205022 		    "nge_attach: add nge_chip_factotum softintr failed!");
20285574Smx205022 
20295574Smx205022 		return (DDI_FAILURE);
20305574Smx205022 	}
20315574Smx205022 	if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip)
20325574Smx205022 	    != DDI_SUCCESS) {
20335574Smx205022 		nge_problem(ngep, "nge_attach: get softintr priority failed\n");
20345574Smx205022 
20355574Smx205022 		return (DDI_FAILURE);
20365574Smx205022 	}
20375574Smx205022 	ngep->soft_pri = soft_prip;
20385574Smx205022 
20395574Smx205022 	ngep->progress |= PROGRESS_FACTOTUM;
20405574Smx205022 	/* Get supported interrupt types */
20415574Smx205022 	if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types)
20425574Smx205022 	    != DDI_SUCCESS) {
20435574Smx205022 		nge_error(ngep, "ddi_intr_get_supported_types failed\n");
20445574Smx205022 
20455574Smx205022 		return (DDI_FAILURE);
20465574Smx205022 	}
20475574Smx205022 
20485574Smx205022 	NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x",
20495574Smx205022 	    intr_types));
20505574Smx205022 
20515574Smx205022 	if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) {
20525574Smx205022 
20535574Smx205022 		/* MSI Configurations for mcp55 chipset */
20545574Smx205022 		if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 ||
20555574Smx205022 		    ngep->chipinfo.device == DEVICE_ID_MCP55_372) {
20565574Smx205022 
20575574Smx205022 
20585574Smx205022 			/* Enable the 8 vectors */
20595574Smx205022 			msi_mask.msi_mask_val =
20605574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MASK);
20615574Smx205022 			msi_mask.msi_msk_bits.vec0 = NGE_SET;
20625574Smx205022 			msi_mask.msi_msk_bits.vec1 = NGE_SET;
20635574Smx205022 			msi_mask.msi_msk_bits.vec2 = NGE_SET;
20645574Smx205022 			msi_mask.msi_msk_bits.vec3 = NGE_SET;
20655574Smx205022 			msi_mask.msi_msk_bits.vec4 = NGE_SET;
20665574Smx205022 			msi_mask.msi_msk_bits.vec5 = NGE_SET;
20675574Smx205022 			msi_mask.msi_msk_bits.vec6 = NGE_SET;
20685574Smx205022 			msi_mask.msi_msk_bits.vec7 = NGE_SET;
20695574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MASK,
20705574Smx205022 			    msi_mask.msi_mask_val);
20715574Smx205022 
20725574Smx205022 			/*
20735574Smx205022 			 * Remapping the MSI MAP0 and MAP1. MCP55
20745574Smx205022 			 * is default mapping all the interrupt to 0 vector.
20755574Smx205022 			 * Software needs to remapping this.
20765574Smx205022 			 * This mapping is same as CK804.
20775574Smx205022 			 */
20785574Smx205022 			map0_vec.msi_map0_val =
20795574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP0);
20805574Smx205022 			map1_vec.msi_map1_val =
20815574Smx205022 			    nge_reg_get32(ngep, NGE_MSI_MAP1);
20825574Smx205022 			map0_vec.vecs_bits.reint_vec = 0;
20835574Smx205022 			map0_vec.vecs_bits.rcint_vec = 0;
20845574Smx205022 			map0_vec.vecs_bits.miss_vec = 3;
20855574Smx205022 			map0_vec.vecs_bits.teint_vec = 5;
20865574Smx205022 			map0_vec.vecs_bits.tcint_vec = 5;
20875574Smx205022 			map0_vec.vecs_bits.stint_vec = 2;
20885574Smx205022 			map0_vec.vecs_bits.mint_vec = 6;
20895574Smx205022 			map0_vec.vecs_bits.rfint_vec = 0;
20905574Smx205022 			map1_vec.vecs_bits.tfint_vec = 5;
20915574Smx205022 			map1_vec.vecs_bits.feint_vec = 6;
20925574Smx205022 			map1_vec.vecs_bits.resv8_11 = 3;
20935574Smx205022 			map1_vec.vecs_bits.resv12_15 = 1;
20945574Smx205022 			map1_vec.vecs_bits.resv16_19 = 0;
20955574Smx205022 			map1_vec.vecs_bits.resv20_23 = 7;
20965574Smx205022 			map1_vec.vecs_bits.resv24_31 = 0xff;
20975574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP0,
20985574Smx205022 			    map0_vec.msi_map0_val);
20995574Smx205022 			nge_reg_put32(ngep, NGE_MSI_MAP1,
21005574Smx205022 			    map1_vec.msi_map1_val);
21015574Smx205022 		}
21025574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
21035574Smx205022 			NGE_DEBUG(("MSI registration failed, "
21045574Smx205022 			    "trying FIXED interrupt type\n"));
21055574Smx205022 		} else {
21065574Smx205022 			nge_log(ngep, "Using MSI interrupt type\n");
21075574Smx205022 
21085574Smx205022 			ngep->intr_type = DDI_INTR_TYPE_MSI;
21095574Smx205022 			ngep->progress |= PROGRESS_SWINT;
21105574Smx205022 		}
21115574Smx205022 	}
21125574Smx205022 
21135574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT) &&
21145574Smx205022 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
21155574Smx205022 		if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
21165574Smx205022 			nge_error(ngep, "FIXED interrupt "
21175574Smx205022 			    "registration failed\n");
21185574Smx205022 
21195574Smx205022 			return (DDI_FAILURE);
21205574Smx205022 		}
21215574Smx205022 
21225574Smx205022 		nge_log(ngep, "Using FIXED interrupt type\n");
21235574Smx205022 
21245574Smx205022 		ngep->intr_type = DDI_INTR_TYPE_FIXED;
21255574Smx205022 		ngep->progress |= PROGRESS_SWINT;
21265574Smx205022 	}
21275574Smx205022 
21285574Smx205022 
21295574Smx205022 	if (!(ngep->progress & PROGRESS_SWINT)) {
21305574Smx205022 		nge_error(ngep, "No interrupts registered\n");
21315574Smx205022 
21325574Smx205022 		return (DDI_FAILURE);
21335574Smx205022 	}
21345574Smx205022 	mutex_init(ngep->genlock, NULL, MUTEX_DRIVER,
21355574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
21365574Smx205022 	mutex_init(ngep->softlock, NULL, MUTEX_DRIVER,
21375574Smx205022 	    DDI_INTR_PRI(ngep->soft_pri));
21385574Smx205022 	rw_init(ngep->rwlock, NULL, RW_DRIVER,
21395574Smx205022 	    DDI_INTR_PRI(ngep->intr_pri));
21405574Smx205022 
21415574Smx205022 	return (DDI_SUCCESS);
21425574Smx205022 }
21435574Smx205022 
21445574Smx205022 /*
21455574Smx205022  * nge_add_intrs:
21465574Smx205022  *
21475574Smx205022  * Register FIXED or MSI interrupts.
21485574Smx205022  */
21495574Smx205022 static int
21505574Smx205022 nge_add_intrs(nge_t *ngep, int	intr_type)
21515574Smx205022 {
21525574Smx205022 	dev_info_t	*dip = ngep->devinfo;
21535574Smx205022 	int		avail, actual, intr_size, count = 0;
21545574Smx205022 	int		i, flag, ret;
21555574Smx205022 
21565574Smx205022 	NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type));
21575574Smx205022 
21585574Smx205022 	/* Get number of interrupts */
21595574Smx205022 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
21605574Smx205022 	if ((ret != DDI_SUCCESS) || (count == 0)) {
21615574Smx205022 		nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, "
21625574Smx205022 		    "count: %d", ret, count);
21635574Smx205022 
21645574Smx205022 		return (DDI_FAILURE);
21655574Smx205022 	}
21665574Smx205022 
21675574Smx205022 	/* Get number of available interrupts */
21685574Smx205022 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
21695574Smx205022 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
21705574Smx205022 		nge_error(ngep, "ddi_intr_get_navail() failure, "
21715574Smx205022 		    "ret: %d, avail: %d\n", ret, avail);
21725574Smx205022 
21735574Smx205022 		return (DDI_FAILURE);
21745574Smx205022 	}
21755574Smx205022 
21765574Smx205022 	if (avail < count) {
21775574Smx205022 		NGE_DEBUG(("nitrs() returned %d, navail returned %d\n",
21785574Smx205022 		    count, avail));
21795574Smx205022 	}
21805574Smx205022 	flag = DDI_INTR_ALLOC_NORMAL;
21815574Smx205022 
21825574Smx205022 	/* Allocate an array of interrupt handles */
21835574Smx205022 	intr_size = count * sizeof (ddi_intr_handle_t);
21845574Smx205022 	ngep->htable = kmem_alloc(intr_size, KM_SLEEP);
21855574Smx205022 
21865574Smx205022 	/* Call ddi_intr_alloc() */
21875574Smx205022 	ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0,
21885574Smx205022 	    count, &actual, flag);
21895574Smx205022 
21905574Smx205022 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
21915574Smx205022 		nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret);
21925574Smx205022 
21935574Smx205022 		kmem_free(ngep->htable, intr_size);
21945574Smx205022 		return (DDI_FAILURE);
21955574Smx205022 	}
21965574Smx205022 
21975574Smx205022 	if (actual < count) {
21985574Smx205022 		NGE_DEBUG(("Requested: %d, Received: %d\n",
21995574Smx205022 		    count, actual));
22005574Smx205022 	}
22015574Smx205022 
22025574Smx205022 	ngep->intr_actual_cnt = actual;
22035574Smx205022 	ngep->intr_req_cnt = count;
22045574Smx205022 
22055574Smx205022 	/*
22065574Smx205022 	 * Get priority for first msi, assume remaining are all the same
22075574Smx205022 	 */
22085574Smx205022 	if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) !=
22095574Smx205022 	    DDI_SUCCESS) {
22105574Smx205022 		nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret);
22115574Smx205022 
22125574Smx205022 		/* Free already allocated intr */
22135574Smx205022 		for (i = 0; i < actual; i++) {
22145574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
22155574Smx205022 		}
22165574Smx205022 
22175574Smx205022 		kmem_free(ngep->htable, intr_size);
22185574Smx205022 
22195574Smx205022 		return (DDI_FAILURE);
22205574Smx205022 	}
22215574Smx205022 	/* Test for high level mutex */
22225574Smx205022 	if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) {
22235574Smx205022 		nge_error(ngep, "nge_add_intrs:"
22245574Smx205022 		    "Hi level interrupt not supported");
22255574Smx205022 
22265574Smx205022 		for (i = 0; i < actual; i++)
22275574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
22285574Smx205022 
22295574Smx205022 		kmem_free(ngep->htable, intr_size);
22305574Smx205022 
22315574Smx205022 		return (DDI_FAILURE);
22325574Smx205022 	}
22335574Smx205022 
22345574Smx205022 
22355574Smx205022 	/* Call ddi_intr_add_handler() */
22365574Smx205022 	for (i = 0; i < actual; i++) {
22375574Smx205022 		if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr,
22385574Smx205022 		    (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
22395574Smx205022 			nge_error(ngep, "ddi_intr_add_handler() "
22405574Smx205022 			    "failed %d\n", ret);
22415574Smx205022 
22425574Smx205022 			/* Free already allocated intr */
22435574Smx205022 			for (i = 0; i < actual; i++) {
22445574Smx205022 				(void) ddi_intr_free(ngep->htable[i]);
22455574Smx205022 			}
22465574Smx205022 
22475574Smx205022 			kmem_free(ngep->htable, intr_size);
22485574Smx205022 
22495574Smx205022 			return (DDI_FAILURE);
22505574Smx205022 		}
22515574Smx205022 	}
22525574Smx205022 
22535574Smx205022 	if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap))
22545574Smx205022 	    != DDI_SUCCESS) {
22555574Smx205022 		nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret);
22565574Smx205022 
22575574Smx205022 		for (i = 0; i < actual; i++) {
22585574Smx205022 			(void) ddi_intr_remove_handler(ngep->htable[i]);
22595574Smx205022 			(void) ddi_intr_free(ngep->htable[i]);
22605574Smx205022 		}
22615574Smx205022 
22625574Smx205022 		kmem_free(ngep->htable, intr_size);
22635574Smx205022 
22645574Smx205022 		return (DDI_FAILURE);
22655574Smx205022 	}
22665574Smx205022 
22675574Smx205022 	return (DDI_SUCCESS);
22685574Smx205022 }
22695574Smx205022 
22705574Smx205022 /*
22715574Smx205022  * nge_rem_intrs:
22725574Smx205022  *
22735574Smx205022  * Unregister FIXED or MSI interrupts
22745574Smx205022  */
22755574Smx205022 static void
22765574Smx205022 nge_rem_intrs(nge_t *ngep)
22775574Smx205022 {
22785574Smx205022 	int	i;
22795574Smx205022 
22805574Smx205022 	NGE_DEBUG(("nge_rem_intrs\n"));
22815574Smx205022 
22825574Smx205022 	/* Disable all interrupts */
22835574Smx205022 	if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) {
22845574Smx205022 		/* Call ddi_intr_block_disable() */
22855574Smx205022 		(void) ddi_intr_block_disable(ngep->htable,
22865574Smx205022 		    ngep->intr_actual_cnt);
22875574Smx205022 	} else {
22885574Smx205022 		for (i = 0; i < ngep->intr_actual_cnt; i++) {
22895574Smx205022 			(void) ddi_intr_disable(ngep->htable[i]);
22905574Smx205022 		}
22915574Smx205022 	}
22925574Smx205022 
22935574Smx205022 	/* Call ddi_intr_remove_handler() */
22945574Smx205022 	for (i = 0; i < ngep->intr_actual_cnt; i++) {
22955574Smx205022 		(void) ddi_intr_remove_handler(ngep->htable[i]);
22965574Smx205022 		(void) ddi_intr_free(ngep->htable[i]);
22975574Smx205022 	}
22985574Smx205022 
22995574Smx205022 	kmem_free(ngep->htable,
23005574Smx205022 	    ngep->intr_req_cnt * sizeof (ddi_intr_handle_t));
23015574Smx205022 }
2302