16f3e57acSmx205022 /* 247693af9Smx205022 * CDDL HEADER START 347693af9Smx205022 * 447693af9Smx205022 * The contents of this file are subject to the terms of the 547693af9Smx205022 * Common Development and Distribution License (the "License"). 647693af9Smx205022 * You may not use this file except in compliance with the License. 747693af9Smx205022 * 847693af9Smx205022 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 947693af9Smx205022 * or http://www.opensolaris.org/os/licensing. 1047693af9Smx205022 * See the License for the specific language governing permissions 1147693af9Smx205022 * and limitations under the License. 1247693af9Smx205022 * 1347693af9Smx205022 * When distributing Covered Code, include this CDDL HEADER in each 1447693af9Smx205022 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1547693af9Smx205022 * If applicable, add the following below this CDDL HEADER, with the 1647693af9Smx205022 * fields enclosed by brackets "[]" replaced with your own identifying 1747693af9Smx205022 * information: Portions Copyright [yyyy] [name of copyright owner] 1847693af9Smx205022 * 1947693af9Smx205022 * CDDL HEADER END 206f3e57acSmx205022 */ 216f3e57acSmx205022 226f3e57acSmx205022 /* 23*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2447693af9Smx205022 * Use is subject to license terms. 256f3e57acSmx205022 */ 266f3e57acSmx205022 276f3e57acSmx205022 286f3e57acSmx205022 #include "nge.h" 296f3e57acSmx205022 306f3e57acSmx205022 /* 316f3e57acSmx205022 * Describes the chip's DMA engine 326f3e57acSmx205022 */ 336f3e57acSmx205022 346f3e57acSmx205022 static ddi_dma_attr_t hot_dma_attr = { 356f3e57acSmx205022 DMA_ATTR_V0, /* dma_attr version */ 366f3e57acSmx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 376f3e57acSmx205022 0x000000FFFFFFFFFFull, /* dma_attr_addr_hi */ 386f3e57acSmx205022 0x000000007FFFFFFFull, /* dma_attr_count_max */ 396f3e57acSmx205022 0x0000000000000010ull, /* dma_attr_align */ 406f3e57acSmx205022 0x00000FFF, /* dma_attr_burstsizes */ 416f3e57acSmx205022 0x00000001, /* dma_attr_minxfer */ 426f3e57acSmx205022 0x000000000000FFFFull, /* dma_attr_maxxfer */ 436f3e57acSmx205022 0x000000FFFFFFFFFFull, /* dma_attr_seg */ 446f3e57acSmx205022 1, /* dma_attr_sgllen */ 456f3e57acSmx205022 0x00000001, /* dma_attr_granular */ 466f3e57acSmx205022 0 476f3e57acSmx205022 }; 486f3e57acSmx205022 496f3e57acSmx205022 static ddi_dma_attr_t hot_tx_dma_attr = { 506f3e57acSmx205022 DMA_ATTR_V0, /* dma_attr version */ 516f3e57acSmx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 526f3e57acSmx205022 0x000000FFFFFFFFFFull, /* dma_attr_addr_hi */ 536f3e57acSmx205022 0x0000000000003FFFull, /* dma_attr_count_max */ 546f3e57acSmx205022 0x0000000000000010ull, /* dma_attr_align */ 556f3e57acSmx205022 0x00000FFF, /* dma_attr_burstsizes */ 566f3e57acSmx205022 0x00000001, /* dma_attr_minxfer */ 576f3e57acSmx205022 0x0000000000003FFFull, /* dma_attr_maxxfer */ 586f3e57acSmx205022 0x000000FFFFFFFFFFull, /* dma_attr_seg */ 596f3e57acSmx205022 NGE_MAX_COOKIES, /* dma_attr_sgllen */ 606f3e57acSmx205022 1, /* dma_attr_granular */ 616f3e57acSmx205022 0 626f3e57acSmx205022 }; 636f3e57acSmx205022 646f3e57acSmx205022 static ddi_dma_attr_t sum_dma_attr = { 656f3e57acSmx205022 DMA_ATTR_V0, /* dma_attr version */ 666f3e57acSmx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 676f3e57acSmx205022 0x00000000FFFFFFFFull, /* dma_attr_addr_hi */ 686f3e57acSmx205022 0x000000007FFFFFFFull, /* dma_attr_count_max */ 696f3e57acSmx205022 0x0000000000000010ull, /* dma_attr_align */ 706f3e57acSmx205022 0x00000FFF, /* dma_attr_burstsizes */ 716f3e57acSmx205022 0x00000001, /* dma_attr_minxfer */ 726f3e57acSmx205022 0x000000000000FFFFull, /* dma_attr_maxxfer */ 736f3e57acSmx205022 0x00000000FFFFFFFFull, /* dma_attr_seg */ 746f3e57acSmx205022 1, /* dma_attr_sgllen */ 756f3e57acSmx205022 0x00000001, /* dma_attr_granular */ 766f3e57acSmx205022 0 776f3e57acSmx205022 }; 786f3e57acSmx205022 796f3e57acSmx205022 static ddi_dma_attr_t sum_tx_dma_attr = { 806f3e57acSmx205022 DMA_ATTR_V0, /* dma_attr version */ 816f3e57acSmx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 826f3e57acSmx205022 0x00000000FFFFFFFFull, /* dma_attr_addr_hi */ 836f3e57acSmx205022 0x0000000000003FFFull, /* dma_attr_count_max */ 846f3e57acSmx205022 0x0000000000000010ull, /* dma_attr_align */ 856f3e57acSmx205022 0x00000FFF, /* dma_attr_burstsizes */ 866f3e57acSmx205022 0x00000001, /* dma_attr_minxfer */ 876f3e57acSmx205022 0x0000000000003FFFull, /* dma_attr_maxxfer */ 886f3e57acSmx205022 0x00000000FFFFFFFFull, /* dma_attr_seg */ 896f3e57acSmx205022 NGE_MAX_COOKIES, /* dma_attr_sgllen */ 906f3e57acSmx205022 1, /* dma_attr_granular */ 916f3e57acSmx205022 0 926f3e57acSmx205022 }; 936f3e57acSmx205022 946f3e57acSmx205022 /* 956f3e57acSmx205022 * DMA access attributes for data. 966f3e57acSmx205022 */ 976f3e57acSmx205022 ddi_device_acc_attr_t nge_data_accattr = { 986f3e57acSmx205022 DDI_DEVICE_ATTR_V0, 996f3e57acSmx205022 DDI_STRUCTURE_LE_ACC, 1006f3e57acSmx205022 DDI_STRICTORDER_ACC, 1016f3e57acSmx205022 DDI_DEFAULT_ACC 1026f3e57acSmx205022 }; 1036f3e57acSmx205022 1046f3e57acSmx205022 /* 1056f3e57acSmx205022 * DMA access attributes for descriptors. 1066f3e57acSmx205022 */ 1076f3e57acSmx205022 static ddi_device_acc_attr_t nge_desc_accattr = { 1086f3e57acSmx205022 DDI_DEVICE_ATTR_V0, 1096f3e57acSmx205022 DDI_STRUCTURE_LE_ACC, 1106f3e57acSmx205022 DDI_STRICTORDER_ACC, 1116f3e57acSmx205022 DDI_DEFAULT_ACC 1126f3e57acSmx205022 }; 1136f3e57acSmx205022 1146f3e57acSmx205022 /* 1156f3e57acSmx205022 * PIO access attributes for registers 1166f3e57acSmx205022 */ 1176f3e57acSmx205022 static ddi_device_acc_attr_t nge_reg_accattr = { 1186f3e57acSmx205022 DDI_DEVICE_ATTR_V0, 1196f3e57acSmx205022 DDI_STRUCTURE_LE_ACC, 1206f3e57acSmx205022 DDI_STRICTORDER_ACC, 1216f3e57acSmx205022 DDI_DEFAULT_ACC 1226f3e57acSmx205022 }; 1236f3e57acSmx205022 1246f3e57acSmx205022 /* 1256f3e57acSmx205022 * NIC DESC MODE 2 1266f3e57acSmx205022 */ 1276f3e57acSmx205022 1286f3e57acSmx205022 static const nge_desc_attr_t nge_sum_desc = { 1296f3e57acSmx205022 1306f3e57acSmx205022 sizeof (sum_rx_bd), 1316f3e57acSmx205022 sizeof (sum_tx_bd), 1326f3e57acSmx205022 &sum_dma_attr, 1336f3e57acSmx205022 &sum_tx_dma_attr, 1346f3e57acSmx205022 nge_sum_rxd_fill, 1356f3e57acSmx205022 nge_sum_rxd_check, 1366f3e57acSmx205022 nge_sum_txd_fill, 1376f3e57acSmx205022 nge_sum_txd_check, 1386f3e57acSmx205022 }; 1396f3e57acSmx205022 1406f3e57acSmx205022 /* 1416f3e57acSmx205022 * NIC DESC MODE 3 1426f3e57acSmx205022 */ 1436f3e57acSmx205022 1446f3e57acSmx205022 static const nge_desc_attr_t nge_hot_desc = { 1456f3e57acSmx205022 1466f3e57acSmx205022 sizeof (hot_rx_bd), 1476f3e57acSmx205022 sizeof (hot_tx_bd), 1486f3e57acSmx205022 &hot_dma_attr, 1496f3e57acSmx205022 &hot_tx_dma_attr, 1506f3e57acSmx205022 nge_hot_rxd_fill, 1516f3e57acSmx205022 nge_hot_rxd_check, 1526f3e57acSmx205022 nge_hot_txd_fill, 1536f3e57acSmx205022 nge_hot_txd_check, 1546f3e57acSmx205022 }; 1556f3e57acSmx205022 1564045d941Ssowmini static char nge_ident[] = "nVidia 1Gb Ethernet"; 1576f3e57acSmx205022 static char clsize_propname[] = "cache-line-size"; 1586f3e57acSmx205022 static char latency_propname[] = "latency-timer"; 1596f3e57acSmx205022 static char debug_propname[] = "nge-debug-flags"; 16002d51d0dSjj146644 static char intr_moderation[] = "intr-moderation"; 1616f3e57acSmx205022 static char rx_data_hw[] = "rx-data-hw"; 1626f3e57acSmx205022 static char rx_prd_lw[] = "rx-prd-lw"; 1636f3e57acSmx205022 static char rx_prd_hw[] = "rx-prd-hw"; 1646f3e57acSmx205022 static char sw_intr_intv[] = "sw-intr-intvl"; 1656f3e57acSmx205022 static char nge_desc_mode[] = "desc-mode"; 1666f3e57acSmx205022 static char default_mtu[] = "default_mtu"; 1676f3e57acSmx205022 static char low_memory_mode[] = "minimal-memory-usage"; 1686f3e57acSmx205022 extern kmutex_t nge_log_mutex[1]; 1696f3e57acSmx205022 1706f3e57acSmx205022 static int nge_m_start(void *); 1716f3e57acSmx205022 static void nge_m_stop(void *); 1726f3e57acSmx205022 static int nge_m_promisc(void *, boolean_t); 1736f3e57acSmx205022 static int nge_m_multicst(void *, boolean_t, const uint8_t *); 1746f3e57acSmx205022 static int nge_m_unicst(void *, const uint8_t *); 1756f3e57acSmx205022 static void nge_m_ioctl(void *, queue_t *, mblk_t *); 1766f3e57acSmx205022 static boolean_t nge_m_getcapab(void *, mac_capab_t, void *); 1775a3d0718Smx205022 static int nge_m_setprop(void *, const char *, mac_prop_id_t, 1785a3d0718Smx205022 uint_t, const void *); 1795a3d0718Smx205022 static int nge_m_getprop(void *, const char *, mac_prop_id_t, 180*0dc2366fSVenugopal Iyer uint_t, void *); 181*0dc2366fSVenugopal Iyer static void nge_m_propinfo(void *, const char *, mac_prop_id_t, 182*0dc2366fSVenugopal Iyer mac_prop_info_handle_t); 1835a3d0718Smx205022 static int nge_set_priv_prop(nge_t *, const char *, uint_t, 1845a3d0718Smx205022 const void *); 1855a3d0718Smx205022 static int nge_get_priv_prop(nge_t *, const char *, uint_t, 186*0dc2366fSVenugopal Iyer void *); 1876f3e57acSmx205022 1885a3d0718Smx205022 #define NGE_M_CALLBACK_FLAGS\ 189*0dc2366fSVenugopal Iyer (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | \ 190*0dc2366fSVenugopal Iyer MC_PROPINFO) 1916f3e57acSmx205022 1926f3e57acSmx205022 static mac_callbacks_t nge_m_callbacks = { 1936f3e57acSmx205022 NGE_M_CALLBACK_FLAGS, 1946f3e57acSmx205022 nge_m_stat, 1956f3e57acSmx205022 nge_m_start, 1966f3e57acSmx205022 nge_m_stop, 1976f3e57acSmx205022 nge_m_promisc, 1986f3e57acSmx205022 nge_m_multicst, 1996f3e57acSmx205022 nge_m_unicst, 2006f3e57acSmx205022 nge_m_tx, 201*0dc2366fSVenugopal Iyer NULL, 2026f3e57acSmx205022 nge_m_ioctl, 2035a3d0718Smx205022 nge_m_getcapab, 2045a3d0718Smx205022 NULL, 2055a3d0718Smx205022 NULL, 2065a3d0718Smx205022 nge_m_setprop, 207*0dc2366fSVenugopal Iyer nge_m_getprop, 208*0dc2366fSVenugopal Iyer nge_m_propinfo 2096f3e57acSmx205022 }; 2106f3e57acSmx205022 211*0dc2366fSVenugopal Iyer char *nge_priv_props[] = { 212*0dc2366fSVenugopal Iyer "_tx_bcopy_threshold", 213*0dc2366fSVenugopal Iyer "_rx_bcopy_threshold", 214*0dc2366fSVenugopal Iyer "_recv_max_packet", 215*0dc2366fSVenugopal Iyer "_poll_quiet_time", 216*0dc2366fSVenugopal Iyer "_poll_busy_time", 217*0dc2366fSVenugopal Iyer "_rx_intr_hwater", 218*0dc2366fSVenugopal Iyer "_rx_intr_lwater", 219*0dc2366fSVenugopal Iyer NULL 2204045d941Ssowmini }; 2214045d941Ssowmini 2226f3e57acSmx205022 static int nge_add_intrs(nge_t *, int); 2236f3e57acSmx205022 static void nge_rem_intrs(nge_t *); 2246f3e57acSmx205022 static int nge_register_intrs_and_init_locks(nge_t *); 2256f3e57acSmx205022 2266f3e57acSmx205022 /* 2276f3e57acSmx205022 * NGE MSI tunable: 2286f3e57acSmx205022 */ 2296f3e57acSmx205022 boolean_t nge_enable_msi = B_FALSE; 2306f3e57acSmx205022 2316f3e57acSmx205022 static enum ioc_reply 2326f3e57acSmx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode) 2336f3e57acSmx205022 { 2346f3e57acSmx205022 /* 2356f3e57acSmx205022 * If the mode isn't being changed, there's nothing to do ... 2366f3e57acSmx205022 */ 2376f3e57acSmx205022 if (mode == ngep->param_loop_mode) 2386f3e57acSmx205022 return (IOC_ACK); 2396f3e57acSmx205022 2406f3e57acSmx205022 /* 2416f3e57acSmx205022 * Validate the requested mode and prepare a suitable message 2426f3e57acSmx205022 * to explain the link down/up cycle that the change will 2436f3e57acSmx205022 * probably induce ... 2446f3e57acSmx205022 */ 2456f3e57acSmx205022 switch (mode) { 2466f3e57acSmx205022 default: 2476f3e57acSmx205022 return (IOC_INVAL); 2486f3e57acSmx205022 2496f3e57acSmx205022 case NGE_LOOP_NONE: 2506f3e57acSmx205022 case NGE_LOOP_EXTERNAL_100: 2516f3e57acSmx205022 case NGE_LOOP_EXTERNAL_10: 2526f3e57acSmx205022 case NGE_LOOP_INTERNAL_PHY: 2536f3e57acSmx205022 break; 2546f3e57acSmx205022 } 2556f3e57acSmx205022 2566f3e57acSmx205022 /* 2576f3e57acSmx205022 * All OK; tell the caller to reprogram 2586f3e57acSmx205022 * the PHY and/or MAC for the new mode ... 2596f3e57acSmx205022 */ 2606f3e57acSmx205022 ngep->param_loop_mode = mode; 2616f3e57acSmx205022 return (IOC_RESTART_ACK); 2626f3e57acSmx205022 } 2636f3e57acSmx205022 2646f3e57acSmx205022 #undef NGE_DBG 2656f3e57acSmx205022 #define NGE_DBG NGE_DBG_INIT 2666f3e57acSmx205022 2676f3e57acSmx205022 /* 2686f3e57acSmx205022 * Utility routine to carve a slice off a chunk of allocated memory, 2696f3e57acSmx205022 * updating the chunk descriptor accordingly. The size of the slice 2706f3e57acSmx205022 * is given by the product of the <qty> and <size> parameters. 2716f3e57acSmx205022 */ 2726f3e57acSmx205022 void 2736f3e57acSmx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 2746f3e57acSmx205022 uint32_t qty, uint32_t size) 2756f3e57acSmx205022 { 2766f3e57acSmx205022 size_t totsize; 2776f3e57acSmx205022 2786f3e57acSmx205022 totsize = qty*size; 2796f3e57acSmx205022 ASSERT(size > 0); 2806f3e57acSmx205022 ASSERT(totsize <= chunk->alength); 2816f3e57acSmx205022 2826f3e57acSmx205022 *slice = *chunk; 2836f3e57acSmx205022 slice->nslots = qty; 2846f3e57acSmx205022 slice->size = size; 2856f3e57acSmx205022 slice->alength = totsize; 2866f3e57acSmx205022 2876f3e57acSmx205022 chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 2886f3e57acSmx205022 chunk->alength -= totsize; 2896f3e57acSmx205022 chunk->offset += totsize; 2906f3e57acSmx205022 chunk->cookie.dmac_laddress += totsize; 2916f3e57acSmx205022 chunk->cookie.dmac_size -= totsize; 2926f3e57acSmx205022 } 2936f3e57acSmx205022 2946f3e57acSmx205022 /* 2956f3e57acSmx205022 * Allocate an area of memory and a DMA handle for accessing it 2966f3e57acSmx205022 */ 2976f3e57acSmx205022 int 2986f3e57acSmx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p, 2996f3e57acSmx205022 uint_t dma_flags, dma_area_t *dma_p) 3006f3e57acSmx205022 { 3016f3e57acSmx205022 int err; 3026f3e57acSmx205022 caddr_t va; 3036f3e57acSmx205022 3046f3e57acSmx205022 NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 3056f3e57acSmx205022 (void *)ngep, memsize, attr_p, dma_flags, dma_p)); 3066f3e57acSmx205022 /* 3076f3e57acSmx205022 * Allocate handle 3086f3e57acSmx205022 */ 3096f3e57acSmx205022 err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr, 3106f3e57acSmx205022 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 3116f3e57acSmx205022 if (err != DDI_SUCCESS) 3126f3e57acSmx205022 goto fail; 3136f3e57acSmx205022 3146f3e57acSmx205022 /* 3156f3e57acSmx205022 * Allocate memory 3166f3e57acSmx205022 */ 3176f3e57acSmx205022 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 3186f3e57acSmx205022 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 3196f3e57acSmx205022 DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl); 3206f3e57acSmx205022 if (err != DDI_SUCCESS) 3216f3e57acSmx205022 goto fail; 3226f3e57acSmx205022 3236f3e57acSmx205022 /* 3246f3e57acSmx205022 * Bind the two together 3256f3e57acSmx205022 */ 3266f3e57acSmx205022 dma_p->mem_va = va; 3276f3e57acSmx205022 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 3286f3e57acSmx205022 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 3296f3e57acSmx205022 &dma_p->cookie, &dma_p->ncookies); 3306f3e57acSmx205022 3316f3e57acSmx205022 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 3326f3e57acSmx205022 goto fail; 3336f3e57acSmx205022 3346f3e57acSmx205022 dma_p->nslots = ~0U; 3356f3e57acSmx205022 dma_p->size = ~0U; 3366f3e57acSmx205022 dma_p->offset = 0; 3376f3e57acSmx205022 3386f3e57acSmx205022 return (DDI_SUCCESS); 3396f3e57acSmx205022 3406f3e57acSmx205022 fail: 3416f3e57acSmx205022 nge_free_dma_mem(dma_p); 3426f3e57acSmx205022 NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!")); 3436f3e57acSmx205022 3446f3e57acSmx205022 return (DDI_FAILURE); 3456f3e57acSmx205022 } 3466f3e57acSmx205022 3476f3e57acSmx205022 /* 3486f3e57acSmx205022 * Free one allocated area of DMAable memory 3496f3e57acSmx205022 */ 3506f3e57acSmx205022 void 3516f3e57acSmx205022 nge_free_dma_mem(dma_area_t *dma_p) 3526f3e57acSmx205022 { 3536f3e57acSmx205022 if (dma_p->dma_hdl != NULL) { 3546f3e57acSmx205022 if (dma_p->ncookies) { 3556f3e57acSmx205022 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 3566f3e57acSmx205022 dma_p->ncookies = 0; 3576f3e57acSmx205022 } 3586f3e57acSmx205022 } 3596f3e57acSmx205022 if (dma_p->acc_hdl != NULL) { 3606f3e57acSmx205022 ddi_dma_mem_free(&dma_p->acc_hdl); 3616f3e57acSmx205022 dma_p->acc_hdl = NULL; 3626f3e57acSmx205022 } 3636f3e57acSmx205022 if (dma_p->dma_hdl != NULL) { 3646f3e57acSmx205022 ddi_dma_free_handle(&dma_p->dma_hdl); 3656f3e57acSmx205022 dma_p->dma_hdl = NULL; 3666f3e57acSmx205022 } 3676f3e57acSmx205022 } 3686f3e57acSmx205022 3696f3e57acSmx205022 #define ALLOC_TX_BUF 0x1 3706f3e57acSmx205022 #define ALLOC_TX_DESC 0x2 3716f3e57acSmx205022 #define ALLOC_RX_DESC 0x4 3726f3e57acSmx205022 3736f3e57acSmx205022 int 3746f3e57acSmx205022 nge_alloc_bufs(nge_t *ngep) 3756f3e57acSmx205022 { 3766f3e57acSmx205022 int err; 3776f3e57acSmx205022 int split; 3786f3e57acSmx205022 int progress; 3796f3e57acSmx205022 size_t txbuffsize; 3806f3e57acSmx205022 size_t rxdescsize; 3816f3e57acSmx205022 size_t txdescsize; 3826f3e57acSmx205022 3836f3e57acSmx205022 txbuffsize = ngep->tx_desc * ngep->buf_size; 3846f3e57acSmx205022 rxdescsize = ngep->rx_desc; 3856f3e57acSmx205022 txdescsize = ngep->tx_desc; 3866f3e57acSmx205022 rxdescsize *= ngep->desc_attr.rxd_size; 3876f3e57acSmx205022 txdescsize *= ngep->desc_attr.txd_size; 3886f3e57acSmx205022 progress = 0; 3896f3e57acSmx205022 3906f3e57acSmx205022 NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep)); 3916f3e57acSmx205022 /* 3926f3e57acSmx205022 * Allocate memory & handles for TX buffers 3936f3e57acSmx205022 */ 3946f3e57acSmx205022 ASSERT((txbuffsize % ngep->nge_split) == 0); 3956f3e57acSmx205022 for (split = 0; split < ngep->nge_split; ++split) { 3966f3e57acSmx205022 err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split, 3976f3e57acSmx205022 &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE, 3986f3e57acSmx205022 &ngep->send->buf[split]); 3996f3e57acSmx205022 if (err != DDI_SUCCESS) 4006f3e57acSmx205022 goto fail; 4016f3e57acSmx205022 } 4026f3e57acSmx205022 4036f3e57acSmx205022 progress |= ALLOC_TX_BUF; 4046f3e57acSmx205022 4056f3e57acSmx205022 /* 4066f3e57acSmx205022 * Allocate memory & handles for receive return rings and 4076f3e57acSmx205022 * buffer (producer) descriptor rings 4086f3e57acSmx205022 */ 4096f3e57acSmx205022 err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr, 4106f3e57acSmx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc); 4116f3e57acSmx205022 if (err != DDI_SUCCESS) 4126f3e57acSmx205022 goto fail; 4136f3e57acSmx205022 progress |= ALLOC_RX_DESC; 4146f3e57acSmx205022 4156f3e57acSmx205022 /* 4166f3e57acSmx205022 * Allocate memory & handles for TX descriptor rings, 4176f3e57acSmx205022 */ 4186f3e57acSmx205022 err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr, 4196f3e57acSmx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc); 4206f3e57acSmx205022 if (err != DDI_SUCCESS) 4216f3e57acSmx205022 goto fail; 4226f3e57acSmx205022 return (DDI_SUCCESS); 4236f3e57acSmx205022 4246f3e57acSmx205022 fail: 4256f3e57acSmx205022 if (progress & ALLOC_RX_DESC) 4266f3e57acSmx205022 nge_free_dma_mem(&ngep->recv->desc); 4276f3e57acSmx205022 if (progress & ALLOC_TX_BUF) { 4286f3e57acSmx205022 for (split = 0; split < ngep->nge_split; ++split) 4296f3e57acSmx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4306f3e57acSmx205022 } 4316f3e57acSmx205022 4326f3e57acSmx205022 return (DDI_FAILURE); 4336f3e57acSmx205022 } 4346f3e57acSmx205022 4356f3e57acSmx205022 /* 4366f3e57acSmx205022 * This routine frees the transmit and receive buffers and descriptors. 4376f3e57acSmx205022 * Make sure the chip is stopped before calling it! 4386f3e57acSmx205022 */ 4396f3e57acSmx205022 void 4406f3e57acSmx205022 nge_free_bufs(nge_t *ngep) 4416f3e57acSmx205022 { 4426f3e57acSmx205022 int split; 4436f3e57acSmx205022 4446f3e57acSmx205022 NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep)); 4456f3e57acSmx205022 4466f3e57acSmx205022 nge_free_dma_mem(&ngep->recv->desc); 4476f3e57acSmx205022 nge_free_dma_mem(&ngep->send->desc); 4486f3e57acSmx205022 4496f3e57acSmx205022 for (split = 0; split < ngep->nge_split; ++split) 4506f3e57acSmx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4516f3e57acSmx205022 } 4526f3e57acSmx205022 4536f3e57acSmx205022 /* 4546f3e57acSmx205022 * Clean up initialisation done above before the memory is freed 4556f3e57acSmx205022 */ 4566f3e57acSmx205022 static void 4576f3e57acSmx205022 nge_fini_send_ring(nge_t *ngep) 4586f3e57acSmx205022 { 4596f3e57acSmx205022 uint32_t slot; 4606f3e57acSmx205022 size_t dmah_num; 4616f3e57acSmx205022 send_ring_t *srp; 4626f3e57acSmx205022 sw_tx_sbd_t *ssbdp; 4636f3e57acSmx205022 4646f3e57acSmx205022 srp = ngep->send; 4656f3e57acSmx205022 ssbdp = srp->sw_sbds; 4666f3e57acSmx205022 4676f3e57acSmx205022 NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep)); 4686f3e57acSmx205022 4696f3e57acSmx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 4706f3e57acSmx205022 4716f3e57acSmx205022 for (slot = 0; slot < dmah_num; ++slot) { 4726f3e57acSmx205022 if (srp->dmahndl[slot].hndl) { 4736f3e57acSmx205022 (void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl); 4746f3e57acSmx205022 ddi_dma_free_handle(&srp->dmahndl[slot].hndl); 4756f3e57acSmx205022 srp->dmahndl[slot].hndl = NULL; 4766f3e57acSmx205022 srp->dmahndl[slot].next = NULL; 4776f3e57acSmx205022 } 4786f3e57acSmx205022 } 4796f3e57acSmx205022 4806f3e57acSmx205022 srp->dmah_free.head = NULL; 4816f3e57acSmx205022 srp->dmah_free.tail = NULL; 4826f3e57acSmx205022 4836f3e57acSmx205022 kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp)); 4846f3e57acSmx205022 4856f3e57acSmx205022 } 4866f3e57acSmx205022 4876f3e57acSmx205022 /* 4886f3e57acSmx205022 * Initialise the specified Send Ring, using the information in the 4896f3e57acSmx205022 * <dma_area> descriptors that it contains to set up all the other 4906f3e57acSmx205022 * fields. This routine should be called only once for each ring. 4916f3e57acSmx205022 */ 4926f3e57acSmx205022 static int 4936f3e57acSmx205022 nge_init_send_ring(nge_t *ngep) 4946f3e57acSmx205022 { 4956f3e57acSmx205022 size_t dmah_num; 4966f3e57acSmx205022 uint32_t nslots; 4976f3e57acSmx205022 uint32_t err; 4986f3e57acSmx205022 uint32_t slot; 4996f3e57acSmx205022 uint32_t split; 5006f3e57acSmx205022 send_ring_t *srp; 5016f3e57acSmx205022 sw_tx_sbd_t *ssbdp; 5026f3e57acSmx205022 dma_area_t desc; 5036f3e57acSmx205022 dma_area_t pbuf; 5046f3e57acSmx205022 5056f3e57acSmx205022 srp = ngep->send; 5066f3e57acSmx205022 srp->desc.nslots = ngep->tx_desc; 5076f3e57acSmx205022 nslots = srp->desc.nslots; 5086f3e57acSmx205022 5096f3e57acSmx205022 NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep)); 5106f3e57acSmx205022 /* 5116f3e57acSmx205022 * Other one-off initialisation of per-ring data 5126f3e57acSmx205022 */ 5136f3e57acSmx205022 srp->ngep = ngep; 5146f3e57acSmx205022 5156f3e57acSmx205022 /* 5166f3e57acSmx205022 * Allocate the array of s/w Send Buffer Descriptors 5176f3e57acSmx205022 */ 5186f3e57acSmx205022 ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 5196f3e57acSmx205022 srp->sw_sbds = ssbdp; 5206f3e57acSmx205022 5216f3e57acSmx205022 /* 5226f3e57acSmx205022 * Now initialise each array element once and for all 5236f3e57acSmx205022 */ 5246f3e57acSmx205022 desc = srp->desc; 5256f3e57acSmx205022 for (split = 0; split < ngep->nge_split; ++split) { 5266f3e57acSmx205022 pbuf = srp->buf[split]; 5276f3e57acSmx205022 for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) { 5286f3e57acSmx205022 nge_slice_chunk(&ssbdp->desc, &desc, 1, 5296f3e57acSmx205022 ngep->desc_attr.txd_size); 5306f3e57acSmx205022 nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1, 5316f3e57acSmx205022 ngep->buf_size); 5326f3e57acSmx205022 } 5336f3e57acSmx205022 ASSERT(pbuf.alength == 0); 5346f3e57acSmx205022 } 5356f3e57acSmx205022 ASSERT(desc.alength == 0); 5366f3e57acSmx205022 5376f3e57acSmx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5386f3e57acSmx205022 5396f3e57acSmx205022 /* preallocate dma handles for tx buffer */ 5406f3e57acSmx205022 for (slot = 0; slot < dmah_num; ++slot) { 5416f3e57acSmx205022 5426f3e57acSmx205022 err = ddi_dma_alloc_handle(ngep->devinfo, 5436f3e57acSmx205022 ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT, 5446f3e57acSmx205022 NULL, &srp->dmahndl[slot].hndl); 5456f3e57acSmx205022 5466f3e57acSmx205022 if (err != DDI_SUCCESS) { 5476f3e57acSmx205022 nge_fini_send_ring(ngep); 5486f3e57acSmx205022 nge_error(ngep, 5496f3e57acSmx205022 "nge_init_send_ring: alloc dma handle fails"); 5506f3e57acSmx205022 return (DDI_FAILURE); 5516f3e57acSmx205022 } 5526f3e57acSmx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5536f3e57acSmx205022 } 5546f3e57acSmx205022 5556f3e57acSmx205022 srp->dmah_free.head = srp->dmahndl; 5566f3e57acSmx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5576f3e57acSmx205022 srp->dmah_free.tail->next = NULL; 5586f3e57acSmx205022 5596f3e57acSmx205022 return (DDI_SUCCESS); 5606f3e57acSmx205022 } 5616f3e57acSmx205022 5626f3e57acSmx205022 /* 5636f3e57acSmx205022 * Intialize the tx recycle pointer and tx sending pointer of tx ring 5646f3e57acSmx205022 * and set the type of tx's data descriptor by default. 5656f3e57acSmx205022 */ 5666f3e57acSmx205022 static void 5676f3e57acSmx205022 nge_reinit_send_ring(nge_t *ngep) 5686f3e57acSmx205022 { 5696f3e57acSmx205022 size_t dmah_num; 5706f3e57acSmx205022 uint32_t slot; 5716f3e57acSmx205022 send_ring_t *srp; 5726f3e57acSmx205022 sw_tx_sbd_t *ssbdp; 5736f3e57acSmx205022 5746f3e57acSmx205022 srp = ngep->send; 5756f3e57acSmx205022 5766f3e57acSmx205022 /* 5776f3e57acSmx205022 * Reinitialise control variables ... 5786f3e57acSmx205022 */ 5796f3e57acSmx205022 5806f3e57acSmx205022 srp->tx_hwmark = NGE_DESC_MIN; 5816f3e57acSmx205022 srp->tx_lwmark = NGE_DESC_MIN; 5826f3e57acSmx205022 5836f3e57acSmx205022 srp->tx_next = 0; 5846f3e57acSmx205022 srp->tx_free = srp->desc.nslots; 5856f3e57acSmx205022 srp->tc_next = 0; 5866f3e57acSmx205022 5876f3e57acSmx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5886f3e57acSmx205022 5896f3e57acSmx205022 for (slot = 0; slot - dmah_num != 0; ++slot) 5906f3e57acSmx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5916f3e57acSmx205022 5926f3e57acSmx205022 srp->dmah_free.head = srp->dmahndl; 5936f3e57acSmx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5946f3e57acSmx205022 srp->dmah_free.tail->next = NULL; 5956f3e57acSmx205022 5966f3e57acSmx205022 /* 5976f3e57acSmx205022 * Zero and sync all the h/w Send Buffer Descriptors 5986f3e57acSmx205022 */ 5996f3e57acSmx205022 for (slot = 0; slot < srp->desc.nslots; ++slot) { 6006f3e57acSmx205022 ssbdp = &srp->sw_sbds[slot]; 6016f3e57acSmx205022 ssbdp->flags = HOST_OWN; 6026f3e57acSmx205022 } 6036f3e57acSmx205022 6046f3e57acSmx205022 DMA_ZERO(srp->desc); 6056f3e57acSmx205022 DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 6066f3e57acSmx205022 } 6076f3e57acSmx205022 6086f3e57acSmx205022 /* 6096f3e57acSmx205022 * Initialize the slot number of rx's ring 6106f3e57acSmx205022 */ 6116f3e57acSmx205022 static void 6126f3e57acSmx205022 nge_init_recv_ring(nge_t *ngep) 6136f3e57acSmx205022 { 6146f3e57acSmx205022 recv_ring_t *rrp; 6156f3e57acSmx205022 6166f3e57acSmx205022 rrp = ngep->recv; 6176f3e57acSmx205022 rrp->desc.nslots = ngep->rx_desc; 6186f3e57acSmx205022 rrp->ngep = ngep; 6196f3e57acSmx205022 } 6206f3e57acSmx205022 6216f3e57acSmx205022 /* 6226f3e57acSmx205022 * Intialize the rx recycle pointer and rx sending pointer of rx ring 6236f3e57acSmx205022 */ 6246f3e57acSmx205022 static void 6256f3e57acSmx205022 nge_reinit_recv_ring(nge_t *ngep) 6266f3e57acSmx205022 { 6276f3e57acSmx205022 recv_ring_t *rrp; 6286f3e57acSmx205022 6296f3e57acSmx205022 rrp = ngep->recv; 6306f3e57acSmx205022 6316f3e57acSmx205022 /* 6326f3e57acSmx205022 * Reinitialise control variables ... 6336f3e57acSmx205022 */ 6346f3e57acSmx205022 rrp->prod_index = 0; 6356f3e57acSmx205022 /* 6366f3e57acSmx205022 * Zero and sync all the h/w Send Buffer Descriptors 6376f3e57acSmx205022 */ 6386f3e57acSmx205022 DMA_ZERO(rrp->desc); 6396f3e57acSmx205022 DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV); 6406f3e57acSmx205022 } 6416f3e57acSmx205022 6426f3e57acSmx205022 /* 6436f3e57acSmx205022 * Clean up initialisation done above before the memory is freed 6446f3e57acSmx205022 */ 6456f3e57acSmx205022 static void 6466f3e57acSmx205022 nge_fini_buff_ring(nge_t *ngep) 6476f3e57acSmx205022 { 6486f3e57acSmx205022 uint32_t i; 6496f3e57acSmx205022 buff_ring_t *brp; 6506f3e57acSmx205022 dma_area_t *bufp; 6516f3e57acSmx205022 sw_rx_sbd_t *bsbdp; 6526f3e57acSmx205022 6536f3e57acSmx205022 brp = ngep->buff; 6546f3e57acSmx205022 bsbdp = brp->sw_rbds; 6556f3e57acSmx205022 6566f3e57acSmx205022 NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep)); 6576f3e57acSmx205022 6586f3e57acSmx205022 mutex_enter(brp->recycle_lock); 6596f3e57acSmx205022 brp->buf_sign++; 6606f3e57acSmx205022 mutex_exit(brp->recycle_lock); 6616f3e57acSmx205022 for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) { 6626f3e57acSmx205022 if (bsbdp->bufp) { 6636f3e57acSmx205022 if (bsbdp->bufp->mp) 6646f3e57acSmx205022 freemsg(bsbdp->bufp->mp); 6656f3e57acSmx205022 nge_free_dma_mem(bsbdp->bufp); 6666f3e57acSmx205022 kmem_free(bsbdp->bufp, sizeof (dma_area_t)); 6676f3e57acSmx205022 bsbdp->bufp = NULL; 6686f3e57acSmx205022 } 6696f3e57acSmx205022 } 6706f3e57acSmx205022 while (brp->free_list != NULL) { 6716f3e57acSmx205022 bufp = brp->free_list; 6726f3e57acSmx205022 brp->free_list = bufp->next; 6736f3e57acSmx205022 bufp->next = NULL; 6746f3e57acSmx205022 if (bufp->mp) 6756f3e57acSmx205022 freemsg(bufp->mp); 6766f3e57acSmx205022 nge_free_dma_mem(bufp); 6776f3e57acSmx205022 kmem_free(bufp, sizeof (dma_area_t)); 6786f3e57acSmx205022 } 6796f3e57acSmx205022 while (brp->recycle_list != NULL) { 6806f3e57acSmx205022 bufp = brp->recycle_list; 6816f3e57acSmx205022 brp->recycle_list = bufp->next; 6826f3e57acSmx205022 bufp->next = NULL; 6836f3e57acSmx205022 if (bufp->mp) 6846f3e57acSmx205022 freemsg(bufp->mp); 6856f3e57acSmx205022 nge_free_dma_mem(bufp); 6866f3e57acSmx205022 kmem_free(bufp, sizeof (dma_area_t)); 6876f3e57acSmx205022 } 6886f3e57acSmx205022 6896f3e57acSmx205022 6906f3e57acSmx205022 kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp))); 6916f3e57acSmx205022 brp->sw_rbds = NULL; 6926f3e57acSmx205022 } 6936f3e57acSmx205022 6946f3e57acSmx205022 /* 6956f3e57acSmx205022 * Intialize the Rx's data ring and free ring 6966f3e57acSmx205022 */ 6976f3e57acSmx205022 static int 6986f3e57acSmx205022 nge_init_buff_ring(nge_t *ngep) 6996f3e57acSmx205022 { 7006f3e57acSmx205022 uint32_t err; 7016f3e57acSmx205022 uint32_t slot; 7026f3e57acSmx205022 uint32_t nslots_buff; 7036f3e57acSmx205022 uint32_t nslots_recv; 7046f3e57acSmx205022 buff_ring_t *brp; 7056f3e57acSmx205022 recv_ring_t *rrp; 7066f3e57acSmx205022 dma_area_t desc; 7076f3e57acSmx205022 dma_area_t *bufp; 7086f3e57acSmx205022 sw_rx_sbd_t *bsbdp; 7096f3e57acSmx205022 7106f3e57acSmx205022 rrp = ngep->recv; 7116f3e57acSmx205022 brp = ngep->buff; 7126f3e57acSmx205022 brp->nslots = ngep->rx_buf; 7136f3e57acSmx205022 brp->rx_bcopy = B_FALSE; 7146f3e57acSmx205022 nslots_recv = rrp->desc.nslots; 7156f3e57acSmx205022 nslots_buff = brp->nslots; 7166f3e57acSmx205022 brp->ngep = ngep; 7176f3e57acSmx205022 7186f3e57acSmx205022 NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep)); 7196f3e57acSmx205022 7206f3e57acSmx205022 /* 7216f3e57acSmx205022 * Allocate the array of s/w Recv Buffer Descriptors 7226f3e57acSmx205022 */ 7236f3e57acSmx205022 bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP); 7246f3e57acSmx205022 brp->sw_rbds = bsbdp; 7256f3e57acSmx205022 brp->free_list = NULL; 7266f3e57acSmx205022 brp->recycle_list = NULL; 7276f3e57acSmx205022 for (slot = 0; slot < nslots_buff; ++slot) { 7286f3e57acSmx205022 bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP); 7296f3e57acSmx205022 err = nge_alloc_dma_mem(ngep, (ngep->buf_size 7306f3e57acSmx205022 + NGE_HEADROOM), 7316f3e57acSmx205022 &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp); 7326f3e57acSmx205022 if (err != DDI_SUCCESS) { 7336f3e57acSmx205022 kmem_free(bufp, sizeof (dma_area_t)); 7346f3e57acSmx205022 return (DDI_FAILURE); 7356f3e57acSmx205022 } 7366f3e57acSmx205022 7376f3e57acSmx205022 bufp->alength -= NGE_HEADROOM; 7386f3e57acSmx205022 bufp->offset += NGE_HEADROOM; 7396f3e57acSmx205022 bufp->private = (caddr_t)ngep; 7406f3e57acSmx205022 bufp->rx_recycle.free_func = nge_recv_recycle; 7416f3e57acSmx205022 bufp->rx_recycle.free_arg = (caddr_t)bufp; 7426f3e57acSmx205022 bufp->signature = brp->buf_sign; 7436f3e57acSmx205022 bufp->rx_delivered = B_FALSE; 7446f3e57acSmx205022 bufp->mp = desballoc(DMA_VPTR(*bufp), 7456f3e57acSmx205022 ngep->buf_size + NGE_HEADROOM, 7466f3e57acSmx205022 0, &bufp->rx_recycle); 7476f3e57acSmx205022 7486f3e57acSmx205022 if (bufp->mp == NULL) { 7496f3e57acSmx205022 return (DDI_FAILURE); 7506f3e57acSmx205022 } 7516f3e57acSmx205022 bufp->next = brp->free_list; 7526f3e57acSmx205022 brp->free_list = bufp; 7536f3e57acSmx205022 } 7546f3e57acSmx205022 7556f3e57acSmx205022 /* 7566f3e57acSmx205022 * Now initialise each array element once and for all 7576f3e57acSmx205022 */ 7586f3e57acSmx205022 desc = rrp->desc; 7596f3e57acSmx205022 for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) { 7606f3e57acSmx205022 nge_slice_chunk(&bsbdp->desc, &desc, 1, 7616f3e57acSmx205022 ngep->desc_attr.rxd_size); 7626f3e57acSmx205022 bufp = brp->free_list; 7636f3e57acSmx205022 brp->free_list = bufp->next; 7646f3e57acSmx205022 bsbdp->bufp = bufp; 7656f3e57acSmx205022 bsbdp->flags = CONTROLER_OWN; 7666f3e57acSmx205022 bufp->next = NULL; 7676f3e57acSmx205022 } 7686f3e57acSmx205022 7696f3e57acSmx205022 ASSERT(desc.alength == 0); 7706f3e57acSmx205022 return (DDI_SUCCESS); 7716f3e57acSmx205022 } 7726f3e57acSmx205022 7736f3e57acSmx205022 /* 7746f3e57acSmx205022 * Fill the host address of data in rx' descriptor 7756f3e57acSmx205022 * and initialize free pointers of rx free ring 7766f3e57acSmx205022 */ 7776f3e57acSmx205022 static int 7786f3e57acSmx205022 nge_reinit_buff_ring(nge_t *ngep) 7796f3e57acSmx205022 { 7806f3e57acSmx205022 uint32_t slot; 7816f3e57acSmx205022 uint32_t nslots_recv; 7826f3e57acSmx205022 buff_ring_t *brp; 7836f3e57acSmx205022 recv_ring_t *rrp; 7846f3e57acSmx205022 sw_rx_sbd_t *bsbdp; 7856f3e57acSmx205022 void *hw_bd_p; 7866f3e57acSmx205022 7876f3e57acSmx205022 brp = ngep->buff; 7886f3e57acSmx205022 rrp = ngep->recv; 7896f3e57acSmx205022 bsbdp = brp->sw_rbds; 7906f3e57acSmx205022 nslots_recv = rrp->desc.nslots; 7916f3e57acSmx205022 for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) { 7926f3e57acSmx205022 hw_bd_p = DMA_VPTR(bsbdp->desc); 7936f3e57acSmx205022 /* 7946f3e57acSmx205022 * There is a scenario: When the traffic of small tcp 7956f3e57acSmx205022 * packet is heavy, suspending the tcp traffic will 7966f3e57acSmx205022 * cause the preallocated buffers for rx not to be 7976f3e57acSmx205022 * released in time by tcp taffic and cause rx's buffer 7986f3e57acSmx205022 * pointers not to be refilled in time. 7996f3e57acSmx205022 * 8006f3e57acSmx205022 * At this point, if we reinitialize the driver, the bufp 8016f3e57acSmx205022 * pointer for rx's traffic will be NULL. 8026f3e57acSmx205022 * So the result of the reinitializion fails. 8036f3e57acSmx205022 */ 8046f3e57acSmx205022 if (bsbdp->bufp == NULL) 8056f3e57acSmx205022 return (DDI_FAILURE); 8066f3e57acSmx205022 8076f3e57acSmx205022 ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie, 8086f3e57acSmx205022 bsbdp->bufp->alength); 8096f3e57acSmx205022 } 8106f3e57acSmx205022 return (DDI_SUCCESS); 8116f3e57acSmx205022 } 8126f3e57acSmx205022 8136f3e57acSmx205022 static void 8146f3e57acSmx205022 nge_init_ring_param_lock(nge_t *ngep) 8156f3e57acSmx205022 { 8166f3e57acSmx205022 buff_ring_t *brp; 8176f3e57acSmx205022 send_ring_t *srp; 8186f3e57acSmx205022 8196f3e57acSmx205022 srp = ngep->send; 8206f3e57acSmx205022 brp = ngep->buff; 8216f3e57acSmx205022 8226f3e57acSmx205022 /* Init the locks for send ring */ 8236f3e57acSmx205022 mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 8246f3e57acSmx205022 DDI_INTR_PRI(ngep->intr_pri)); 8256f3e57acSmx205022 mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 8266f3e57acSmx205022 DDI_INTR_PRI(ngep->intr_pri)); 8276f3e57acSmx205022 mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER, 8286f3e57acSmx205022 DDI_INTR_PRI(ngep->intr_pri)); 8296f3e57acSmx205022 8306f3e57acSmx205022 /* Init parameters of buffer ring */ 8316f3e57acSmx205022 brp->free_list = NULL; 8326f3e57acSmx205022 brp->recycle_list = NULL; 8336f3e57acSmx205022 brp->rx_hold = 0; 8346f3e57acSmx205022 brp->buf_sign = 0; 8356f3e57acSmx205022 8366f3e57acSmx205022 /* Init recycle list lock */ 8376f3e57acSmx205022 mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER, 8386f3e57acSmx205022 DDI_INTR_PRI(ngep->intr_pri)); 8396f3e57acSmx205022 } 8406f3e57acSmx205022 8416f3e57acSmx205022 int 8426f3e57acSmx205022 nge_init_rings(nge_t *ngep) 8436f3e57acSmx205022 { 8446f3e57acSmx205022 uint32_t err; 8456f3e57acSmx205022 8466f3e57acSmx205022 err = nge_init_send_ring(ngep); 8476f3e57acSmx205022 if (err != DDI_SUCCESS) { 8486f3e57acSmx205022 return (err); 8496f3e57acSmx205022 } 8506f3e57acSmx205022 nge_init_recv_ring(ngep); 8516f3e57acSmx205022 8526f3e57acSmx205022 err = nge_init_buff_ring(ngep); 8536f3e57acSmx205022 if (err != DDI_SUCCESS) { 8546f3e57acSmx205022 nge_fini_send_ring(ngep); 8556f3e57acSmx205022 return (DDI_FAILURE); 8566f3e57acSmx205022 } 8576f3e57acSmx205022 8586f3e57acSmx205022 return (err); 8596f3e57acSmx205022 } 8606f3e57acSmx205022 8616f3e57acSmx205022 static int 8626f3e57acSmx205022 nge_reinit_ring(nge_t *ngep) 8636f3e57acSmx205022 { 8646f3e57acSmx205022 int err; 8656f3e57acSmx205022 8666f3e57acSmx205022 nge_reinit_recv_ring(ngep); 8676f3e57acSmx205022 nge_reinit_send_ring(ngep); 8686f3e57acSmx205022 err = nge_reinit_buff_ring(ngep); 8696f3e57acSmx205022 return (err); 8706f3e57acSmx205022 } 8716f3e57acSmx205022 8726f3e57acSmx205022 8736f3e57acSmx205022 void 8746f3e57acSmx205022 nge_fini_rings(nge_t *ngep) 8756f3e57acSmx205022 { 8766f3e57acSmx205022 /* 8776f3e57acSmx205022 * For receive ring, nothing need to be finished. 8786f3e57acSmx205022 * So only finish buffer ring and send ring here. 8796f3e57acSmx205022 */ 8806f3e57acSmx205022 nge_fini_buff_ring(ngep); 8816f3e57acSmx205022 nge_fini_send_ring(ngep); 8826f3e57acSmx205022 } 8836f3e57acSmx205022 8846f3e57acSmx205022 /* 8856f3e57acSmx205022 * Loopback ioctl code 8866f3e57acSmx205022 */ 8876f3e57acSmx205022 8886f3e57acSmx205022 static lb_property_t loopmodes[] = { 8896f3e57acSmx205022 { normal, "normal", NGE_LOOP_NONE }, 8906f3e57acSmx205022 { external, "100Mbps", NGE_LOOP_EXTERNAL_100 }, 8916f3e57acSmx205022 { external, "10Mbps", NGE_LOOP_EXTERNAL_10 }, 8926f3e57acSmx205022 { internal, "PHY", NGE_LOOP_INTERNAL_PHY }, 8936f3e57acSmx205022 }; 8946f3e57acSmx205022 8956f3e57acSmx205022 enum ioc_reply 8966f3e57acSmx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp) 8976f3e57acSmx205022 { 8986f3e57acSmx205022 int cmd; 8996f3e57acSmx205022 uint32_t *lbmp; 9006f3e57acSmx205022 lb_info_sz_t *lbsp; 9016f3e57acSmx205022 lb_property_t *lbpp; 9026f3e57acSmx205022 9036f3e57acSmx205022 /* 9046f3e57acSmx205022 * Validate format of ioctl 9056f3e57acSmx205022 */ 9066f3e57acSmx205022 if (mp->b_cont == NULL) 9076f3e57acSmx205022 return (IOC_INVAL); 9086f3e57acSmx205022 9096f3e57acSmx205022 cmd = iocp->ioc_cmd; 9106f3e57acSmx205022 9116f3e57acSmx205022 switch (cmd) { 9126f3e57acSmx205022 default: 9136f3e57acSmx205022 return (IOC_INVAL); 9146f3e57acSmx205022 9156f3e57acSmx205022 case LB_GET_INFO_SIZE: 9166f3e57acSmx205022 if (iocp->ioc_count != sizeof (lb_info_sz_t)) 9176f3e57acSmx205022 return (IOC_INVAL); 9186f3e57acSmx205022 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 9196f3e57acSmx205022 *lbsp = sizeof (loopmodes); 9206f3e57acSmx205022 return (IOC_REPLY); 9216f3e57acSmx205022 9226f3e57acSmx205022 case LB_GET_INFO: 9236f3e57acSmx205022 if (iocp->ioc_count != sizeof (loopmodes)) 9246f3e57acSmx205022 return (IOC_INVAL); 9256f3e57acSmx205022 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 9266f3e57acSmx205022 bcopy(loopmodes, lbpp, sizeof (loopmodes)); 9276f3e57acSmx205022 return (IOC_REPLY); 9286f3e57acSmx205022 9296f3e57acSmx205022 case LB_GET_MODE: 9306f3e57acSmx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9316f3e57acSmx205022 return (IOC_INVAL); 9326f3e57acSmx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9336f3e57acSmx205022 *lbmp = ngep->param_loop_mode; 9346f3e57acSmx205022 return (IOC_REPLY); 9356f3e57acSmx205022 9366f3e57acSmx205022 case LB_SET_MODE: 9376f3e57acSmx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9386f3e57acSmx205022 return (IOC_INVAL); 9396f3e57acSmx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9406f3e57acSmx205022 return (nge_set_loop_mode(ngep, *lbmp)); 9416f3e57acSmx205022 } 9426f3e57acSmx205022 } 9436f3e57acSmx205022 9446f3e57acSmx205022 #undef NGE_DBG 9456f3e57acSmx205022 #define NGE_DBG NGE_DBG_NEMO 9466f3e57acSmx205022 9476f3e57acSmx205022 9486f3e57acSmx205022 static void 9496f3e57acSmx205022 nge_check_desc_prop(nge_t *ngep) 9506f3e57acSmx205022 { 9516f3e57acSmx205022 if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD) 9526f3e57acSmx205022 ngep->desc_mode = DESC_HOT; 9536f3e57acSmx205022 9546f3e57acSmx205022 if (ngep->desc_mode == DESC_OFFLOAD) { 9556f3e57acSmx205022 9566f3e57acSmx205022 ngep->desc_attr = nge_sum_desc; 9576f3e57acSmx205022 9586f3e57acSmx205022 } else if (ngep->desc_mode == DESC_HOT) { 9596f3e57acSmx205022 9606f3e57acSmx205022 ngep->desc_attr = nge_hot_desc; 9616f3e57acSmx205022 } 9626f3e57acSmx205022 } 9636f3e57acSmx205022 9646f3e57acSmx205022 /* 9656f3e57acSmx205022 * nge_get_props -- get the parameters to tune the driver 9666f3e57acSmx205022 */ 9676f3e57acSmx205022 static void 9686f3e57acSmx205022 nge_get_props(nge_t *ngep) 9696f3e57acSmx205022 { 9706f3e57acSmx205022 chip_info_t *infop; 9716f3e57acSmx205022 dev_info_t *devinfo; 9726f3e57acSmx205022 nge_dev_spec_param_t *dev_param_p; 9736f3e57acSmx205022 9746f3e57acSmx205022 devinfo = ngep->devinfo; 9756f3e57acSmx205022 infop = (chip_info_t *)&ngep->chipinfo; 9766f3e57acSmx205022 dev_param_p = &ngep->dev_spec_param; 9776f3e57acSmx205022 9786f3e57acSmx205022 infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9796f3e57acSmx205022 DDI_PROP_DONTPASS, clsize_propname, 32); 9806f3e57acSmx205022 9816f3e57acSmx205022 infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9826f3e57acSmx205022 DDI_PROP_DONTPASS, latency_propname, 64); 98302d51d0dSjj146644 ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 98402d51d0dSjj146644 DDI_PROP_DONTPASS, intr_moderation, NGE_SET); 9856f3e57acSmx205022 ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9866f3e57acSmx205022 DDI_PROP_DONTPASS, rx_data_hw, 0x20); 9876f3e57acSmx205022 ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9886f3e57acSmx205022 DDI_PROP_DONTPASS, rx_prd_lw, 0x4); 9896f3e57acSmx205022 ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9906f3e57acSmx205022 DDI_PROP_DONTPASS, rx_prd_hw, 0xc); 9916f3e57acSmx205022 9926f3e57acSmx205022 ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9936f3e57acSmx205022 DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC); 9946f3e57acSmx205022 ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9956f3e57acSmx205022 DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP); 9966f3e57acSmx205022 ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9976f3e57acSmx205022 DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type); 9986f3e57acSmx205022 ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9996f3e57acSmx205022 DDI_PROP_DONTPASS, low_memory_mode, 0); 10006f3e57acSmx205022 10016f3e57acSmx205022 if (dev_param_p->jumbo) { 10026f3e57acSmx205022 ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 10036f3e57acSmx205022 DDI_PROP_DONTPASS, default_mtu, ETHERMTU); 10046f3e57acSmx205022 } else 10056f3e57acSmx205022 ngep->default_mtu = ETHERMTU; 100686d6718fSLi-Zhen You if (dev_param_p->tx_pause_frame) 100786d6718fSLi-Zhen You ngep->param_link_tx_pause = B_TRUE; 100886d6718fSLi-Zhen You else 100986d6718fSLi-Zhen You ngep->param_link_tx_pause = B_FALSE; 101086d6718fSLi-Zhen You 101186d6718fSLi-Zhen You if (dev_param_p->rx_pause_frame) 101286d6718fSLi-Zhen You ngep->param_link_rx_pause = B_TRUE; 101386d6718fSLi-Zhen You else 101486d6718fSLi-Zhen You ngep->param_link_rx_pause = B_FALSE; 10156f3e57acSmx205022 10166f3e57acSmx205022 if (ngep->default_mtu > ETHERMTU && 10176f3e57acSmx205022 ngep->default_mtu <= NGE_MTU_2500) { 10186f3e57acSmx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 10196f3e57acSmx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 10206f3e57acSmx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 10216f3e57acSmx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 10226f3e57acSmx205022 ngep->nge_split = NGE_SPLIT_256; 10236f3e57acSmx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 10246f3e57acSmx205022 ngep->default_mtu <= NGE_MTU_4500) { 10256f3e57acSmx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 10266f3e57acSmx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 10276f3e57acSmx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 10286f3e57acSmx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 10296f3e57acSmx205022 ngep->nge_split = NGE_SPLIT_256; 10306f3e57acSmx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 10316f3e57acSmx205022 ngep->default_mtu <= NGE_MAX_MTU) { 10326f3e57acSmx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10336f3e57acSmx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10346f3e57acSmx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10356f3e57acSmx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10366f3e57acSmx205022 ngep->nge_split = NGE_SPLIT_256; 10376f3e57acSmx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 10386f3e57acSmx205022 ngep->default_mtu = NGE_MAX_MTU; 10396f3e57acSmx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10406f3e57acSmx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10416f3e57acSmx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10426f3e57acSmx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10436f3e57acSmx205022 ngep->nge_split = NGE_SPLIT_256; 10446f3e57acSmx205022 } else if (ngep->lowmem_mode != 0) { 10456f3e57acSmx205022 ngep->default_mtu = ETHERMTU; 10466f3e57acSmx205022 ngep->buf_size = NGE_STD_BUFSZ; 10476f3e57acSmx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 10486f3e57acSmx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 10496f3e57acSmx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 10506f3e57acSmx205022 ngep->nge_split = NGE_SPLIT_32; 10516f3e57acSmx205022 } else { 10526f3e57acSmx205022 ngep->default_mtu = ETHERMTU; 10536f3e57acSmx205022 ngep->buf_size = NGE_STD_BUFSZ; 10546f3e57acSmx205022 ngep->tx_desc = dev_param_p->tx_desc_num; 10556f3e57acSmx205022 ngep->rx_desc = dev_param_p->rx_desc_num; 10566f3e57acSmx205022 ngep->rx_buf = dev_param_p->rx_desc_num * 2; 10576f3e57acSmx205022 ngep->nge_split = dev_param_p->nge_split; 10586f3e57acSmx205022 } 10596f3e57acSmx205022 10606f3e57acSmx205022 nge_check_desc_prop(ngep); 10616f3e57acSmx205022 } 10626f3e57acSmx205022 10636f3e57acSmx205022 10646f3e57acSmx205022 static int 106519397407SSherry Moore nge_reset_dev(nge_t *ngep) 10666f3e57acSmx205022 { 10676f3e57acSmx205022 int err; 10682d58516dSmx205022 nge_mul_addr1 maddr1; 10692d58516dSmx205022 nge_sw_statistics_t *sw_stp; 10702d58516dSmx205022 sw_stp = &ngep->statistics.sw_statistics; 10716f3e57acSmx205022 send_ring_t *srp = ngep->send; 10726f3e57acSmx205022 10736f3e57acSmx205022 ASSERT(mutex_owned(ngep->genlock)); 10746f3e57acSmx205022 mutex_enter(srp->tc_lock); 10756f3e57acSmx205022 mutex_enter(srp->tx_lock); 10766f3e57acSmx205022 10776f3e57acSmx205022 nge_tx_recycle_all(ngep); 10786f3e57acSmx205022 err = nge_reinit_ring(ngep); 10796f3e57acSmx205022 if (err == DDI_FAILURE) { 10806f3e57acSmx205022 mutex_exit(srp->tx_lock); 10816f3e57acSmx205022 mutex_exit(srp->tc_lock); 10826f3e57acSmx205022 return (err); 10836f3e57acSmx205022 } 10846f3e57acSmx205022 err = nge_chip_reset(ngep); 10852d58516dSmx205022 /* 10862d58516dSmx205022 * Clear the Multicast mac address table 10872d58516dSmx205022 */ 10882d58516dSmx205022 nge_reg_put32(ngep, NGE_MUL_ADDR0, 0); 10892d58516dSmx205022 maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1); 10902d58516dSmx205022 maddr1.addr_bits.addr = 0; 10912d58516dSmx205022 nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val); 10922d58516dSmx205022 10936f3e57acSmx205022 mutex_exit(srp->tx_lock); 10946f3e57acSmx205022 mutex_exit(srp->tc_lock); 10956f3e57acSmx205022 if (err == DDI_FAILURE) 10966f3e57acSmx205022 return (err); 10976f3e57acSmx205022 ngep->watchdog = 0; 10986f3e57acSmx205022 ngep->resched_needed = B_FALSE; 10996f3e57acSmx205022 ngep->promisc = B_FALSE; 11006f3e57acSmx205022 ngep->param_loop_mode = NGE_LOOP_NONE; 11016f3e57acSmx205022 ngep->factotum_flag = 0; 11026f3e57acSmx205022 ngep->resched_needed = 0; 11036f3e57acSmx205022 ngep->nge_mac_state = NGE_MAC_RESET; 11046f3e57acSmx205022 ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL; 11056f3e57acSmx205022 ngep->max_sdu += VTAG_SIZE; 11066f3e57acSmx205022 ngep->rx_def = 0x16; 11072d58516dSmx205022 11082d58516dSmx205022 /* Clear the software statistics */ 11092d58516dSmx205022 sw_stp->recv_count = 0; 11102d58516dSmx205022 sw_stp->xmit_count = 0; 11112d58516dSmx205022 sw_stp->rbytes = 0; 11122d58516dSmx205022 sw_stp->obytes = 0; 11132d58516dSmx205022 11146f3e57acSmx205022 return (DDI_SUCCESS); 11156f3e57acSmx205022 } 11166f3e57acSmx205022 11176f3e57acSmx205022 static void 11186f3e57acSmx205022 nge_m_stop(void *arg) 11196f3e57acSmx205022 { 11206f3e57acSmx205022 nge_t *ngep = arg; /* private device info */ 1121a01a4735SWinson Wang - Sun Microsystems - Beijing China int err; 11226f3e57acSmx205022 11236f3e57acSmx205022 NGE_TRACE(("nge_m_stop($%p)", arg)); 11246f3e57acSmx205022 11256f3e57acSmx205022 /* 11266f3e57acSmx205022 * Just stop processing, then record new MAC state 11276f3e57acSmx205022 */ 11286f3e57acSmx205022 mutex_enter(ngep->genlock); 11292d58516dSmx205022 /* If suspended, the adapter is already stopped, just return. */ 11302d58516dSmx205022 if (ngep->suspended) { 11312d58516dSmx205022 ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED); 11322d58516dSmx205022 mutex_exit(ngep->genlock); 11332d58516dSmx205022 return; 11342d58516dSmx205022 } 11356f3e57acSmx205022 rw_enter(ngep->rwlock, RW_WRITER); 11366f3e57acSmx205022 1137a01a4735SWinson Wang - Sun Microsystems - Beijing China err = nge_chip_stop(ngep, B_FALSE); 1138a01a4735SWinson Wang - Sun Microsystems - Beijing China if (err == DDI_FAILURE) 1139a01a4735SWinson Wang - Sun Microsystems - Beijing China err = nge_chip_reset(ngep); 1140a01a4735SWinson Wang - Sun Microsystems - Beijing China if (err == DDI_FAILURE) 1141a01a4735SWinson Wang - Sun Microsystems - Beijing China nge_problem(ngep, "nge_m_stop: stop chip failed"); 11426f3e57acSmx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 11436f3e57acSmx205022 11446f3e57acSmx205022 /* Recycle all the TX BD */ 11456f3e57acSmx205022 nge_tx_recycle_all(ngep); 11466f3e57acSmx205022 nge_fini_rings(ngep); 11476f3e57acSmx205022 nge_free_bufs(ngep); 11486f3e57acSmx205022 11496f3e57acSmx205022 NGE_DEBUG(("nge_m_stop($%p) done", arg)); 11506f3e57acSmx205022 11516f3e57acSmx205022 rw_exit(ngep->rwlock); 11526f3e57acSmx205022 mutex_exit(ngep->genlock); 11536f3e57acSmx205022 } 11546f3e57acSmx205022 11556f3e57acSmx205022 static int 11566f3e57acSmx205022 nge_m_start(void *arg) 11576f3e57acSmx205022 { 11586f3e57acSmx205022 int err; 11596f3e57acSmx205022 nge_t *ngep = arg; 11606f3e57acSmx205022 11616f3e57acSmx205022 NGE_TRACE(("nge_m_start($%p)", arg)); 11622d58516dSmx205022 11636f3e57acSmx205022 /* 11646f3e57acSmx205022 * Start processing and record new MAC state 11656f3e57acSmx205022 */ 11666f3e57acSmx205022 mutex_enter(ngep->genlock); 11672d58516dSmx205022 /* 11682d58516dSmx205022 * If suspended, don't start, as the resume processing 11692d58516dSmx205022 * will recall this function with the suspended flag off. 11702d58516dSmx205022 */ 11712d58516dSmx205022 if (ngep->suspended) { 11722d58516dSmx205022 mutex_exit(ngep->genlock); 117375675fb7Svb160487 return (EIO); 11742d58516dSmx205022 } 11756f3e57acSmx205022 rw_enter(ngep->rwlock, RW_WRITER); 11766f3e57acSmx205022 err = nge_alloc_bufs(ngep); 11776f3e57acSmx205022 if (err != DDI_SUCCESS) { 11786f3e57acSmx205022 nge_problem(ngep, "nge_m_start: DMA buffer allocation failed"); 11796f3e57acSmx205022 goto finish; 11806f3e57acSmx205022 } 11816f3e57acSmx205022 err = nge_init_rings(ngep); 11826f3e57acSmx205022 if (err != DDI_SUCCESS) { 11836f3e57acSmx205022 nge_free_bufs(ngep); 118475675fb7Svb160487 nge_problem(ngep, "nge_init_rings() failed,err=%x", err); 11856f3e57acSmx205022 goto finish; 11866f3e57acSmx205022 } 11876f3e57acSmx205022 err = nge_restart(ngep); 11886f3e57acSmx205022 11896f3e57acSmx205022 NGE_DEBUG(("nge_m_start($%p) done", arg)); 11906f3e57acSmx205022 finish: 11916f3e57acSmx205022 rw_exit(ngep->rwlock); 11926f3e57acSmx205022 mutex_exit(ngep->genlock); 11936f3e57acSmx205022 119475675fb7Svb160487 return (err == DDI_SUCCESS ? 0 : EIO); 11956f3e57acSmx205022 } 11966f3e57acSmx205022 11976f3e57acSmx205022 static int 11986f3e57acSmx205022 nge_m_unicst(void *arg, const uint8_t *macaddr) 11996f3e57acSmx205022 { 12006f3e57acSmx205022 nge_t *ngep = arg; 12016f3e57acSmx205022 12026f3e57acSmx205022 NGE_TRACE(("nge_m_unicst($%p)", arg)); 12036f3e57acSmx205022 /* 12046f3e57acSmx205022 * Remember the new current address in the driver state 12056f3e57acSmx205022 * Sync the chip's idea of the address too ... 12066f3e57acSmx205022 */ 12076f3e57acSmx205022 mutex_enter(ngep->genlock); 12086f3e57acSmx205022 12096f3e57acSmx205022 ethaddr_copy(macaddr, ngep->cur_uni_addr.addr); 12106f3e57acSmx205022 ngep->cur_uni_addr.set = 1; 12116f3e57acSmx205022 12126f3e57acSmx205022 /* 12136f3e57acSmx205022 * If we are suspended, we want to quit now, and not update 12146f3e57acSmx205022 * the chip. Doing so might put it in a bad state, but the 12156f3e57acSmx205022 * resume will get the unicast address installed. 12166f3e57acSmx205022 */ 12172d58516dSmx205022 if (ngep->suspended) { 12182d58516dSmx205022 mutex_exit(ngep->genlock); 12196f3e57acSmx205022 return (DDI_SUCCESS); 12202d58516dSmx205022 } 12216f3e57acSmx205022 nge_chip_sync(ngep); 12226f3e57acSmx205022 12236f3e57acSmx205022 NGE_DEBUG(("nge_m_unicst($%p) done", arg)); 12246f3e57acSmx205022 mutex_exit(ngep->genlock); 12256f3e57acSmx205022 12266f3e57acSmx205022 return (0); 12276f3e57acSmx205022 } 12286f3e57acSmx205022 12296f3e57acSmx205022 static int 12306f3e57acSmx205022 nge_m_promisc(void *arg, boolean_t on) 12316f3e57acSmx205022 { 12326f3e57acSmx205022 nge_t *ngep = arg; 12336f3e57acSmx205022 12346f3e57acSmx205022 NGE_TRACE(("nge_m_promisc($%p)", arg)); 12356f3e57acSmx205022 12366f3e57acSmx205022 /* 12376f3e57acSmx205022 * Store specified mode and pass to chip layer to update h/w 12386f3e57acSmx205022 */ 12396f3e57acSmx205022 mutex_enter(ngep->genlock); 12402d58516dSmx205022 /* 12412d58516dSmx205022 * If suspended, there is no need to do anything, even 12422d58516dSmx205022 * recording the promiscuious mode is not neccessary, as 12432d58516dSmx205022 * it won't be properly set on resume. Just return failing. 12442d58516dSmx205022 */ 12452d58516dSmx205022 if (ngep->suspended) { 12462d58516dSmx205022 mutex_exit(ngep->genlock); 12472d58516dSmx205022 return (DDI_FAILURE); 12482d58516dSmx205022 } 12496f3e57acSmx205022 if (ngep->promisc == on) { 12506f3e57acSmx205022 mutex_exit(ngep->genlock); 12516f3e57acSmx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12526f3e57acSmx205022 return (0); 12536f3e57acSmx205022 } 12546f3e57acSmx205022 ngep->promisc = on; 12556de4f663Smx205022 ngep->record_promisc = ngep->promisc; 12566f3e57acSmx205022 nge_chip_sync(ngep); 12576f3e57acSmx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12586f3e57acSmx205022 mutex_exit(ngep->genlock); 12596f3e57acSmx205022 12606f3e57acSmx205022 return (0); 12616f3e57acSmx205022 } 12626f3e57acSmx205022 12636f3e57acSmx205022 static void nge_mulparam(nge_t *ngep) 12646f3e57acSmx205022 { 12656f3e57acSmx205022 uint8_t number; 12666f3e57acSmx205022 ether_addr_t pand; 12676f3e57acSmx205022 ether_addr_t por; 12686f3e57acSmx205022 mul_item *plist; 12696f3e57acSmx205022 12706f3e57acSmx205022 for (number = 0; number < ETHERADDRL; number++) { 12716f3e57acSmx205022 pand[number] = 0x00; 12726f3e57acSmx205022 por[number] = 0x00; 12736f3e57acSmx205022 } 12746f3e57acSmx205022 for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) { 12756f3e57acSmx205022 for (number = 0; number < ETHERADDRL; number++) { 12766f3e57acSmx205022 pand[number] &= plist->mul_addr[number]; 12776f3e57acSmx205022 por[number] |= plist->mul_addr[number]; 12786f3e57acSmx205022 } 12796f3e57acSmx205022 } 12806f3e57acSmx205022 for (number = 0; number < ETHERADDRL; number++) { 12816f3e57acSmx205022 ngep->cur_mul_addr.addr[number] 12826f3e57acSmx205022 = pand[number] & por[number]; 12836f3e57acSmx205022 ngep->cur_mul_mask.addr[number] 12846f3e57acSmx205022 = pand [number] | (~por[number]); 12856f3e57acSmx205022 } 12866f3e57acSmx205022 } 12876f3e57acSmx205022 static int 12886f3e57acSmx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12896f3e57acSmx205022 { 12906f3e57acSmx205022 boolean_t update; 12916f3e57acSmx205022 boolean_t b_eq; 12926f3e57acSmx205022 nge_t *ngep = arg; 12936f3e57acSmx205022 mul_item *plist; 12946f3e57acSmx205022 mul_item *plist_prev; 12956f3e57acSmx205022 mul_item *pitem; 12966f3e57acSmx205022 12976f3e57acSmx205022 NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg, 12986f3e57acSmx205022 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 12996f3e57acSmx205022 13006f3e57acSmx205022 update = B_FALSE; 13016f3e57acSmx205022 plist = plist_prev = NULL; 13026f3e57acSmx205022 mutex_enter(ngep->genlock); 13036f3e57acSmx205022 if (add) { 13046f3e57acSmx205022 if (ngep->pcur_mulist != NULL) { 13056f3e57acSmx205022 for (plist = ngep->pcur_mulist; plist != NULL; 13066f3e57acSmx205022 plist = plist->next) { 13076f3e57acSmx205022 b_eq = ether_eq(plist->mul_addr, mca); 13086f3e57acSmx205022 if (b_eq) { 13096f3e57acSmx205022 plist->ref_cnt++; 13106f3e57acSmx205022 break; 13116f3e57acSmx205022 } 13126f3e57acSmx205022 plist_prev = plist; 13136f3e57acSmx205022 } 13146f3e57acSmx205022 } 13156f3e57acSmx205022 13166f3e57acSmx205022 if (plist == NULL) { 13176f3e57acSmx205022 pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP); 13186f3e57acSmx205022 ether_copy(mca, pitem->mul_addr); 13196f3e57acSmx205022 pitem ->ref_cnt++; 13206f3e57acSmx205022 pitem ->next = NULL; 13216f3e57acSmx205022 if (plist_prev == NULL) 13226f3e57acSmx205022 ngep->pcur_mulist = pitem; 13236f3e57acSmx205022 else 13246f3e57acSmx205022 plist_prev->next = pitem; 13256f3e57acSmx205022 update = B_TRUE; 13266f3e57acSmx205022 } 13276f3e57acSmx205022 } else { 13286f3e57acSmx205022 if (ngep->pcur_mulist != NULL) { 13296f3e57acSmx205022 for (plist = ngep->pcur_mulist; plist != NULL; 13306f3e57acSmx205022 plist = plist->next) { 13316f3e57acSmx205022 b_eq = ether_eq(plist->mul_addr, mca); 13326f3e57acSmx205022 if (b_eq) { 13336f3e57acSmx205022 update = B_TRUE; 13346f3e57acSmx205022 break; 13356f3e57acSmx205022 } 13366f3e57acSmx205022 plist_prev = plist; 13376f3e57acSmx205022 } 13386f3e57acSmx205022 13396f3e57acSmx205022 if (update) { 13406f3e57acSmx205022 if ((plist_prev == NULL) && 13416f3e57acSmx205022 (plist->next == NULL)) 13426f3e57acSmx205022 ngep->pcur_mulist = NULL; 13436f3e57acSmx205022 else if ((plist_prev == NULL) && 13446f3e57acSmx205022 (plist->next != NULL)) 13456f3e57acSmx205022 ngep->pcur_mulist = plist->next; 13466f3e57acSmx205022 else 13476f3e57acSmx205022 plist_prev->next = plist->next; 13486f3e57acSmx205022 kmem_free(plist, sizeof (mul_item)); 13496f3e57acSmx205022 } 13506f3e57acSmx205022 } 13516f3e57acSmx205022 } 13526f3e57acSmx205022 13532d58516dSmx205022 if (update && !ngep->suspended) { 13546f3e57acSmx205022 nge_mulparam(ngep); 13556f3e57acSmx205022 nge_chip_sync(ngep); 13566f3e57acSmx205022 } 13576f3e57acSmx205022 NGE_DEBUG(("nge_m_multicst($%p) done", arg)); 13586f3e57acSmx205022 mutex_exit(ngep->genlock); 13596f3e57acSmx205022 13606f3e57acSmx205022 return (0); 13616f3e57acSmx205022 } 13626f3e57acSmx205022 13636f3e57acSmx205022 static void 13646f3e57acSmx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 13656f3e57acSmx205022 { 13666f3e57acSmx205022 int err; 13676f3e57acSmx205022 int cmd; 13686f3e57acSmx205022 nge_t *ngep = arg; 13696f3e57acSmx205022 struct iocblk *iocp; 13706f3e57acSmx205022 enum ioc_reply status; 13716f3e57acSmx205022 boolean_t need_privilege; 13726f3e57acSmx205022 13736f3e57acSmx205022 /* 13746f3e57acSmx205022 * If suspended, we might actually be able to do some of 13756f3e57acSmx205022 * these ioctls, but it is harder to make sure they occur 13766f3e57acSmx205022 * without actually putting the hardware in an undesireable 13776f3e57acSmx205022 * state. So just NAK it. 13786f3e57acSmx205022 */ 13792d58516dSmx205022 mutex_enter(ngep->genlock); 13806f3e57acSmx205022 if (ngep->suspended) { 13816f3e57acSmx205022 miocnak(wq, mp, 0, EINVAL); 13822d58516dSmx205022 mutex_exit(ngep->genlock); 13836f3e57acSmx205022 return; 13846f3e57acSmx205022 } 13852d58516dSmx205022 mutex_exit(ngep->genlock); 13866f3e57acSmx205022 13876f3e57acSmx205022 /* 13886f3e57acSmx205022 * Validate the command before bothering with the mutex ... 13896f3e57acSmx205022 */ 13906f3e57acSmx205022 iocp = (struct iocblk *)mp->b_rptr; 13916f3e57acSmx205022 iocp->ioc_error = 0; 13926f3e57acSmx205022 need_privilege = B_TRUE; 13936f3e57acSmx205022 cmd = iocp->ioc_cmd; 13946f3e57acSmx205022 13956f3e57acSmx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x", cmd)); 13966f3e57acSmx205022 switch (cmd) { 13976f3e57acSmx205022 default: 13986f3e57acSmx205022 NGE_LDB(NGE_DBG_BADIOC, 13996f3e57acSmx205022 ("nge_m_ioctl: unknown cmd 0x%x", cmd)); 14006f3e57acSmx205022 14016f3e57acSmx205022 miocnak(wq, mp, 0, EINVAL); 14026f3e57acSmx205022 return; 14036f3e57acSmx205022 14046f3e57acSmx205022 case NGE_MII_READ: 14056f3e57acSmx205022 case NGE_MII_WRITE: 14066f3e57acSmx205022 case NGE_SEE_READ: 14076f3e57acSmx205022 case NGE_SEE_WRITE: 14086f3e57acSmx205022 case NGE_DIAG: 14096f3e57acSmx205022 case NGE_PEEK: 14106f3e57acSmx205022 case NGE_POKE: 14116f3e57acSmx205022 case NGE_PHY_RESET: 14126f3e57acSmx205022 case NGE_SOFT_RESET: 14136f3e57acSmx205022 case NGE_HARD_RESET: 14146f3e57acSmx205022 break; 14156f3e57acSmx205022 14166f3e57acSmx205022 case LB_GET_INFO_SIZE: 14176f3e57acSmx205022 case LB_GET_INFO: 14186f3e57acSmx205022 case LB_GET_MODE: 14196f3e57acSmx205022 need_privilege = B_FALSE; 14206f3e57acSmx205022 break; 14216f3e57acSmx205022 case LB_SET_MODE: 14226f3e57acSmx205022 break; 14236f3e57acSmx205022 } 14246f3e57acSmx205022 14256f3e57acSmx205022 if (need_privilege) { 14266f3e57acSmx205022 /* 14276f3e57acSmx205022 * Check for specific net_config privilege. 14286f3e57acSmx205022 */ 14296f3e57acSmx205022 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 14306f3e57acSmx205022 if (err != 0) { 14316f3e57acSmx205022 NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d", 14326f3e57acSmx205022 cmd, err)); 14336f3e57acSmx205022 miocnak(wq, mp, 0, err); 14346f3e57acSmx205022 return; 14356f3e57acSmx205022 } 14366f3e57acSmx205022 } 14376f3e57acSmx205022 14386f3e57acSmx205022 mutex_enter(ngep->genlock); 14396f3e57acSmx205022 14406f3e57acSmx205022 switch (cmd) { 14416f3e57acSmx205022 default: 14426f3e57acSmx205022 _NOTE(NOTREACHED) 14436f3e57acSmx205022 status = IOC_INVAL; 14446f3e57acSmx205022 break; 14456f3e57acSmx205022 14466f3e57acSmx205022 case NGE_MII_READ: 14476f3e57acSmx205022 case NGE_MII_WRITE: 14486f3e57acSmx205022 case NGE_SEE_READ: 14496f3e57acSmx205022 case NGE_SEE_WRITE: 14506f3e57acSmx205022 case NGE_DIAG: 14516f3e57acSmx205022 case NGE_PEEK: 14526f3e57acSmx205022 case NGE_POKE: 14536f3e57acSmx205022 case NGE_PHY_RESET: 14546f3e57acSmx205022 case NGE_SOFT_RESET: 14556f3e57acSmx205022 case NGE_HARD_RESET: 14566f3e57acSmx205022 status = nge_chip_ioctl(ngep, mp, iocp); 14576f3e57acSmx205022 break; 14586f3e57acSmx205022 14596f3e57acSmx205022 case LB_GET_INFO_SIZE: 14606f3e57acSmx205022 case LB_GET_INFO: 14616f3e57acSmx205022 case LB_GET_MODE: 14626f3e57acSmx205022 case LB_SET_MODE: 14636f3e57acSmx205022 status = nge_loop_ioctl(ngep, mp, iocp); 14646f3e57acSmx205022 break; 14656f3e57acSmx205022 14666f3e57acSmx205022 } 14676f3e57acSmx205022 14686f3e57acSmx205022 /* 14696f3e57acSmx205022 * Do we need to reprogram the PHY and/or the MAC? 14706f3e57acSmx205022 * Do it now, while we still have the mutex. 14716f3e57acSmx205022 * 14726f3e57acSmx205022 * Note: update the PHY first, 'cos it controls the 14736f3e57acSmx205022 * speed/duplex parameters that the MAC code uses. 14746f3e57acSmx205022 */ 14756f3e57acSmx205022 14766f3e57acSmx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status)); 14776f3e57acSmx205022 14786f3e57acSmx205022 switch (status) { 14796f3e57acSmx205022 case IOC_RESTART_REPLY: 14806f3e57acSmx205022 case IOC_RESTART_ACK: 14816f3e57acSmx205022 (*ngep->physops->phys_update)(ngep); 14826f3e57acSmx205022 nge_chip_sync(ngep); 14836f3e57acSmx205022 break; 14846f3e57acSmx205022 14856f3e57acSmx205022 default: 14866f3e57acSmx205022 break; 14876f3e57acSmx205022 } 14886f3e57acSmx205022 14896f3e57acSmx205022 mutex_exit(ngep->genlock); 14906f3e57acSmx205022 14916f3e57acSmx205022 /* 14926f3e57acSmx205022 * Finally, decide how to reply 14936f3e57acSmx205022 */ 14946f3e57acSmx205022 switch (status) { 14956f3e57acSmx205022 14966f3e57acSmx205022 default: 14976f3e57acSmx205022 case IOC_INVAL: 14986f3e57acSmx205022 miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 14996f3e57acSmx205022 EINVAL : iocp->ioc_error); 15006f3e57acSmx205022 break; 15016f3e57acSmx205022 15026f3e57acSmx205022 case IOC_DONE: 15036f3e57acSmx205022 break; 15046f3e57acSmx205022 15056f3e57acSmx205022 case IOC_RESTART_ACK: 15066f3e57acSmx205022 case IOC_ACK: 15076f3e57acSmx205022 miocack(wq, mp, 0, 0); 15086f3e57acSmx205022 break; 15096f3e57acSmx205022 15106f3e57acSmx205022 case IOC_RESTART_REPLY: 15116f3e57acSmx205022 case IOC_REPLY: 15126f3e57acSmx205022 mp->b_datap->db_type = iocp->ioc_error == 0 ? 15136f3e57acSmx205022 M_IOCACK : M_IOCNAK; 15146f3e57acSmx205022 qreply(wq, mp); 15156f3e57acSmx205022 break; 15166f3e57acSmx205022 } 15176f3e57acSmx205022 } 15186f3e57acSmx205022 15195a3d0718Smx205022 static boolean_t 15205a3d0718Smx205022 nge_param_locked(mac_prop_id_t pr_num) 15215a3d0718Smx205022 { 15225a3d0718Smx205022 /* 15235a3d0718Smx205022 * All adv_* parameters are locked (read-only) while 15245a3d0718Smx205022 * the device is in any sort of loopback mode ... 15255a3d0718Smx205022 */ 15265a3d0718Smx205022 switch (pr_num) { 15273fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP: 15283fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 15293fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 15303fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 15313fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 15323fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 15333fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 15343fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 15353fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 15363fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 15373fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 15383fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 15393fd94f8cSam223141 case MAC_PROP_AUTONEG: 15403fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 15415a3d0718Smx205022 return (B_TRUE); 15425a3d0718Smx205022 } 15435a3d0718Smx205022 return (B_FALSE); 15445a3d0718Smx205022 } 15455a3d0718Smx205022 15465a3d0718Smx205022 /* 15475a3d0718Smx205022 * callback functions for set/get of properties 15485a3d0718Smx205022 */ 15495a3d0718Smx205022 static int 15505a3d0718Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 15515a3d0718Smx205022 uint_t pr_valsize, const void *pr_val) 15525a3d0718Smx205022 { 15535a3d0718Smx205022 nge_t *ngep = barg; 15545a3d0718Smx205022 int err = 0; 15554045d941Ssowmini uint32_t cur_mtu, new_mtu; 15565a3d0718Smx205022 link_flowctrl_t fl; 15575a3d0718Smx205022 15585a3d0718Smx205022 mutex_enter(ngep->genlock); 15595a3d0718Smx205022 if (ngep->param_loop_mode != NGE_LOOP_NONE && 15605a3d0718Smx205022 nge_param_locked(pr_num)) { 15615a3d0718Smx205022 /* 15625a3d0718Smx205022 * All adv_* parameters are locked (read-only) 15635a3d0718Smx205022 * while the device is in any sort of loopback mode. 15645a3d0718Smx205022 */ 15655a3d0718Smx205022 mutex_exit(ngep->genlock); 15665a3d0718Smx205022 return (EBUSY); 15675a3d0718Smx205022 } 15685a3d0718Smx205022 switch (pr_num) { 15693fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 15705a3d0718Smx205022 ngep->param_en_1000fdx = *(uint8_t *)pr_val; 15715a3d0718Smx205022 ngep->param_adv_1000fdx = *(uint8_t *)pr_val; 15725a3d0718Smx205022 goto reprogram; 15733fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 15745a3d0718Smx205022 ngep->param_en_100fdx = *(uint8_t *)pr_val; 15755a3d0718Smx205022 ngep->param_adv_100fdx = *(uint8_t *)pr_val; 15765a3d0718Smx205022 goto reprogram; 15773fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 15785a3d0718Smx205022 ngep->param_en_100hdx = *(uint8_t *)pr_val; 15795a3d0718Smx205022 ngep->param_adv_100hdx = *(uint8_t *)pr_val; 15805a3d0718Smx205022 goto reprogram; 15813fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 15825a3d0718Smx205022 ngep->param_en_10fdx = *(uint8_t *)pr_val; 15835a3d0718Smx205022 ngep->param_adv_10fdx = *(uint8_t *)pr_val; 15845a3d0718Smx205022 goto reprogram; 15853fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 15865a3d0718Smx205022 ngep->param_en_10hdx = *(uint8_t *)pr_val; 15875a3d0718Smx205022 ngep->param_adv_10hdx = *(uint8_t *)pr_val; 15885a3d0718Smx205022 reprogram: 15895a3d0718Smx205022 (*ngep->physops->phys_update)(ngep); 15905a3d0718Smx205022 nge_chip_sync(ngep); 15915a3d0718Smx205022 break; 15925a3d0718Smx205022 15933fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP: 15943fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 15953fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 15963fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 15973fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 15983fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 15993fd94f8cSam223141 case MAC_PROP_STATUS: 16003fd94f8cSam223141 case MAC_PROP_SPEED: 16013fd94f8cSam223141 case MAC_PROP_DUPLEX: 16023fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 16035a3d0718Smx205022 err = ENOTSUP; /* read-only prop. Can't set this */ 16045a3d0718Smx205022 break; 16053fd94f8cSam223141 case MAC_PROP_AUTONEG: 16065a3d0718Smx205022 ngep->param_adv_autoneg = *(uint8_t *)pr_val; 16075a3d0718Smx205022 (*ngep->physops->phys_update)(ngep); 16085a3d0718Smx205022 nge_chip_sync(ngep); 16095a3d0718Smx205022 break; 16103fd94f8cSam223141 case MAC_PROP_MTU: 16115a3d0718Smx205022 cur_mtu = ngep->default_mtu; 16125a3d0718Smx205022 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 16135a3d0718Smx205022 if (new_mtu == cur_mtu) { 16145a3d0718Smx205022 err = 0; 16155a3d0718Smx205022 break; 16165a3d0718Smx205022 } 16175a3d0718Smx205022 if (new_mtu < ETHERMTU || 16185a3d0718Smx205022 new_mtu > NGE_MAX_MTU) { 16195a3d0718Smx205022 err = EINVAL; 16205a3d0718Smx205022 break; 16215a3d0718Smx205022 } 16225a3d0718Smx205022 if ((new_mtu > ETHERMTU) && 16235a3d0718Smx205022 (!ngep->dev_spec_param.jumbo)) { 16245a3d0718Smx205022 err = EINVAL; 16255a3d0718Smx205022 break; 16265a3d0718Smx205022 } 16275a3d0718Smx205022 if (ngep->nge_mac_state == NGE_MAC_STARTED) { 16285a3d0718Smx205022 err = EBUSY; 16295a3d0718Smx205022 break; 16305a3d0718Smx205022 } 16315a3d0718Smx205022 16325a3d0718Smx205022 ngep->default_mtu = new_mtu; 16335a3d0718Smx205022 if (ngep->default_mtu > ETHERMTU && 16345a3d0718Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 16355a3d0718Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 16365a3d0718Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 16375a3d0718Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 16385a3d0718Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 16395a3d0718Smx205022 ngep->nge_split = NGE_SPLIT_256; 16405a3d0718Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 16415a3d0718Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 16425a3d0718Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 16435a3d0718Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 16445a3d0718Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 16455a3d0718Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 16465a3d0718Smx205022 ngep->nge_split = NGE_SPLIT_256; 16475a3d0718Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 16485a3d0718Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 16495a3d0718Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16505a3d0718Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16515a3d0718Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16525a3d0718Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16535a3d0718Smx205022 ngep->nge_split = NGE_SPLIT_256; 16545a3d0718Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 16555a3d0718Smx205022 ngep->default_mtu = NGE_MAX_MTU; 16565a3d0718Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16575a3d0718Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16585a3d0718Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16595a3d0718Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16605a3d0718Smx205022 ngep->nge_split = NGE_SPLIT_256; 16615a3d0718Smx205022 } else if (ngep->lowmem_mode != 0) { 16625a3d0718Smx205022 ngep->default_mtu = ETHERMTU; 16635a3d0718Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16645a3d0718Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 16655a3d0718Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 16665a3d0718Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 16675a3d0718Smx205022 ngep->nge_split = NGE_SPLIT_32; 16685a3d0718Smx205022 } else { 16695a3d0718Smx205022 ngep->default_mtu = ETHERMTU; 16705a3d0718Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16715a3d0718Smx205022 ngep->tx_desc = 16725a3d0718Smx205022 ngep->dev_spec_param.tx_desc_num; 16735a3d0718Smx205022 ngep->rx_desc = 16745a3d0718Smx205022 ngep->dev_spec_param.rx_desc_num; 16755a3d0718Smx205022 ngep->rx_buf = 16765a3d0718Smx205022 ngep->dev_spec_param.rx_desc_num * 2; 16775a3d0718Smx205022 ngep->nge_split = 16785a3d0718Smx205022 ngep->dev_spec_param.nge_split; 16795a3d0718Smx205022 } 16805a3d0718Smx205022 16815a3d0718Smx205022 err = mac_maxsdu_update(ngep->mh, ngep->default_mtu); 16825a3d0718Smx205022 16835a3d0718Smx205022 break; 16843fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 16855a3d0718Smx205022 bcopy(pr_val, &fl, sizeof (fl)); 16865a3d0718Smx205022 switch (fl) { 16875a3d0718Smx205022 default: 16885a3d0718Smx205022 err = ENOTSUP; 16895a3d0718Smx205022 break; 16905a3d0718Smx205022 case LINK_FLOWCTRL_NONE: 16915a3d0718Smx205022 ngep->param_adv_pause = 0; 16925a3d0718Smx205022 ngep->param_adv_asym_pause = 0; 16935a3d0718Smx205022 16945a3d0718Smx205022 ngep->param_link_rx_pause = B_FALSE; 16955a3d0718Smx205022 ngep->param_link_tx_pause = B_FALSE; 16965a3d0718Smx205022 break; 16975a3d0718Smx205022 case LINK_FLOWCTRL_RX: 16985a3d0718Smx205022 if (!((ngep->param_lp_pause == 0) && 16995a3d0718Smx205022 (ngep->param_lp_asym_pause == 1))) { 17005a3d0718Smx205022 err = EINVAL; 17015a3d0718Smx205022 break; 17025a3d0718Smx205022 } 17035a3d0718Smx205022 ngep->param_adv_pause = 1; 17045a3d0718Smx205022 ngep->param_adv_asym_pause = 1; 17055a3d0718Smx205022 17065a3d0718Smx205022 ngep->param_link_rx_pause = B_TRUE; 17075a3d0718Smx205022 ngep->param_link_tx_pause = B_FALSE; 17085a3d0718Smx205022 break; 17095a3d0718Smx205022 case LINK_FLOWCTRL_TX: 17105a3d0718Smx205022 if (!((ngep->param_lp_pause == 1) && 17115a3d0718Smx205022 (ngep->param_lp_asym_pause == 1))) { 17125a3d0718Smx205022 err = EINVAL; 17135a3d0718Smx205022 break; 17145a3d0718Smx205022 } 17155a3d0718Smx205022 ngep->param_adv_pause = 0; 17165a3d0718Smx205022 ngep->param_adv_asym_pause = 1; 17175a3d0718Smx205022 17185a3d0718Smx205022 ngep->param_link_rx_pause = B_FALSE; 17195a3d0718Smx205022 ngep->param_link_tx_pause = B_TRUE; 17205a3d0718Smx205022 break; 17215a3d0718Smx205022 case LINK_FLOWCTRL_BI: 17225a3d0718Smx205022 if (ngep->param_lp_pause != 1) { 17235a3d0718Smx205022 err = EINVAL; 17245a3d0718Smx205022 break; 17255a3d0718Smx205022 } 17265a3d0718Smx205022 ngep->param_adv_pause = 1; 17275a3d0718Smx205022 17285a3d0718Smx205022 ngep->param_link_rx_pause = B_TRUE; 17295a3d0718Smx205022 ngep->param_link_tx_pause = B_TRUE; 17305a3d0718Smx205022 break; 17315a3d0718Smx205022 } 17325a3d0718Smx205022 17335a3d0718Smx205022 if (err == 0) { 17345a3d0718Smx205022 (*ngep->physops->phys_update)(ngep); 17355a3d0718Smx205022 nge_chip_sync(ngep); 17365a3d0718Smx205022 } 17375a3d0718Smx205022 17385a3d0718Smx205022 break; 17393fd94f8cSam223141 case MAC_PROP_PRIVATE: 17405a3d0718Smx205022 err = nge_set_priv_prop(ngep, pr_name, pr_valsize, 17415a3d0718Smx205022 pr_val); 17425a3d0718Smx205022 if (err == 0) { 17435a3d0718Smx205022 (*ngep->physops->phys_update)(ngep); 17445a3d0718Smx205022 nge_chip_sync(ngep); 17455a3d0718Smx205022 } 17465a3d0718Smx205022 break; 17475a3d0718Smx205022 default: 17485a3d0718Smx205022 err = ENOTSUP; 17495a3d0718Smx205022 } 17505a3d0718Smx205022 mutex_exit(ngep->genlock); 17515a3d0718Smx205022 return (err); 17525a3d0718Smx205022 } 17535a3d0718Smx205022 17545a3d0718Smx205022 static int 17555a3d0718Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 1756*0dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val) 17575a3d0718Smx205022 { 17585a3d0718Smx205022 nge_t *ngep = barg; 17594045d941Ssowmini int err = 0; 17605a3d0718Smx205022 link_flowctrl_t fl; 17614045d941Ssowmini uint64_t speed; 1762afdda45fSVasumathi Sundaram - Sun Microsystems 17635a3d0718Smx205022 switch (pr_num) { 17643fd94f8cSam223141 case MAC_PROP_DUPLEX: 1765*0dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_duplex_t)); 17664045d941Ssowmini bcopy(&ngep->param_link_duplex, pr_val, 17674045d941Ssowmini sizeof (link_duplex_t)); 17685a3d0718Smx205022 break; 17693fd94f8cSam223141 case MAC_PROP_SPEED: 1770*0dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (uint64_t)); 17714045d941Ssowmini speed = ngep->param_link_speed * 1000000ull; 17724045d941Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 17735a3d0718Smx205022 break; 17743fd94f8cSam223141 case MAC_PROP_AUTONEG: 17755a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_adv_autoneg; 17765a3d0718Smx205022 break; 17773fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 1778*0dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_flowctrl_t)); 17795a3d0718Smx205022 if (ngep->param_link_rx_pause && 17805a3d0718Smx205022 !ngep->param_link_tx_pause) 17815a3d0718Smx205022 fl = LINK_FLOWCTRL_RX; 17825a3d0718Smx205022 17835a3d0718Smx205022 if (!ngep->param_link_rx_pause && 17845a3d0718Smx205022 !ngep->param_link_tx_pause) 17855a3d0718Smx205022 fl = LINK_FLOWCTRL_NONE; 17865a3d0718Smx205022 17875a3d0718Smx205022 if (!ngep->param_link_rx_pause && 17885a3d0718Smx205022 ngep->param_link_tx_pause) 17895a3d0718Smx205022 fl = LINK_FLOWCTRL_TX; 17905a3d0718Smx205022 17915a3d0718Smx205022 if (ngep->param_link_rx_pause && 17925a3d0718Smx205022 ngep->param_link_tx_pause) 17935a3d0718Smx205022 fl = LINK_FLOWCTRL_BI; 17945a3d0718Smx205022 bcopy(&fl, pr_val, sizeof (fl)); 17955a3d0718Smx205022 break; 17963fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP: 17975a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_adv_1000fdx; 17985a3d0718Smx205022 break; 17993fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 18005a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000fdx; 18015a3d0718Smx205022 break; 18023fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 18035a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_adv_1000hdx; 18045a3d0718Smx205022 break; 18053fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 18065a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000hdx; 18075a3d0718Smx205022 break; 18083fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 18095a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100fdx; 18105a3d0718Smx205022 break; 18113fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 18125a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_en_100fdx; 18135a3d0718Smx205022 break; 18143fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 18155a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100hdx; 18165a3d0718Smx205022 break; 18173fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 18185a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_en_100hdx; 18195a3d0718Smx205022 break; 18203fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 18215a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10fdx; 18225a3d0718Smx205022 break; 18233fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 18245a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_en_10fdx; 18255a3d0718Smx205022 break; 18263fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 18275a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10hdx; 18285a3d0718Smx205022 break; 18293fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 18305a3d0718Smx205022 *(uint8_t *)pr_val = ngep->param_en_10hdx; 18315a3d0718Smx205022 break; 18323fd94f8cSam223141 case MAC_PROP_ADV_100T4_CAP: 18333fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP: 18344045d941Ssowmini *(uint8_t *)pr_val = 0; 18354045d941Ssowmini break; 18363fd94f8cSam223141 case MAC_PROP_PRIVATE: 1837*0dc2366fSVenugopal Iyer err = nge_get_priv_prop(ngep, pr_name, 18384045d941Ssowmini pr_valsize, pr_val); 18395a3d0718Smx205022 break; 18405a3d0718Smx205022 default: 18415a3d0718Smx205022 err = ENOTSUP; 18425a3d0718Smx205022 } 18435a3d0718Smx205022 return (err); 18445a3d0718Smx205022 } 18455a3d0718Smx205022 1846*0dc2366fSVenugopal Iyer static void 1847*0dc2366fSVenugopal Iyer nge_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num, 1848*0dc2366fSVenugopal Iyer mac_prop_info_handle_t prh) 1849*0dc2366fSVenugopal Iyer { 1850*0dc2366fSVenugopal Iyer nge_t *ngep = barg; 1851*0dc2366fSVenugopal Iyer 1852*0dc2366fSVenugopal Iyer switch (pr_num) { 1853*0dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX: 1854*0dc2366fSVenugopal Iyer case MAC_PROP_SPEED: 1855*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000FDX_CAP: 1856*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000HDX_CAP: 1857*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP: 1858*0dc2366fSVenugopal Iyer case MAC_PROP_EN_1000HDX_CAP: 1859*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP: 1860*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP: 1861*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP: 1862*0dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP: 1863*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100T4_CAP: 1864*0dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1865*0dc2366fSVenugopal Iyer break; 1866*0dc2366fSVenugopal Iyer 1867*0dc2366fSVenugopal Iyer case MAC_PROP_EN_1000FDX_CAP: 1868*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP: 1869*0dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP: 1870*0dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP: 1871*0dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP: 1872*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 1); 1873*0dc2366fSVenugopal Iyer break; 1874*0dc2366fSVenugopal Iyer 1875*0dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG: 1876*0dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 1); 1877*0dc2366fSVenugopal Iyer break; 1878*0dc2366fSVenugopal Iyer 1879*0dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL: 1880*0dc2366fSVenugopal Iyer mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI); 1881*0dc2366fSVenugopal Iyer break; 1882*0dc2366fSVenugopal Iyer 1883*0dc2366fSVenugopal Iyer case MAC_PROP_MTU: 1884*0dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, ETHERMTU, 1885*0dc2366fSVenugopal Iyer ngep->dev_spec_param.jumbo ? NGE_MAX_MTU : ETHERMTU); 1886*0dc2366fSVenugopal Iyer break; 1887*0dc2366fSVenugopal Iyer 1888*0dc2366fSVenugopal Iyer case MAC_PROP_PRIVATE: { 1889*0dc2366fSVenugopal Iyer char valstr[64]; 1890*0dc2366fSVenugopal Iyer int value; 1891*0dc2366fSVenugopal Iyer 1892*0dc2366fSVenugopal Iyer bzero(valstr, sizeof (valstr)); 1893*0dc2366fSVenugopal Iyer if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 1894*0dc2366fSVenugopal Iyer value = NGE_TX_COPY_SIZE; 1895*0dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 1896*0dc2366fSVenugopal Iyer value = NGE_RX_COPY_SIZE; 1897*0dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_recv_max_packet") == 0) { 1898*0dc2366fSVenugopal Iyer value = 128; 1899*0dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_poll_quiet_time") == 0) { 1900*0dc2366fSVenugopal Iyer value = NGE_POLL_QUIET_TIME; 1901*0dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_poll_busy_time") == 0) { 1902*0dc2366fSVenugopal Iyer value = NGE_POLL_BUSY_TIME; 1903*0dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 1904*0dc2366fSVenugopal Iyer value = 1; 1905*0dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 1906*0dc2366fSVenugopal Iyer value = 8; 1907*0dc2366fSVenugopal Iyer } else { 1908*0dc2366fSVenugopal Iyer return; 1909*0dc2366fSVenugopal Iyer } 1910*0dc2366fSVenugopal Iyer 1911*0dc2366fSVenugopal Iyer (void) snprintf(valstr, sizeof (valstr), "%d", value); 1912*0dc2366fSVenugopal Iyer } 1913*0dc2366fSVenugopal Iyer } 1914*0dc2366fSVenugopal Iyer 1915*0dc2366fSVenugopal Iyer } 1916*0dc2366fSVenugopal Iyer 19175a3d0718Smx205022 /* ARGSUSED */ 19185a3d0718Smx205022 static int 19195a3d0718Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize, 19205a3d0718Smx205022 const void *pr_val) 19215a3d0718Smx205022 { 19225a3d0718Smx205022 int err = 0; 19235a3d0718Smx205022 long result; 19245a3d0718Smx205022 19255a3d0718Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 19265a3d0718Smx205022 if (pr_val == NULL) { 19275a3d0718Smx205022 err = EINVAL; 19285a3d0718Smx205022 return (err); 19295a3d0718Smx205022 } 19305a3d0718Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19315a3d0718Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19325a3d0718Smx205022 err = EINVAL; 19335a3d0718Smx205022 } else { 19345a3d0718Smx205022 ngep->param_txbcopy_threshold = (uint32_t)result; 19355a3d0718Smx205022 goto reprogram; 19365a3d0718Smx205022 } 19375a3d0718Smx205022 return (err); 19385a3d0718Smx205022 } 19395a3d0718Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 19405a3d0718Smx205022 if (pr_val == NULL) { 19415a3d0718Smx205022 err = EINVAL; 19425a3d0718Smx205022 return (err); 19435a3d0718Smx205022 } 19445a3d0718Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19455a3d0718Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19465a3d0718Smx205022 err = EINVAL; 19475a3d0718Smx205022 } else { 19485a3d0718Smx205022 ngep->param_rxbcopy_threshold = (uint32_t)result; 19495a3d0718Smx205022 goto reprogram; 19505a3d0718Smx205022 } 19515a3d0718Smx205022 return (err); 19525a3d0718Smx205022 } 19535a3d0718Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 19545a3d0718Smx205022 if (pr_val == NULL) { 19555a3d0718Smx205022 err = EINVAL; 19565a3d0718Smx205022 return (err); 19575a3d0718Smx205022 } 19585a3d0718Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19595a3d0718Smx205022 if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 19605a3d0718Smx205022 err = EINVAL; 19615a3d0718Smx205022 } else { 19625a3d0718Smx205022 ngep->param_recv_max_packet = (uint32_t)result; 19635a3d0718Smx205022 goto reprogram; 19645a3d0718Smx205022 } 19655a3d0718Smx205022 return (err); 19665a3d0718Smx205022 } 19675a3d0718Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 19685a3d0718Smx205022 if (pr_val == NULL) { 19695a3d0718Smx205022 err = EINVAL; 19705a3d0718Smx205022 return (err); 19715a3d0718Smx205022 } 19725a3d0718Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19735a3d0718Smx205022 if (result < 0 || result > 10000) { 19745a3d0718Smx205022 err = EINVAL; 19755a3d0718Smx205022 } else { 19765a3d0718Smx205022 ngep->param_poll_quiet_time = (uint32_t)result; 19775a3d0718Smx205022 goto reprogram; 19785a3d0718Smx205022 } 19795a3d0718Smx205022 return (err); 19805a3d0718Smx205022 } 19815a3d0718Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 19825a3d0718Smx205022 if (pr_val == NULL) { 19835a3d0718Smx205022 err = EINVAL; 19845a3d0718Smx205022 return (err); 19855a3d0718Smx205022 } 19865a3d0718Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19875a3d0718Smx205022 if (result < 0 || result > 10000) { 19885a3d0718Smx205022 err = EINVAL; 19895a3d0718Smx205022 } else { 19905a3d0718Smx205022 ngep->param_poll_busy_time = (uint32_t)result; 19915a3d0718Smx205022 goto reprogram; 19925a3d0718Smx205022 } 19935a3d0718Smx205022 return (err); 19945a3d0718Smx205022 } 19955a3d0718Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 19965a3d0718Smx205022 if (pr_val == NULL) { 19975a3d0718Smx205022 err = EINVAL; 19985a3d0718Smx205022 return (err); 19995a3d0718Smx205022 } 20005a3d0718Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20014045d941Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20025a3d0718Smx205022 err = EINVAL; 20035a3d0718Smx205022 } else { 20045a3d0718Smx205022 ngep->param_rx_intr_hwater = (uint32_t)result; 20055a3d0718Smx205022 goto reprogram; 20065a3d0718Smx205022 } 20075a3d0718Smx205022 return (err); 20085a3d0718Smx205022 } 20095a3d0718Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 20105a3d0718Smx205022 if (pr_val == NULL) { 20115a3d0718Smx205022 err = EINVAL; 20125a3d0718Smx205022 return (err); 20135a3d0718Smx205022 } 20145a3d0718Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20154045d941Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20165a3d0718Smx205022 err = EINVAL; 20175a3d0718Smx205022 } else { 20185a3d0718Smx205022 ngep->param_rx_intr_lwater = (uint32_t)result; 20195a3d0718Smx205022 goto reprogram; 20205a3d0718Smx205022 } 20215a3d0718Smx205022 return (err); 20225a3d0718Smx205022 } 20235a3d0718Smx205022 err = ENOTSUP; 20245a3d0718Smx205022 return (err); 20255a3d0718Smx205022 20265a3d0718Smx205022 reprogram: 20275a3d0718Smx205022 if (err == 0) { 20285a3d0718Smx205022 (*ngep->physops->phys_update)(ngep); 20295a3d0718Smx205022 nge_chip_sync(ngep); 20305a3d0718Smx205022 } 20315a3d0718Smx205022 20325a3d0718Smx205022 return (err); 20335a3d0718Smx205022 } 20345a3d0718Smx205022 20355a3d0718Smx205022 static int 2036*0dc2366fSVenugopal Iyer nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize, 2037*0dc2366fSVenugopal Iyer void *pr_val) 20385a3d0718Smx205022 { 20395a3d0718Smx205022 int err = ENOTSUP; 20404045d941Ssowmini int value; 20415a3d0718Smx205022 20425a3d0718Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 2043*0dc2366fSVenugopal Iyer value = ngep->param_txbcopy_threshold; 20445a3d0718Smx205022 err = 0; 20455a3d0718Smx205022 goto done; 20465a3d0718Smx205022 } 20475a3d0718Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 2048*0dc2366fSVenugopal Iyer value = ngep->param_rxbcopy_threshold; 20495a3d0718Smx205022 err = 0; 20505a3d0718Smx205022 goto done; 20515a3d0718Smx205022 } 20525a3d0718Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 2053*0dc2366fSVenugopal Iyer value = ngep->param_recv_max_packet; 20545a3d0718Smx205022 err = 0; 20555a3d0718Smx205022 goto done; 20565a3d0718Smx205022 } 20575a3d0718Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 2058*0dc2366fSVenugopal Iyer value = ngep->param_poll_quiet_time; 20595a3d0718Smx205022 err = 0; 20605a3d0718Smx205022 goto done; 20615a3d0718Smx205022 } 20625a3d0718Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 2063*0dc2366fSVenugopal Iyer value = ngep->param_poll_busy_time; 20645a3d0718Smx205022 err = 0; 20655a3d0718Smx205022 goto done; 20665a3d0718Smx205022 } 20675a3d0718Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 2068*0dc2366fSVenugopal Iyer value = ngep->param_rx_intr_hwater; 20695a3d0718Smx205022 err = 0; 20705a3d0718Smx205022 goto done; 20715a3d0718Smx205022 } 20725a3d0718Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 2073*0dc2366fSVenugopal Iyer value = ngep->param_rx_intr_lwater; 20745a3d0718Smx205022 err = 0; 20755a3d0718Smx205022 goto done; 20765a3d0718Smx205022 } 20775a3d0718Smx205022 20785a3d0718Smx205022 done: 20795a3d0718Smx205022 if (err == 0) { 20804045d941Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 20815a3d0718Smx205022 } 20825a3d0718Smx205022 return (err); 20835a3d0718Smx205022 } 20845a3d0718Smx205022 20856f3e57acSmx205022 /* ARGSUSED */ 20866f3e57acSmx205022 static boolean_t 20876f3e57acSmx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 20886f3e57acSmx205022 { 20896f3e57acSmx205022 nge_t *ngep = arg; 20906f3e57acSmx205022 nge_dev_spec_param_t *dev_param_p; 20916f3e57acSmx205022 20926f3e57acSmx205022 dev_param_p = &ngep->dev_spec_param; 20936f3e57acSmx205022 20946f3e57acSmx205022 switch (cap) { 20956f3e57acSmx205022 case MAC_CAPAB_HCKSUM: { 20966f3e57acSmx205022 uint32_t *hcksum_txflags = cap_data; 20976f3e57acSmx205022 20986f3e57acSmx205022 if (dev_param_p->tx_hw_checksum) { 20996f3e57acSmx205022 *hcksum_txflags = dev_param_p->tx_hw_checksum; 21006f3e57acSmx205022 } else 21016f3e57acSmx205022 return (B_FALSE); 21026f3e57acSmx205022 break; 21036f3e57acSmx205022 } 21046f3e57acSmx205022 default: 21056f3e57acSmx205022 return (B_FALSE); 21066f3e57acSmx205022 } 21076f3e57acSmx205022 return (B_TRUE); 21086f3e57acSmx205022 } 21096f3e57acSmx205022 21106f3e57acSmx205022 #undef NGE_DBG 21116f3e57acSmx205022 #define NGE_DBG NGE_DBG_INIT /* debug flag for this code */ 21126f3e57acSmx205022 int 21136f3e57acSmx205022 nge_restart(nge_t *ngep) 21146f3e57acSmx205022 { 21156f3e57acSmx205022 int err = 0; 211619397407SSherry Moore err = nge_reset_dev(ngep); 21176de4f663Smx205022 /* write back the promisc setting */ 21186de4f663Smx205022 ngep->promisc = ngep->record_promisc; 2119c322ff79Smx205022 nge_chip_sync(ngep); 21202d58516dSmx205022 if (!err) 21212d58516dSmx205022 err = nge_chip_start(ngep); 21226f3e57acSmx205022 21236f3e57acSmx205022 if (err) { 21246f3e57acSmx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 21256f3e57acSmx205022 return (DDI_FAILURE); 21266f3e57acSmx205022 } else { 21276f3e57acSmx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 21286f3e57acSmx205022 return (DDI_SUCCESS); 21296f3e57acSmx205022 } 21306f3e57acSmx205022 } 21316f3e57acSmx205022 21326f3e57acSmx205022 void 21336f3e57acSmx205022 nge_wake_factotum(nge_t *ngep) 21346f3e57acSmx205022 { 21356f3e57acSmx205022 mutex_enter(ngep->softlock); 21366f3e57acSmx205022 if (ngep->factotum_flag == 0) { 21376f3e57acSmx205022 ngep->factotum_flag = 1; 21386f3e57acSmx205022 (void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL); 21396f3e57acSmx205022 } 21406f3e57acSmx205022 mutex_exit(ngep->softlock); 21416f3e57acSmx205022 } 21426f3e57acSmx205022 214351fc88a8SWinson Wang - Sun Microsystems - Beijing China void 214451fc88a8SWinson Wang - Sun Microsystems - Beijing China nge_interrupt_optimize(nge_t *ngep) 214551fc88a8SWinson Wang - Sun Microsystems - Beijing China { 214651fc88a8SWinson Wang - Sun Microsystems - Beijing China uint32_t tx_pkts; 214751fc88a8SWinson Wang - Sun Microsystems - Beijing China tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last; 214851fc88a8SWinson Wang - Sun Microsystems - Beijing China ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count; 214951fc88a8SWinson Wang - Sun Microsystems - Beijing China if ((tx_pkts > NGE_POLL_TUNE) && 215051fc88a8SWinson Wang - Sun Microsystems - Beijing China (tx_pkts <= NGE_POLL_MAX)) 215151fc88a8SWinson Wang - Sun Microsystems - Beijing China ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER); 215251fc88a8SWinson Wang - Sun Microsystems - Beijing China else 215351fc88a8SWinson Wang - Sun Microsystems - Beijing China ngep->tfint_threshold = NGE_TFINT_DEFAULT; 215451fc88a8SWinson Wang - Sun Microsystems - Beijing China } 215551fc88a8SWinson Wang - Sun Microsystems - Beijing China 21566f3e57acSmx205022 /* 21576f3e57acSmx205022 * High-level cyclic handler 21586f3e57acSmx205022 * 21596f3e57acSmx205022 * This routine schedules a (low-level) softint callback to the 21606f3e57acSmx205022 * factotum. 21616f3e57acSmx205022 */ 21626f3e57acSmx205022 21636f3e57acSmx205022 static void 21646f3e57acSmx205022 nge_chip_cyclic(void *arg) 21656f3e57acSmx205022 { 21666f3e57acSmx205022 nge_t *ngep; 21676f3e57acSmx205022 21686f3e57acSmx205022 ngep = (nge_t *)arg; 21696f3e57acSmx205022 21706f3e57acSmx205022 switch (ngep->nge_chip_state) { 21716f3e57acSmx205022 default: 21726f3e57acSmx205022 return; 21736f3e57acSmx205022 21746f3e57acSmx205022 case NGE_CHIP_RUNNING: 217551fc88a8SWinson Wang - Sun Microsystems - Beijing China nge_interrupt_optimize(ngep); 21766f3e57acSmx205022 break; 21776f3e57acSmx205022 21786f3e57acSmx205022 case NGE_CHIP_FAULT: 21796f3e57acSmx205022 case NGE_CHIP_ERROR: 21806f3e57acSmx205022 break; 21816f3e57acSmx205022 } 21826f3e57acSmx205022 21836f3e57acSmx205022 nge_wake_factotum(ngep); 21846f3e57acSmx205022 } 21856f3e57acSmx205022 2186d635b452SWinson Wang - Sun Microsystems - Beijing China /* 2187d635b452SWinson Wang - Sun Microsystems - Beijing China * Get/Release semaphore of SMU 2188d635b452SWinson Wang - Sun Microsystems - Beijing China * For SMU enabled chipset 2189d635b452SWinson Wang - Sun Microsystems - Beijing China * When nge driver is attached, driver should acquire 2190d635b452SWinson Wang - Sun Microsystems - Beijing China * semaphore before PHY init and accessing MAC registers. 2191d635b452SWinson Wang - Sun Microsystems - Beijing China * When nge driver is unattached, driver should release 2192d635b452SWinson Wang - Sun Microsystems - Beijing China * semaphore. 2193d635b452SWinson Wang - Sun Microsystems - Beijing China */ 2194d635b452SWinson Wang - Sun Microsystems - Beijing China 2195d635b452SWinson Wang - Sun Microsystems - Beijing China static int 2196d635b452SWinson Wang - Sun Microsystems - Beijing China nge_smu_sema(nge_t *ngep, boolean_t acquire) 2197d635b452SWinson Wang - Sun Microsystems - Beijing China { 2198d635b452SWinson Wang - Sun Microsystems - Beijing China nge_tx_en tx_en; 2199d635b452SWinson Wang - Sun Microsystems - Beijing China uint32_t tries; 2200d635b452SWinson Wang - Sun Microsystems - Beijing China 2201d635b452SWinson Wang - Sun Microsystems - Beijing China if (acquire) { 2202d635b452SWinson Wang - Sun Microsystems - Beijing China for (tries = 0; tries < 5; tries++) { 2203d635b452SWinson Wang - Sun Microsystems - Beijing China tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 2204d635b452SWinson Wang - Sun Microsystems - Beijing China if (tx_en.bits.smu2mac == NGE_SMU_FREE) 2205d635b452SWinson Wang - Sun Microsystems - Beijing China break; 2206d635b452SWinson Wang - Sun Microsystems - Beijing China delay(drv_usectohz(1000000)); 2207d635b452SWinson Wang - Sun Microsystems - Beijing China } 2208d635b452SWinson Wang - Sun Microsystems - Beijing China if (tx_en.bits.smu2mac != NGE_SMU_FREE) 2209d635b452SWinson Wang - Sun Microsystems - Beijing China return (DDI_FAILURE); 2210d635b452SWinson Wang - Sun Microsystems - Beijing China for (tries = 0; tries < 5; tries++) { 2211d635b452SWinson Wang - Sun Microsystems - Beijing China tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 2212d635b452SWinson Wang - Sun Microsystems - Beijing China tx_en.bits.mac2smu = NGE_SMU_GET; 2213d635b452SWinson Wang - Sun Microsystems - Beijing China nge_reg_put32(ngep, NGE_TX_EN, tx_en.val); 2214d635b452SWinson Wang - Sun Microsystems - Beijing China tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 2215d635b452SWinson Wang - Sun Microsystems - Beijing China 2216d635b452SWinson Wang - Sun Microsystems - Beijing China if (tx_en.bits.mac2smu == NGE_SMU_GET && 2217d635b452SWinson Wang - Sun Microsystems - Beijing China tx_en.bits.smu2mac == NGE_SMU_FREE) 2218d635b452SWinson Wang - Sun Microsystems - Beijing China return (DDI_SUCCESS); 2219d635b452SWinson Wang - Sun Microsystems - Beijing China drv_usecwait(10); 2220d635b452SWinson Wang - Sun Microsystems - Beijing China } 2221d635b452SWinson Wang - Sun Microsystems - Beijing China return (DDI_FAILURE); 2222d635b452SWinson Wang - Sun Microsystems - Beijing China } else 2223d635b452SWinson Wang - Sun Microsystems - Beijing China nge_reg_put32(ngep, NGE_TX_EN, 0x0); 2224d635b452SWinson Wang - Sun Microsystems - Beijing China 2225d635b452SWinson Wang - Sun Microsystems - Beijing China return (DDI_SUCCESS); 2226d635b452SWinson Wang - Sun Microsystems - Beijing China 2227d635b452SWinson Wang - Sun Microsystems - Beijing China } 22286f3e57acSmx205022 static void 22296f3e57acSmx205022 nge_unattach(nge_t *ngep) 22306f3e57acSmx205022 { 22316f3e57acSmx205022 send_ring_t *srp; 22326f3e57acSmx205022 buff_ring_t *brp; 22336f3e57acSmx205022 22346f3e57acSmx205022 srp = ngep->send; 22356f3e57acSmx205022 brp = ngep->buff; 22366f3e57acSmx205022 NGE_TRACE(("nge_unattach($%p)", (void *)ngep)); 22376f3e57acSmx205022 22386f3e57acSmx205022 /* 22396f3e57acSmx205022 * Flag that no more activity may be initiated 22406f3e57acSmx205022 */ 22416f3e57acSmx205022 ngep->progress &= ~PROGRESS_READY; 22426f3e57acSmx205022 ngep->nge_mac_state = NGE_MAC_UNATTACH; 22436f3e57acSmx205022 22446f3e57acSmx205022 /* 22456f3e57acSmx205022 * Quiesce the PHY and MAC (leave it reset but still powered). 22466f3e57acSmx205022 * Clean up and free all NGE data structures 22476f3e57acSmx205022 */ 22486f3e57acSmx205022 if (ngep->periodic_id != NULL) { 22496f3e57acSmx205022 ddi_periodic_delete(ngep->periodic_id); 22506f3e57acSmx205022 ngep->periodic_id = NULL; 22516f3e57acSmx205022 } 22526f3e57acSmx205022 22536f3e57acSmx205022 if (ngep->progress & PROGRESS_KSTATS) 22546f3e57acSmx205022 nge_fini_kstats(ngep); 22556f3e57acSmx205022 22566f3e57acSmx205022 if (ngep->progress & PROGRESS_HWINT) { 22576f3e57acSmx205022 mutex_enter(ngep->genlock); 22586f3e57acSmx205022 nge_restore_mac_addr(ngep); 22596f3e57acSmx205022 (void) nge_chip_stop(ngep, B_FALSE); 2260d635b452SWinson Wang - Sun Microsystems - Beijing China if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 2261d635b452SWinson Wang - Sun Microsystems - Beijing China ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 2262d635b452SWinson Wang - Sun Microsystems - Beijing China (void) nge_smu_sema(ngep, B_FALSE); 2263d635b452SWinson Wang - Sun Microsystems - Beijing China } 22646f3e57acSmx205022 mutex_exit(ngep->genlock); 22656f3e57acSmx205022 } 22666f3e57acSmx205022 22676f3e57acSmx205022 if (ngep->progress & PROGRESS_SWINT) 22686f3e57acSmx205022 nge_rem_intrs(ngep); 22696f3e57acSmx205022 22706f3e57acSmx205022 if (ngep->progress & PROGRESS_FACTOTUM) 22716f3e57acSmx205022 (void) ddi_intr_remove_softint(ngep->factotum_hdl); 22726f3e57acSmx205022 22736f3e57acSmx205022 if (ngep->progress & PROGRESS_RESCHED) 22746f3e57acSmx205022 (void) ddi_intr_remove_softint(ngep->resched_hdl); 22756f3e57acSmx205022 22766f3e57acSmx205022 if (ngep->progress & PROGRESS_INTR) { 22776f3e57acSmx205022 mutex_destroy(srp->tx_lock); 22786f3e57acSmx205022 mutex_destroy(srp->tc_lock); 22796f3e57acSmx205022 mutex_destroy(&srp->dmah_lock); 22806f3e57acSmx205022 mutex_destroy(brp->recycle_lock); 22816f3e57acSmx205022 22826f3e57acSmx205022 mutex_destroy(ngep->genlock); 22836f3e57acSmx205022 mutex_destroy(ngep->softlock); 22846f3e57acSmx205022 rw_destroy(ngep->rwlock); 22856f3e57acSmx205022 } 22866f3e57acSmx205022 22876f3e57acSmx205022 if (ngep->progress & PROGRESS_REGS) 22886f3e57acSmx205022 ddi_regs_map_free(&ngep->io_handle); 22896f3e57acSmx205022 22906f3e57acSmx205022 if (ngep->progress & PROGRESS_CFG) 22916f3e57acSmx205022 pci_config_teardown(&ngep->cfg_handle); 22926f3e57acSmx205022 22936f3e57acSmx205022 ddi_remove_minor_node(ngep->devinfo, NULL); 22946f3e57acSmx205022 22956f3e57acSmx205022 kmem_free(ngep, sizeof (*ngep)); 22966f3e57acSmx205022 } 22976f3e57acSmx205022 22986f3e57acSmx205022 static int 22996f3e57acSmx205022 nge_resume(dev_info_t *devinfo) 23006f3e57acSmx205022 { 23016f3e57acSmx205022 nge_t *ngep; 23026f3e57acSmx205022 chip_info_t *infop; 23032d58516dSmx205022 int err; 23046f3e57acSmx205022 23056f3e57acSmx205022 ASSERT(devinfo != NULL); 23066f3e57acSmx205022 23076f3e57acSmx205022 ngep = ddi_get_driver_private(devinfo); 23082d58516dSmx205022 err = 0; 23092d58516dSmx205022 23106f3e57acSmx205022 /* 23116f3e57acSmx205022 * If there are state inconsistancies, this is bad. Returning 23126f3e57acSmx205022 * DDI_FAILURE here will eventually cause the machine to panic, 23136f3e57acSmx205022 * so it is best done here so that there is a possibility of 23146f3e57acSmx205022 * debugging the problem. 23156f3e57acSmx205022 */ 23166f3e57acSmx205022 if (ngep == NULL) 23176f3e57acSmx205022 cmn_err(CE_PANIC, 23186f3e57acSmx205022 "nge: ngep returned from ddi_get_driver_private was NULL"); 23196f3e57acSmx205022 infop = (chip_info_t *)&ngep->chipinfo; 23206f3e57acSmx205022 23216f3e57acSmx205022 if (ngep->devinfo != devinfo) 23226f3e57acSmx205022 cmn_err(CE_PANIC, 23232d58516dSmx205022 "nge: passed devinfo not the same as saved devinfo"); 23246f3e57acSmx205022 23252d58516dSmx205022 mutex_enter(ngep->genlock); 23262d58516dSmx205022 rw_enter(ngep->rwlock, RW_WRITER); 23276f3e57acSmx205022 23286f3e57acSmx205022 /* 23296f3e57acSmx205022 * Fetch the config space. Even though we have most of it cached, 23306f3e57acSmx205022 * some values *might* change across a suspend/resume. 23316f3e57acSmx205022 */ 23326f3e57acSmx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 23336f3e57acSmx205022 23346f3e57acSmx205022 /* 23352d58516dSmx205022 * Only in one case, this conditional branch can be executed: the port 23362d58516dSmx205022 * hasn't been plumbed. 23376f3e57acSmx205022 */ 23382d58516dSmx205022 if (ngep->suspended == B_FALSE) { 23392d58516dSmx205022 rw_exit(ngep->rwlock); 23402d58516dSmx205022 mutex_exit(ngep->genlock); 23412d58516dSmx205022 return (DDI_SUCCESS); 23422d58516dSmx205022 } 23432d58516dSmx205022 23442d58516dSmx205022 nge_tx_recycle_all(ngep); 23452d58516dSmx205022 err = nge_reinit_ring(ngep); 23462d58516dSmx205022 if (!err) { 23472d58516dSmx205022 err = nge_chip_reset(ngep); 23482d58516dSmx205022 if (!err) 23492d58516dSmx205022 err = nge_chip_start(ngep); 23502d58516dSmx205022 } 23512d58516dSmx205022 23522d58516dSmx205022 if (err) { 23536f3e57acSmx205022 /* 23546f3e57acSmx205022 * We note the failure, but return success, as the 23556f3e57acSmx205022 * system is still usable without this controller. 23566f3e57acSmx205022 */ 23576f3e57acSmx205022 cmn_err(CE_WARN, "nge: resume: failed to restart controller"); 23582d58516dSmx205022 } else { 23592d58516dSmx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 23606f3e57acSmx205022 } 23612d58516dSmx205022 ngep->suspended = B_FALSE; 23622d58516dSmx205022 23632d58516dSmx205022 rw_exit(ngep->rwlock); 23642d58516dSmx205022 mutex_exit(ngep->genlock); 23652d58516dSmx205022 23666f3e57acSmx205022 return (DDI_SUCCESS); 23676f3e57acSmx205022 } 23686f3e57acSmx205022 23696f3e57acSmx205022 /* 23706f3e57acSmx205022 * attach(9E) -- Attach a device to the system 23716f3e57acSmx205022 * 23726f3e57acSmx205022 * Called once for each board successfully probed. 23736f3e57acSmx205022 */ 23746f3e57acSmx205022 static int 23756f3e57acSmx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 23766f3e57acSmx205022 { 23776f3e57acSmx205022 int err; 23786f3e57acSmx205022 int i; 23796f3e57acSmx205022 int instance; 23806f3e57acSmx205022 caddr_t regs; 23816f3e57acSmx205022 nge_t *ngep; 23826f3e57acSmx205022 chip_info_t *infop; 23836f3e57acSmx205022 mac_register_t *macp; 23846f3e57acSmx205022 23856f3e57acSmx205022 switch (cmd) { 23866f3e57acSmx205022 default: 23876f3e57acSmx205022 return (DDI_FAILURE); 23886f3e57acSmx205022 23896f3e57acSmx205022 case DDI_RESUME: 23906f3e57acSmx205022 return (nge_resume(devinfo)); 23916f3e57acSmx205022 23926f3e57acSmx205022 case DDI_ATTACH: 23936f3e57acSmx205022 break; 23946f3e57acSmx205022 } 23956f3e57acSmx205022 23966f3e57acSmx205022 ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP); 23976f3e57acSmx205022 instance = ddi_get_instance(devinfo); 23986f3e57acSmx205022 ddi_set_driver_private(devinfo, ngep); 23996f3e57acSmx205022 ngep->devinfo = devinfo; 24006f3e57acSmx205022 24016f3e57acSmx205022 (void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d", 24026f3e57acSmx205022 NGE_DRIVER_NAME, instance); 24036f3e57acSmx205022 err = pci_config_setup(devinfo, &ngep->cfg_handle); 24046f3e57acSmx205022 if (err != DDI_SUCCESS) { 24056f3e57acSmx205022 nge_problem(ngep, "nge_attach: pci_config_setup() failed"); 24066f3e57acSmx205022 goto attach_fail; 24076f3e57acSmx205022 } 24084045d941Ssowmini /* 24094045d941Ssowmini * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy 24104045d941Ssowmini * thresholds. Bounds: min 0, max NGE_MAX_SDU 24114045d941Ssowmini */ 24124045d941Ssowmini ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE; 24134045d941Ssowmini ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE; 24144045d941Ssowmini 24154045d941Ssowmini /* 24164045d941Ssowmini * param_recv_max_packet is max packet received per interupt. 24174045d941Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024 24184045d941Ssowmini */ 24194045d941Ssowmini ngep->param_recv_max_packet = 128; 24204045d941Ssowmini 24214045d941Ssowmini /* 24224045d941Ssowmini * param_poll_quiet_time and param_poll_busy_time are quiet/busy time 24234045d941Ssowmini * switch from per packet interrupt to polling interrupt. 24244045d941Ssowmini * Bounds: min 0, max 10000 24254045d941Ssowmini */ 24264045d941Ssowmini ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME; 24274045d941Ssowmini ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME; 242851fc88a8SWinson Wang - Sun Microsystems - Beijing China ngep->tfint_threshold = NGE_TFINT_DEFAULT; 242951fc88a8SWinson Wang - Sun Microsystems - Beijing China ngep->poll = B_FALSE; 243051fc88a8SWinson Wang - Sun Microsystems - Beijing China ngep->ch_intr_mode = B_FALSE; 24314045d941Ssowmini 24324045d941Ssowmini /* 24334045d941Ssowmini * param_rx_intr_hwater/param_rx_intr_lwater: ackets received 24344045d941Ssowmini * to trigger the poll_quiet_time/poll_busy_time counter. 24354045d941Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024. 24364045d941Ssowmini */ 24374045d941Ssowmini ngep->param_rx_intr_hwater = 1; 24384045d941Ssowmini ngep->param_rx_intr_lwater = 8; 24394045d941Ssowmini 24404045d941Ssowmini 24416f3e57acSmx205022 infop = (chip_info_t *)&ngep->chipinfo; 24426f3e57acSmx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 24436f3e57acSmx205022 nge_init_dev_spec_param(ngep); 24446f3e57acSmx205022 nge_get_props(ngep); 24456f3e57acSmx205022 ngep->progress |= PROGRESS_CFG; 24466f3e57acSmx205022 24476f3e57acSmx205022 err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER, 24486f3e57acSmx205022 ®s, 0, 0, &nge_reg_accattr, &ngep->io_handle); 24496f3e57acSmx205022 if (err != DDI_SUCCESS) { 24506f3e57acSmx205022 nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed"); 24516f3e57acSmx205022 goto attach_fail; 24526f3e57acSmx205022 } 24536f3e57acSmx205022 ngep->io_regs = regs; 24546f3e57acSmx205022 ngep->progress |= PROGRESS_REGS; 24556f3e57acSmx205022 24566f3e57acSmx205022 err = nge_register_intrs_and_init_locks(ngep); 24576f3e57acSmx205022 if (err != DDI_SUCCESS) { 24586f3e57acSmx205022 nge_problem(ngep, "nge_attach:" 24596f3e57acSmx205022 " register intrs and init locks failed"); 24606f3e57acSmx205022 goto attach_fail; 24616f3e57acSmx205022 } 24626f3e57acSmx205022 nge_init_ring_param_lock(ngep); 24636f3e57acSmx205022 ngep->progress |= PROGRESS_INTR; 24646f3e57acSmx205022 24656f3e57acSmx205022 mutex_enter(ngep->genlock); 24666f3e57acSmx205022 2467d635b452SWinson Wang - Sun Microsystems - Beijing China if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 2468d635b452SWinson Wang - Sun Microsystems - Beijing China ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 2469d635b452SWinson Wang - Sun Microsystems - Beijing China err = nge_smu_sema(ngep, B_TRUE); 2470d635b452SWinson Wang - Sun Microsystems - Beijing China if (err != DDI_SUCCESS) { 2471d635b452SWinson Wang - Sun Microsystems - Beijing China nge_problem(ngep, "nge_attach: nge_smu_sema() failed"); 2472d635b452SWinson Wang - Sun Microsystems - Beijing China goto attach_fail; 2473d635b452SWinson Wang - Sun Microsystems - Beijing China } 2474d635b452SWinson Wang - Sun Microsystems - Beijing China } 24756f3e57acSmx205022 /* 24766f3e57acSmx205022 * Initialise link state variables 24776f3e57acSmx205022 * Stop, reset & reinitialise the chip. 24786f3e57acSmx205022 * Initialise the (internal) PHY. 24796f3e57acSmx205022 */ 24806f3e57acSmx205022 nge_phys_init(ngep); 2481d27d4a13SMiles Xu, Sun Microsystems ngep->nge_chip_state = NGE_CHIP_INITIAL; 24826f3e57acSmx205022 err = nge_chip_reset(ngep); 24836f3e57acSmx205022 if (err != DDI_SUCCESS) { 24846f3e57acSmx205022 nge_problem(ngep, "nge_attach: nge_chip_reset() failed"); 24856f3e57acSmx205022 mutex_exit(ngep->genlock); 24866f3e57acSmx205022 goto attach_fail; 24876f3e57acSmx205022 } 24886f3e57acSmx205022 nge_chip_sync(ngep); 24896f3e57acSmx205022 24906f3e57acSmx205022 /* 24916f3e57acSmx205022 * Now that mutex locks are initialized, enable interrupts. 24926f3e57acSmx205022 */ 24936f3e57acSmx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 24946f3e57acSmx205022 /* Call ddi_intr_block_enable() for MSI interrupts */ 24956f3e57acSmx205022 (void) ddi_intr_block_enable(ngep->htable, 24966f3e57acSmx205022 ngep->intr_actual_cnt); 24976f3e57acSmx205022 } else { 24986f3e57acSmx205022 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 24996f3e57acSmx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 25006f3e57acSmx205022 (void) ddi_intr_enable(ngep->htable[i]); 25016f3e57acSmx205022 } 25026f3e57acSmx205022 } 25036f3e57acSmx205022 25046f3e57acSmx205022 ngep->link_state = LINK_STATE_UNKNOWN; 25056f3e57acSmx205022 ngep->progress |= PROGRESS_HWINT; 25066f3e57acSmx205022 25076f3e57acSmx205022 /* 25086f3e57acSmx205022 * Register NDD-tweakable parameters 25096f3e57acSmx205022 */ 25106f3e57acSmx205022 if (nge_nd_init(ngep)) { 25116f3e57acSmx205022 nge_problem(ngep, "nge_attach: nge_nd_init() failed"); 25126f3e57acSmx205022 mutex_exit(ngep->genlock); 25136f3e57acSmx205022 goto attach_fail; 25146f3e57acSmx205022 } 25156f3e57acSmx205022 ngep->progress |= PROGRESS_NDD; 25166f3e57acSmx205022 25176f3e57acSmx205022 /* 25186f3e57acSmx205022 * Create & initialise named kstats 25196f3e57acSmx205022 */ 25206f3e57acSmx205022 nge_init_kstats(ngep, instance); 25216f3e57acSmx205022 ngep->progress |= PROGRESS_KSTATS; 25226f3e57acSmx205022 25236f3e57acSmx205022 mutex_exit(ngep->genlock); 25246f3e57acSmx205022 25256f3e57acSmx205022 if ((macp = mac_alloc(MAC_VERSION)) == NULL) 25266f3e57acSmx205022 goto attach_fail; 25276f3e57acSmx205022 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 25286f3e57acSmx205022 macp->m_driver = ngep; 25296f3e57acSmx205022 macp->m_dip = devinfo; 25306f3e57acSmx205022 macp->m_src_addr = infop->vendor_addr.addr; 25316f3e57acSmx205022 macp->m_callbacks = &nge_m_callbacks; 25326f3e57acSmx205022 macp->m_min_sdu = 0; 25336f3e57acSmx205022 macp->m_max_sdu = ngep->default_mtu; 2534d62bc4baSyz147064 macp->m_margin = VTAG_SIZE; 25354045d941Ssowmini macp->m_priv_props = nge_priv_props; 25366f3e57acSmx205022 /* 25376f3e57acSmx205022 * Finally, we're ready to register ourselves with the mac 25386f3e57acSmx205022 * interface; if this succeeds, we're all ready to start() 25396f3e57acSmx205022 */ 25406f3e57acSmx205022 err = mac_register(macp, &ngep->mh); 25416f3e57acSmx205022 mac_free(macp); 25426f3e57acSmx205022 if (err != 0) 25436f3e57acSmx205022 goto attach_fail; 25446f3e57acSmx205022 25456f3e57acSmx205022 /* 25466f3e57acSmx205022 * Register a periodical handler. 25476f3e57acSmx205022 * nge_chip_cyclic() is invoked in kernel context. 25486f3e57acSmx205022 */ 25496f3e57acSmx205022 ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep, 25506f3e57acSmx205022 NGE_CYCLIC_PERIOD, DDI_IPL_0); 25516f3e57acSmx205022 25526f3e57acSmx205022 ngep->progress |= PROGRESS_READY; 25536f3e57acSmx205022 return (DDI_SUCCESS); 25546f3e57acSmx205022 25556f3e57acSmx205022 attach_fail: 25566f3e57acSmx205022 nge_unattach(ngep); 25576f3e57acSmx205022 return (DDI_FAILURE); 25586f3e57acSmx205022 } 25596f3e57acSmx205022 25602d58516dSmx205022 static int 25612d58516dSmx205022 nge_suspend(nge_t *ngep) 25622d58516dSmx205022 { 25632d58516dSmx205022 mutex_enter(ngep->genlock); 25642d58516dSmx205022 rw_enter(ngep->rwlock, RW_WRITER); 25652d58516dSmx205022 25662d58516dSmx205022 /* if the port hasn't been plumbed, just return */ 25672d58516dSmx205022 if (ngep->nge_mac_state != NGE_MAC_STARTED) { 25682d58516dSmx205022 rw_exit(ngep->rwlock); 25692d58516dSmx205022 mutex_exit(ngep->genlock); 25702d58516dSmx205022 return (DDI_SUCCESS); 25712d58516dSmx205022 } 25722d58516dSmx205022 ngep->suspended = B_TRUE; 25732d58516dSmx205022 (void) nge_chip_stop(ngep, B_FALSE); 25742d58516dSmx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 25752d58516dSmx205022 25762d58516dSmx205022 rw_exit(ngep->rwlock); 25772d58516dSmx205022 mutex_exit(ngep->genlock); 25782d58516dSmx205022 return (DDI_SUCCESS); 25792d58516dSmx205022 } 25802d58516dSmx205022 25816f3e57acSmx205022 /* 25826f3e57acSmx205022 * detach(9E) -- Detach a device from the system 25836f3e57acSmx205022 */ 25846f3e57acSmx205022 static int 25856f3e57acSmx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 25866f3e57acSmx205022 { 25876f3e57acSmx205022 int i; 25886f3e57acSmx205022 nge_t *ngep; 25896f3e57acSmx205022 mul_item *p, *nextp; 25906f3e57acSmx205022 buff_ring_t *brp; 25916f3e57acSmx205022 25926f3e57acSmx205022 NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd)); 25936f3e57acSmx205022 25946f3e57acSmx205022 ngep = ddi_get_driver_private(devinfo); 25956f3e57acSmx205022 brp = ngep->buff; 25966f3e57acSmx205022 25976f3e57acSmx205022 switch (cmd) { 25986f3e57acSmx205022 default: 25996f3e57acSmx205022 return (DDI_FAILURE); 26006f3e57acSmx205022 26016f3e57acSmx205022 case DDI_SUSPEND: 26026f3e57acSmx205022 /* 26036f3e57acSmx205022 * Stop the NIC 26046f3e57acSmx205022 * Note: This driver doesn't currently support WOL, but 26056f3e57acSmx205022 * should it in the future, it is important to 26066f3e57acSmx205022 * make sure the PHY remains powered so that the 26076f3e57acSmx205022 * wakeup packet can actually be recieved. 26086f3e57acSmx205022 */ 26092d58516dSmx205022 return (nge_suspend(ngep)); 26106f3e57acSmx205022 26116f3e57acSmx205022 case DDI_DETACH: 26126f3e57acSmx205022 break; 26136f3e57acSmx205022 } 26146f3e57acSmx205022 26156f3e57acSmx205022 /* Try to wait all the buffer post to upper layer be released */ 26166f3e57acSmx205022 for (i = 0; i < 1000; i++) { 26176f3e57acSmx205022 if (brp->rx_hold == 0) 26186f3e57acSmx205022 break; 26196f3e57acSmx205022 drv_usecwait(1000); 26206f3e57acSmx205022 } 26216f3e57acSmx205022 26226f3e57acSmx205022 /* If there is any posted buffer, reject to detach */ 26236f3e57acSmx205022 if (brp->rx_hold != 0) 26246f3e57acSmx205022 return (DDI_FAILURE); 26256f3e57acSmx205022 26266f3e57acSmx205022 /* 26276f3e57acSmx205022 * Unregister from the GLD subsystem. This can fail, in 26286f3e57acSmx205022 * particular if there are DLPI style-2 streams still open - 26296f3e57acSmx205022 * in which case we just return failure without shutting 26306f3e57acSmx205022 * down chip operations. 26316f3e57acSmx205022 */ 26326f3e57acSmx205022 if (mac_unregister(ngep->mh) != DDI_SUCCESS) 26336f3e57acSmx205022 return (DDI_FAILURE); 26346f3e57acSmx205022 26356f3e57acSmx205022 /* 2636c322ff79Smx205022 * Recycle the multicast table. mac_unregister() should be called 2637c322ff79Smx205022 * before it to ensure the multicast table can be used even if 2638c322ff79Smx205022 * mac_unregister() fails. 2639c322ff79Smx205022 */ 2640c322ff79Smx205022 for (p = ngep->pcur_mulist; p != NULL; p = nextp) { 2641c322ff79Smx205022 nextp = p->next; 2642c322ff79Smx205022 kmem_free(p, sizeof (mul_item)); 2643c322ff79Smx205022 } 2644c322ff79Smx205022 ngep->pcur_mulist = NULL; 2645c322ff79Smx205022 2646c322ff79Smx205022 /* 26476f3e57acSmx205022 * All activity stopped, so we can clean up & exit 26486f3e57acSmx205022 */ 26496f3e57acSmx205022 nge_unattach(ngep); 26506f3e57acSmx205022 return (DDI_SUCCESS); 26516f3e57acSmx205022 } 26526f3e57acSmx205022 265319397407SSherry Moore /* 265419397407SSherry Moore * quiesce(9E) entry point. 265519397407SSherry Moore * 265619397407SSherry Moore * This function is called when the system is single-threaded at high 265719397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 265819397407SSherry Moore * blocked. 265919397407SSherry Moore * 266019397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 266119397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 266219397407SSherry Moore */ 266319397407SSherry Moore static int 266419397407SSherry Moore nge_quiesce(dev_info_t *devinfo) 266519397407SSherry Moore { 266619397407SSherry Moore nge_t *ngep; 266719397407SSherry Moore 266819397407SSherry Moore ngep = ddi_get_driver_private(devinfo); 266919397407SSherry Moore 267019397407SSherry Moore if (ngep == NULL) 267119397407SSherry Moore return (DDI_FAILURE); 267219397407SSherry Moore 267319397407SSherry Moore /* 267419397407SSherry Moore * Turn off debug tracing 267519397407SSherry Moore */ 267619397407SSherry Moore nge_debug = 0; 267719397407SSherry Moore ngep->debug = 0; 267819397407SSherry Moore 267919397407SSherry Moore nge_restore_mac_addr(ngep); 268019397407SSherry Moore (void) nge_chip_stop(ngep, B_FALSE); 268119397407SSherry Moore 268219397407SSherry Moore return (DDI_SUCCESS); 268319397407SSherry Moore } 268419397407SSherry Moore 268519397407SSherry Moore 26866f3e57acSmx205022 26876f3e57acSmx205022 /* 26886f3e57acSmx205022 * ========== Module Loading Data & Entry Points ========== 26896f3e57acSmx205022 */ 26906f3e57acSmx205022 26916f3e57acSmx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach, 269219397407SSherry Moore NULL, NULL, D_MP, NULL, nge_quiesce); 26936f3e57acSmx205022 26946f3e57acSmx205022 26956f3e57acSmx205022 static struct modldrv nge_modldrv = { 26966f3e57acSmx205022 &mod_driverops, /* Type of module. This one is a driver */ 26976f3e57acSmx205022 nge_ident, /* short description */ 26986f3e57acSmx205022 &nge_dev_ops /* driver specific ops */ 26996f3e57acSmx205022 }; 27006f3e57acSmx205022 27016f3e57acSmx205022 static struct modlinkage modlinkage = { 27026f3e57acSmx205022 MODREV_1, (void *)&nge_modldrv, NULL 27036f3e57acSmx205022 }; 27046f3e57acSmx205022 27056f3e57acSmx205022 27066f3e57acSmx205022 int 27076f3e57acSmx205022 _info(struct modinfo *modinfop) 27086f3e57acSmx205022 { 27096f3e57acSmx205022 return (mod_info(&modlinkage, modinfop)); 27106f3e57acSmx205022 } 27116f3e57acSmx205022 27126f3e57acSmx205022 int 27136f3e57acSmx205022 _init(void) 27146f3e57acSmx205022 { 27156f3e57acSmx205022 int status; 27166f3e57acSmx205022 27176f3e57acSmx205022 mac_init_ops(&nge_dev_ops, "nge"); 27186f3e57acSmx205022 status = mod_install(&modlinkage); 27196f3e57acSmx205022 if (status != DDI_SUCCESS) 27206f3e57acSmx205022 mac_fini_ops(&nge_dev_ops); 27216f3e57acSmx205022 else 27226f3e57acSmx205022 mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL); 27236f3e57acSmx205022 27246f3e57acSmx205022 return (status); 27256f3e57acSmx205022 } 27266f3e57acSmx205022 27276f3e57acSmx205022 int 27286f3e57acSmx205022 _fini(void) 27296f3e57acSmx205022 { 27306f3e57acSmx205022 int status; 27316f3e57acSmx205022 27326f3e57acSmx205022 status = mod_remove(&modlinkage); 27336f3e57acSmx205022 if (status == DDI_SUCCESS) { 27346f3e57acSmx205022 mac_fini_ops(&nge_dev_ops); 27356f3e57acSmx205022 mutex_destroy(nge_log_mutex); 27366f3e57acSmx205022 } 27376f3e57acSmx205022 27386f3e57acSmx205022 return (status); 27396f3e57acSmx205022 } 27406f3e57acSmx205022 27416f3e57acSmx205022 /* 27426f3e57acSmx205022 * ============ Init MSI/Fixed/SoftInterrupt routines ============== 27436f3e57acSmx205022 */ 27446f3e57acSmx205022 27456f3e57acSmx205022 /* 27466f3e57acSmx205022 * Register interrupts and initialize each mutex and condition variables 27476f3e57acSmx205022 */ 27486f3e57acSmx205022 27496f3e57acSmx205022 static int 27506f3e57acSmx205022 nge_register_intrs_and_init_locks(nge_t *ngep) 27516f3e57acSmx205022 { 27526f3e57acSmx205022 int err; 27536f3e57acSmx205022 int intr_types; 27546f3e57acSmx205022 uint_t soft_prip; 27556f3e57acSmx205022 nge_msi_mask msi_mask; 27566f3e57acSmx205022 nge_msi_map0_vec map0_vec; 27576f3e57acSmx205022 nge_msi_map1_vec map1_vec; 27586f3e57acSmx205022 27596f3e57acSmx205022 /* 27606f3e57acSmx205022 * Add the softint handlers: 27616f3e57acSmx205022 * 27626f3e57acSmx205022 * Both of these handlers are used to avoid restrictions on the 27636f3e57acSmx205022 * context and/or mutexes required for some operations. In 27646f3e57acSmx205022 * particular, the hardware interrupt handler and its subfunctions 27656f3e57acSmx205022 * can detect a number of conditions that we don't want to handle 27666f3e57acSmx205022 * in that context or with that set of mutexes held. So, these 27676f3e57acSmx205022 * softints are triggered instead: 27686f3e57acSmx205022 * 27696f3e57acSmx205022 * the <resched> softint is triggered if if we have previously 27706f3e57acSmx205022 * had to refuse to send a packet because of resource shortage 27716f3e57acSmx205022 * (we've run out of transmit buffers), but the send completion 27726f3e57acSmx205022 * interrupt handler has now detected that more buffers have 27736f3e57acSmx205022 * become available. Its only purpose is to call gld_sched() 27746f3e57acSmx205022 * to retry the pending transmits (we're not allowed to hold 27756f3e57acSmx205022 * driver-defined mutexes across gld_sched()). 27766f3e57acSmx205022 * 27776f3e57acSmx205022 * the <factotum> is triggered if the h/w interrupt handler 27786f3e57acSmx205022 * sees the <link state changed> or <error> bits in the status 27796f3e57acSmx205022 * block. It's also triggered periodically to poll the link 27806f3e57acSmx205022 * state, just in case we aren't getting link status change 27816f3e57acSmx205022 * interrupts ... 27826f3e57acSmx205022 */ 27836f3e57acSmx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl, 27846f3e57acSmx205022 DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep); 27856f3e57acSmx205022 if (err != DDI_SUCCESS) { 27866f3e57acSmx205022 nge_problem(ngep, 27876f3e57acSmx205022 "nge_attach: add nge_reschedule softintr failed"); 27886f3e57acSmx205022 27896f3e57acSmx205022 return (DDI_FAILURE); 27906f3e57acSmx205022 } 27916f3e57acSmx205022 ngep->progress |= PROGRESS_RESCHED; 27926f3e57acSmx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl, 27936f3e57acSmx205022 DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep); 27946f3e57acSmx205022 if (err != DDI_SUCCESS) { 27956f3e57acSmx205022 nge_problem(ngep, 27966f3e57acSmx205022 "nge_attach: add nge_chip_factotum softintr failed!"); 27976f3e57acSmx205022 27986f3e57acSmx205022 return (DDI_FAILURE); 27996f3e57acSmx205022 } 28006f3e57acSmx205022 if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip) 28016f3e57acSmx205022 != DDI_SUCCESS) { 28026f3e57acSmx205022 nge_problem(ngep, "nge_attach: get softintr priority failed\n"); 28036f3e57acSmx205022 28046f3e57acSmx205022 return (DDI_FAILURE); 28056f3e57acSmx205022 } 28066f3e57acSmx205022 ngep->soft_pri = soft_prip; 28076f3e57acSmx205022 28086f3e57acSmx205022 ngep->progress |= PROGRESS_FACTOTUM; 28096f3e57acSmx205022 /* Get supported interrupt types */ 28106f3e57acSmx205022 if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types) 28116f3e57acSmx205022 != DDI_SUCCESS) { 28126f3e57acSmx205022 nge_error(ngep, "ddi_intr_get_supported_types failed\n"); 28136f3e57acSmx205022 28146f3e57acSmx205022 return (DDI_FAILURE); 28156f3e57acSmx205022 } 28166f3e57acSmx205022 28176f3e57acSmx205022 NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x", 28186f3e57acSmx205022 intr_types)); 28196f3e57acSmx205022 28206f3e57acSmx205022 if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) { 28216f3e57acSmx205022 28226f3e57acSmx205022 /* MSI Configurations for mcp55 chipset */ 28236f3e57acSmx205022 if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 28246f3e57acSmx205022 ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 28256f3e57acSmx205022 28266f3e57acSmx205022 28276f3e57acSmx205022 /* Enable the 8 vectors */ 28286f3e57acSmx205022 msi_mask.msi_mask_val = 28296f3e57acSmx205022 nge_reg_get32(ngep, NGE_MSI_MASK); 28306f3e57acSmx205022 msi_mask.msi_msk_bits.vec0 = NGE_SET; 28316f3e57acSmx205022 msi_mask.msi_msk_bits.vec1 = NGE_SET; 28326f3e57acSmx205022 msi_mask.msi_msk_bits.vec2 = NGE_SET; 28336f3e57acSmx205022 msi_mask.msi_msk_bits.vec3 = NGE_SET; 28346f3e57acSmx205022 msi_mask.msi_msk_bits.vec4 = NGE_SET; 28356f3e57acSmx205022 msi_mask.msi_msk_bits.vec5 = NGE_SET; 28366f3e57acSmx205022 msi_mask.msi_msk_bits.vec6 = NGE_SET; 28376f3e57acSmx205022 msi_mask.msi_msk_bits.vec7 = NGE_SET; 28386f3e57acSmx205022 nge_reg_put32(ngep, NGE_MSI_MASK, 28396f3e57acSmx205022 msi_mask.msi_mask_val); 28406f3e57acSmx205022 28416f3e57acSmx205022 /* 28426f3e57acSmx205022 * Remapping the MSI MAP0 and MAP1. MCP55 28436f3e57acSmx205022 * is default mapping all the interrupt to 0 vector. 28446f3e57acSmx205022 * Software needs to remapping this. 28456f3e57acSmx205022 * This mapping is same as CK804. 28466f3e57acSmx205022 */ 28476f3e57acSmx205022 map0_vec.msi_map0_val = 28486f3e57acSmx205022 nge_reg_get32(ngep, NGE_MSI_MAP0); 28496f3e57acSmx205022 map1_vec.msi_map1_val = 28506f3e57acSmx205022 nge_reg_get32(ngep, NGE_MSI_MAP1); 28516f3e57acSmx205022 map0_vec.vecs_bits.reint_vec = 0; 28526f3e57acSmx205022 map0_vec.vecs_bits.rcint_vec = 0; 28536f3e57acSmx205022 map0_vec.vecs_bits.miss_vec = 3; 28546f3e57acSmx205022 map0_vec.vecs_bits.teint_vec = 5; 28556f3e57acSmx205022 map0_vec.vecs_bits.tcint_vec = 5; 28566f3e57acSmx205022 map0_vec.vecs_bits.stint_vec = 2; 28576f3e57acSmx205022 map0_vec.vecs_bits.mint_vec = 6; 28586f3e57acSmx205022 map0_vec.vecs_bits.rfint_vec = 0; 28596f3e57acSmx205022 map1_vec.vecs_bits.tfint_vec = 5; 28606f3e57acSmx205022 map1_vec.vecs_bits.feint_vec = 6; 28616f3e57acSmx205022 map1_vec.vecs_bits.resv8_11 = 3; 28626f3e57acSmx205022 map1_vec.vecs_bits.resv12_15 = 1; 28636f3e57acSmx205022 map1_vec.vecs_bits.resv16_19 = 0; 28646f3e57acSmx205022 map1_vec.vecs_bits.resv20_23 = 7; 28656f3e57acSmx205022 map1_vec.vecs_bits.resv24_31 = 0xff; 28666f3e57acSmx205022 nge_reg_put32(ngep, NGE_MSI_MAP0, 28676f3e57acSmx205022 map0_vec.msi_map0_val); 28686f3e57acSmx205022 nge_reg_put32(ngep, NGE_MSI_MAP1, 28696f3e57acSmx205022 map1_vec.msi_map1_val); 28706f3e57acSmx205022 } 28716f3e57acSmx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 28726f3e57acSmx205022 NGE_DEBUG(("MSI registration failed, " 28736f3e57acSmx205022 "trying FIXED interrupt type\n")); 28746f3e57acSmx205022 } else { 28756f3e57acSmx205022 nge_log(ngep, "Using MSI interrupt type\n"); 28766f3e57acSmx205022 28776f3e57acSmx205022 ngep->intr_type = DDI_INTR_TYPE_MSI; 28786f3e57acSmx205022 ngep->progress |= PROGRESS_SWINT; 28796f3e57acSmx205022 } 28806f3e57acSmx205022 } 28816f3e57acSmx205022 28826f3e57acSmx205022 if (!(ngep->progress & PROGRESS_SWINT) && 28836f3e57acSmx205022 (intr_types & DDI_INTR_TYPE_FIXED)) { 28846f3e57acSmx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 28856f3e57acSmx205022 nge_error(ngep, "FIXED interrupt " 28866f3e57acSmx205022 "registration failed\n"); 28876f3e57acSmx205022 28886f3e57acSmx205022 return (DDI_FAILURE); 28896f3e57acSmx205022 } 28906f3e57acSmx205022 28916f3e57acSmx205022 nge_log(ngep, "Using FIXED interrupt type\n"); 28926f3e57acSmx205022 28936f3e57acSmx205022 ngep->intr_type = DDI_INTR_TYPE_FIXED; 28946f3e57acSmx205022 ngep->progress |= PROGRESS_SWINT; 28956f3e57acSmx205022 } 28966f3e57acSmx205022 28976f3e57acSmx205022 28986f3e57acSmx205022 if (!(ngep->progress & PROGRESS_SWINT)) { 28996f3e57acSmx205022 nge_error(ngep, "No interrupts registered\n"); 29006f3e57acSmx205022 29016f3e57acSmx205022 return (DDI_FAILURE); 29026f3e57acSmx205022 } 29036f3e57acSmx205022 mutex_init(ngep->genlock, NULL, MUTEX_DRIVER, 29046f3e57acSmx205022 DDI_INTR_PRI(ngep->intr_pri)); 29056f3e57acSmx205022 mutex_init(ngep->softlock, NULL, MUTEX_DRIVER, 29066f3e57acSmx205022 DDI_INTR_PRI(ngep->soft_pri)); 29076f3e57acSmx205022 rw_init(ngep->rwlock, NULL, RW_DRIVER, 29086f3e57acSmx205022 DDI_INTR_PRI(ngep->intr_pri)); 29096f3e57acSmx205022 29106f3e57acSmx205022 return (DDI_SUCCESS); 29116f3e57acSmx205022 } 29126f3e57acSmx205022 29136f3e57acSmx205022 /* 29146f3e57acSmx205022 * nge_add_intrs: 29156f3e57acSmx205022 * 29166f3e57acSmx205022 * Register FIXED or MSI interrupts. 29176f3e57acSmx205022 */ 29186f3e57acSmx205022 static int 29196f3e57acSmx205022 nge_add_intrs(nge_t *ngep, int intr_type) 29206f3e57acSmx205022 { 29216f3e57acSmx205022 dev_info_t *dip = ngep->devinfo; 29226f3e57acSmx205022 int avail, actual, intr_size, count = 0; 29236f3e57acSmx205022 int i, flag, ret; 29246f3e57acSmx205022 29256f3e57acSmx205022 NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type)); 29266f3e57acSmx205022 29276f3e57acSmx205022 /* Get number of interrupts */ 29286f3e57acSmx205022 ret = ddi_intr_get_nintrs(dip, intr_type, &count); 29296f3e57acSmx205022 if ((ret != DDI_SUCCESS) || (count == 0)) { 29306f3e57acSmx205022 nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, " 29316f3e57acSmx205022 "count: %d", ret, count); 29326f3e57acSmx205022 29336f3e57acSmx205022 return (DDI_FAILURE); 29346f3e57acSmx205022 } 29356f3e57acSmx205022 29366f3e57acSmx205022 /* Get number of available interrupts */ 29376f3e57acSmx205022 ret = ddi_intr_get_navail(dip, intr_type, &avail); 29386f3e57acSmx205022 if ((ret != DDI_SUCCESS) || (avail == 0)) { 29396f3e57acSmx205022 nge_error(ngep, "ddi_intr_get_navail() failure, " 29406f3e57acSmx205022 "ret: %d, avail: %d\n", ret, avail); 29416f3e57acSmx205022 29426f3e57acSmx205022 return (DDI_FAILURE); 29436f3e57acSmx205022 } 29446f3e57acSmx205022 29456f3e57acSmx205022 if (avail < count) { 29466f3e57acSmx205022 NGE_DEBUG(("nitrs() returned %d, navail returned %d\n", 29476f3e57acSmx205022 count, avail)); 29486f3e57acSmx205022 } 29496f3e57acSmx205022 flag = DDI_INTR_ALLOC_NORMAL; 29506f3e57acSmx205022 29516f3e57acSmx205022 /* Allocate an array of interrupt handles */ 29526f3e57acSmx205022 intr_size = count * sizeof (ddi_intr_handle_t); 29536f3e57acSmx205022 ngep->htable = kmem_alloc(intr_size, KM_SLEEP); 29546f3e57acSmx205022 29556f3e57acSmx205022 /* Call ddi_intr_alloc() */ 29566f3e57acSmx205022 ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0, 29576f3e57acSmx205022 count, &actual, flag); 29586f3e57acSmx205022 29596f3e57acSmx205022 if ((ret != DDI_SUCCESS) || (actual == 0)) { 29606f3e57acSmx205022 nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret); 29616f3e57acSmx205022 29626f3e57acSmx205022 kmem_free(ngep->htable, intr_size); 29636f3e57acSmx205022 return (DDI_FAILURE); 29646f3e57acSmx205022 } 29656f3e57acSmx205022 29666f3e57acSmx205022 if (actual < count) { 29676f3e57acSmx205022 NGE_DEBUG(("Requested: %d, Received: %d\n", 29686f3e57acSmx205022 count, actual)); 29696f3e57acSmx205022 } 29706f3e57acSmx205022 29716f3e57acSmx205022 ngep->intr_actual_cnt = actual; 29726f3e57acSmx205022 ngep->intr_req_cnt = count; 29736f3e57acSmx205022 29746f3e57acSmx205022 /* 29756f3e57acSmx205022 * Get priority for first msi, assume remaining are all the same 29766f3e57acSmx205022 */ 29776f3e57acSmx205022 if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) != 29786f3e57acSmx205022 DDI_SUCCESS) { 29796f3e57acSmx205022 nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret); 29806f3e57acSmx205022 29816f3e57acSmx205022 /* Free already allocated intr */ 29826f3e57acSmx205022 for (i = 0; i < actual; i++) { 29836f3e57acSmx205022 (void) ddi_intr_free(ngep->htable[i]); 29846f3e57acSmx205022 } 29856f3e57acSmx205022 29866f3e57acSmx205022 kmem_free(ngep->htable, intr_size); 29876f3e57acSmx205022 29886f3e57acSmx205022 return (DDI_FAILURE); 29896f3e57acSmx205022 } 29906f3e57acSmx205022 /* Test for high level mutex */ 29916f3e57acSmx205022 if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) { 29926f3e57acSmx205022 nge_error(ngep, "nge_add_intrs:" 29936f3e57acSmx205022 "Hi level interrupt not supported"); 29946f3e57acSmx205022 29956f3e57acSmx205022 for (i = 0; i < actual; i++) 29966f3e57acSmx205022 (void) ddi_intr_free(ngep->htable[i]); 29976f3e57acSmx205022 29986f3e57acSmx205022 kmem_free(ngep->htable, intr_size); 29996f3e57acSmx205022 30006f3e57acSmx205022 return (DDI_FAILURE); 30016f3e57acSmx205022 } 30026f3e57acSmx205022 30036f3e57acSmx205022 30046f3e57acSmx205022 /* Call ddi_intr_add_handler() */ 30056f3e57acSmx205022 for (i = 0; i < actual; i++) { 30066f3e57acSmx205022 if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr, 30076f3e57acSmx205022 (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 30086f3e57acSmx205022 nge_error(ngep, "ddi_intr_add_handler() " 30096f3e57acSmx205022 "failed %d\n", ret); 30106f3e57acSmx205022 30116f3e57acSmx205022 /* Free already allocated intr */ 30126f3e57acSmx205022 for (i = 0; i < actual; i++) { 30136f3e57acSmx205022 (void) ddi_intr_free(ngep->htable[i]); 30146f3e57acSmx205022 } 30156f3e57acSmx205022 30166f3e57acSmx205022 kmem_free(ngep->htable, intr_size); 30176f3e57acSmx205022 30186f3e57acSmx205022 return (DDI_FAILURE); 30196f3e57acSmx205022 } 30206f3e57acSmx205022 } 30216f3e57acSmx205022 30226f3e57acSmx205022 if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap)) 30236f3e57acSmx205022 != DDI_SUCCESS) { 30246f3e57acSmx205022 nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret); 30256f3e57acSmx205022 30266f3e57acSmx205022 for (i = 0; i < actual; i++) { 30276f3e57acSmx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 30286f3e57acSmx205022 (void) ddi_intr_free(ngep->htable[i]); 30296f3e57acSmx205022 } 30306f3e57acSmx205022 30316f3e57acSmx205022 kmem_free(ngep->htable, intr_size); 30326f3e57acSmx205022 30336f3e57acSmx205022 return (DDI_FAILURE); 30346f3e57acSmx205022 } 30356f3e57acSmx205022 30366f3e57acSmx205022 return (DDI_SUCCESS); 30376f3e57acSmx205022 } 30386f3e57acSmx205022 30396f3e57acSmx205022 /* 30406f3e57acSmx205022 * nge_rem_intrs: 30416f3e57acSmx205022 * 30426f3e57acSmx205022 * Unregister FIXED or MSI interrupts 30436f3e57acSmx205022 */ 30446f3e57acSmx205022 static void 30456f3e57acSmx205022 nge_rem_intrs(nge_t *ngep) 30466f3e57acSmx205022 { 30476f3e57acSmx205022 int i; 30486f3e57acSmx205022 30496f3e57acSmx205022 NGE_DEBUG(("nge_rem_intrs\n")); 30506f3e57acSmx205022 30516f3e57acSmx205022 /* Disable all interrupts */ 30526f3e57acSmx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 30536f3e57acSmx205022 /* Call ddi_intr_block_disable() */ 30546f3e57acSmx205022 (void) ddi_intr_block_disable(ngep->htable, 30556f3e57acSmx205022 ngep->intr_actual_cnt); 30566f3e57acSmx205022 } else { 30576f3e57acSmx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 30586f3e57acSmx205022 (void) ddi_intr_disable(ngep->htable[i]); 30596f3e57acSmx205022 } 30606f3e57acSmx205022 } 30616f3e57acSmx205022 30626f3e57acSmx205022 /* Call ddi_intr_remove_handler() */ 30636f3e57acSmx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 30646f3e57acSmx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 30656f3e57acSmx205022 (void) ddi_intr_free(ngep->htable[i]); 30666f3e57acSmx205022 } 30676f3e57acSmx205022 30686f3e57acSmx205022 kmem_free(ngep->htable, 30696f3e57acSmx205022 ngep->intr_req_cnt * sizeof (ddi_intr_handle_t)); 30706f3e57acSmx205022 } 3071