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