15578Smx205022 /* 25578Smx205022 * CDDL HEADER START 35578Smx205022 * 45578Smx205022 * The contents of this file are subject to the terms of the 55578Smx205022 * Common Development and Distribution License (the "License"). 65578Smx205022 * You may not use this file except in compliance with the License. 75578Smx205022 * 85578Smx205022 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95578Smx205022 * or http://www.opensolaris.org/os/licensing. 105578Smx205022 * See the License for the specific language governing permissions 115578Smx205022 * and limitations under the License. 125578Smx205022 * 135578Smx205022 * When distributing Covered Code, include this CDDL HEADER in each 145578Smx205022 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155578Smx205022 * If applicable, add the following below this CDDL HEADER, with the 165578Smx205022 * fields enclosed by brackets "[]" replaced with your own identifying 175578Smx205022 * information: Portions Copyright [yyyy] [name of copyright owner] 185578Smx205022 * 195578Smx205022 * CDDL HEADER END 205578Smx205022 */ 215578Smx205022 225574Smx205022 /* 235869Smx205022 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 245574Smx205022 * Use is subject to license terms. 255574Smx205022 */ 265574Smx205022 275574Smx205022 285574Smx205022 #include "nge.h" 295574Smx205022 305574Smx205022 /* 315574Smx205022 * Describes the chip's DMA engine 325574Smx205022 */ 335574Smx205022 345574Smx205022 static ddi_dma_attr_t hot_dma_attr = { 355574Smx205022 DMA_ATTR_V0, /* dma_attr version */ 365574Smx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 375574Smx205022 0x000000FFFFFFFFFFull, /* dma_attr_addr_hi */ 385574Smx205022 0x000000007FFFFFFFull, /* dma_attr_count_max */ 395574Smx205022 0x0000000000000010ull, /* dma_attr_align */ 405574Smx205022 0x00000FFF, /* dma_attr_burstsizes */ 415574Smx205022 0x00000001, /* dma_attr_minxfer */ 425574Smx205022 0x000000000000FFFFull, /* dma_attr_maxxfer */ 435574Smx205022 0x000000FFFFFFFFFFull, /* dma_attr_seg */ 445574Smx205022 1, /* dma_attr_sgllen */ 455574Smx205022 0x00000001, /* dma_attr_granular */ 465574Smx205022 0 475574Smx205022 }; 485574Smx205022 495574Smx205022 static ddi_dma_attr_t hot_tx_dma_attr = { 505574Smx205022 DMA_ATTR_V0, /* dma_attr version */ 515574Smx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 525574Smx205022 0x000000FFFFFFFFFFull, /* dma_attr_addr_hi */ 535574Smx205022 0x0000000000003FFFull, /* dma_attr_count_max */ 545574Smx205022 0x0000000000000010ull, /* dma_attr_align */ 555574Smx205022 0x00000FFF, /* dma_attr_burstsizes */ 565574Smx205022 0x00000001, /* dma_attr_minxfer */ 575574Smx205022 0x0000000000003FFFull, /* dma_attr_maxxfer */ 585574Smx205022 0x000000FFFFFFFFFFull, /* dma_attr_seg */ 595574Smx205022 NGE_MAX_COOKIES, /* dma_attr_sgllen */ 605574Smx205022 1, /* dma_attr_granular */ 615574Smx205022 0 625574Smx205022 }; 635574Smx205022 645574Smx205022 static ddi_dma_attr_t sum_dma_attr = { 655574Smx205022 DMA_ATTR_V0, /* dma_attr version */ 665574Smx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 675574Smx205022 0x00000000FFFFFFFFull, /* dma_attr_addr_hi */ 685574Smx205022 0x000000007FFFFFFFull, /* dma_attr_count_max */ 695574Smx205022 0x0000000000000010ull, /* dma_attr_align */ 705574Smx205022 0x00000FFF, /* dma_attr_burstsizes */ 715574Smx205022 0x00000001, /* dma_attr_minxfer */ 725574Smx205022 0x000000000000FFFFull, /* dma_attr_maxxfer */ 735574Smx205022 0x00000000FFFFFFFFull, /* dma_attr_seg */ 745574Smx205022 1, /* dma_attr_sgllen */ 755574Smx205022 0x00000001, /* dma_attr_granular */ 765574Smx205022 0 775574Smx205022 }; 785574Smx205022 795574Smx205022 static ddi_dma_attr_t sum_tx_dma_attr = { 805574Smx205022 DMA_ATTR_V0, /* dma_attr version */ 815574Smx205022 0x0000000000000000ull, /* dma_attr_addr_lo */ 825574Smx205022 0x00000000FFFFFFFFull, /* dma_attr_addr_hi */ 835574Smx205022 0x0000000000003FFFull, /* dma_attr_count_max */ 845574Smx205022 0x0000000000000010ull, /* dma_attr_align */ 855574Smx205022 0x00000FFF, /* dma_attr_burstsizes */ 865574Smx205022 0x00000001, /* dma_attr_minxfer */ 875574Smx205022 0x0000000000003FFFull, /* dma_attr_maxxfer */ 885574Smx205022 0x00000000FFFFFFFFull, /* dma_attr_seg */ 895574Smx205022 NGE_MAX_COOKIES, /* dma_attr_sgllen */ 905574Smx205022 1, /* dma_attr_granular */ 915574Smx205022 0 925574Smx205022 }; 935574Smx205022 945574Smx205022 /* 955574Smx205022 * DMA access attributes for data. 965574Smx205022 */ 975574Smx205022 ddi_device_acc_attr_t nge_data_accattr = { 985574Smx205022 DDI_DEVICE_ATTR_V0, 995574Smx205022 DDI_STRUCTURE_LE_ACC, 1005574Smx205022 DDI_STRICTORDER_ACC, 1015574Smx205022 DDI_DEFAULT_ACC 1025574Smx205022 }; 1035574Smx205022 1045574Smx205022 /* 1055574Smx205022 * DMA access attributes for descriptors. 1065574Smx205022 */ 1075574Smx205022 static ddi_device_acc_attr_t nge_desc_accattr = { 1085574Smx205022 DDI_DEVICE_ATTR_V0, 1095574Smx205022 DDI_STRUCTURE_LE_ACC, 1105574Smx205022 DDI_STRICTORDER_ACC, 1115574Smx205022 DDI_DEFAULT_ACC 1125574Smx205022 }; 1135574Smx205022 1145574Smx205022 /* 1155574Smx205022 * PIO access attributes for registers 1165574Smx205022 */ 1175574Smx205022 static ddi_device_acc_attr_t nge_reg_accattr = { 1185574Smx205022 DDI_DEVICE_ATTR_V0, 1195574Smx205022 DDI_STRUCTURE_LE_ACC, 1205574Smx205022 DDI_STRICTORDER_ACC, 1215574Smx205022 DDI_DEFAULT_ACC 1225574Smx205022 }; 1235574Smx205022 1245574Smx205022 /* 1255574Smx205022 * NIC DESC MODE 2 1265574Smx205022 */ 1275574Smx205022 1285574Smx205022 static const nge_desc_attr_t nge_sum_desc = { 1295574Smx205022 1305574Smx205022 sizeof (sum_rx_bd), 1315574Smx205022 sizeof (sum_tx_bd), 1325574Smx205022 &sum_dma_attr, 1335574Smx205022 &sum_tx_dma_attr, 1345574Smx205022 nge_sum_rxd_fill, 1355574Smx205022 nge_sum_rxd_check, 1365574Smx205022 nge_sum_txd_fill, 1375574Smx205022 nge_sum_txd_check, 1385574Smx205022 }; 1395574Smx205022 1405574Smx205022 /* 1415574Smx205022 * NIC DESC MODE 3 1425574Smx205022 */ 1435574Smx205022 1445574Smx205022 static const nge_desc_attr_t nge_hot_desc = { 1455574Smx205022 1465574Smx205022 sizeof (hot_rx_bd), 1475574Smx205022 sizeof (hot_tx_bd), 1485574Smx205022 &hot_dma_attr, 1495574Smx205022 &hot_tx_dma_attr, 1505574Smx205022 nge_hot_rxd_fill, 1515574Smx205022 nge_hot_rxd_check, 1525574Smx205022 nge_hot_txd_fill, 1535574Smx205022 nge_hot_txd_check, 1545574Smx205022 }; 1555574Smx205022 1566512Ssowmini static char nge_ident[] = "nVidia 1Gb Ethernet"; 1575574Smx205022 static char clsize_propname[] = "cache-line-size"; 1585574Smx205022 static char latency_propname[] = "latency-timer"; 1595574Smx205022 static char debug_propname[] = "nge-debug-flags"; 1605659Sjj146644 static char intr_moderation[] = "intr-moderation"; 1615574Smx205022 static char rx_data_hw[] = "rx-data-hw"; 1625574Smx205022 static char rx_prd_lw[] = "rx-prd-lw"; 1635574Smx205022 static char rx_prd_hw[] = "rx-prd-hw"; 1645574Smx205022 static char sw_intr_intv[] = "sw-intr-intvl"; 1655574Smx205022 static char nge_desc_mode[] = "desc-mode"; 1665574Smx205022 static char default_mtu[] = "default_mtu"; 1675574Smx205022 static char low_memory_mode[] = "minimal-memory-usage"; 168*8218SMin.Xu@Sun.COM static char mac_addr_reversion[] = "mac-addr-reversion"; 1695574Smx205022 extern kmutex_t nge_log_mutex[1]; 1705574Smx205022 1715574Smx205022 static int nge_m_start(void *); 1725574Smx205022 static void nge_m_stop(void *); 1735574Smx205022 static int nge_m_promisc(void *, boolean_t); 1745574Smx205022 static int nge_m_multicst(void *, boolean_t, const uint8_t *); 1755574Smx205022 static int nge_m_unicst(void *, const uint8_t *); 1765574Smx205022 static void nge_m_ioctl(void *, queue_t *, mblk_t *); 1775574Smx205022 static boolean_t nge_m_getcapab(void *, mac_capab_t, void *); 1786200Smx205022 static int nge_m_setprop(void *, const char *, mac_prop_id_t, 1796200Smx205022 uint_t, const void *); 1806200Smx205022 static int nge_m_getprop(void *, const char *, mac_prop_id_t, 1818118SVasumathi.Sundaram@Sun.COM uint_t, uint_t, void *, uint_t *); 1826200Smx205022 static int nge_set_priv_prop(nge_t *, const char *, uint_t, 1836200Smx205022 const void *); 1846200Smx205022 static int nge_get_priv_prop(nge_t *, const char *, uint_t, 1856512Ssowmini uint_t, void *); 1866200Smx205022 1876200Smx205022 #define NGE_M_CALLBACK_FLAGS\ 1886200Smx205022 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 1895574Smx205022 1905574Smx205022 static mac_callbacks_t nge_m_callbacks = { 1915574Smx205022 NGE_M_CALLBACK_FLAGS, 1925574Smx205022 nge_m_stat, 1935574Smx205022 nge_m_start, 1945574Smx205022 nge_m_stop, 1955574Smx205022 nge_m_promisc, 1965574Smx205022 nge_m_multicst, 1975574Smx205022 nge_m_unicst, 1985574Smx205022 nge_m_tx, 1995659Sjj146644 NULL, 2005574Smx205022 nge_m_ioctl, 2016200Smx205022 nge_m_getcapab, 2026200Smx205022 NULL, 2036200Smx205022 NULL, 2046200Smx205022 nge_m_setprop, 2056200Smx205022 nge_m_getprop 2065574Smx205022 }; 2075574Smx205022 2086512Ssowmini mac_priv_prop_t nge_priv_props[] = { 2096512Ssowmini {"_tx_bcopy_threshold", MAC_PROP_PERM_RW}, 2106512Ssowmini {"_rx_bcopy_threshold", MAC_PROP_PERM_RW}, 2116512Ssowmini {"_recv_max_packet", MAC_PROP_PERM_RW}, 2126512Ssowmini {"_poll_quiet_time", MAC_PROP_PERM_RW}, 2136512Ssowmini {"_poll_busy_time", MAC_PROP_PERM_RW}, 2146512Ssowmini {"_rx_intr_hwater", MAC_PROP_PERM_RW}, 2156512Ssowmini {"_rx_intr_lwater", MAC_PROP_PERM_RW}, 2166512Ssowmini {"_adv_pause_cap", MAC_PROP_PERM_RW}, 2176512Ssowmini {"_adv_asym_pause_cap", MAC_PROP_PERM_RW}, 2186512Ssowmini {"_tx_n_intr", MAC_PROP_PERM_RW} 2196512Ssowmini }; 2206512Ssowmini 2216512Ssowmini #define NGE_MAX_PRIV_PROPS \ 2226512Ssowmini (sizeof (nge_priv_props)/sizeof (mac_priv_prop_t)) 2236512Ssowmini 2245574Smx205022 static int nge_add_intrs(nge_t *, int); 2255574Smx205022 static void nge_rem_intrs(nge_t *); 2265574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *); 2275574Smx205022 2285574Smx205022 /* 2295574Smx205022 * NGE MSI tunable: 2305574Smx205022 */ 2315574Smx205022 boolean_t nge_enable_msi = B_FALSE; 2325574Smx205022 2335574Smx205022 static enum ioc_reply 2345574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode) 2355574Smx205022 { 2365574Smx205022 /* 2375574Smx205022 * If the mode isn't being changed, there's nothing to do ... 2385574Smx205022 */ 2395574Smx205022 if (mode == ngep->param_loop_mode) 2405574Smx205022 return (IOC_ACK); 2415574Smx205022 2425574Smx205022 /* 2435574Smx205022 * Validate the requested mode and prepare a suitable message 2445574Smx205022 * to explain the link down/up cycle that the change will 2455574Smx205022 * probably induce ... 2465574Smx205022 */ 2475574Smx205022 switch (mode) { 2485574Smx205022 default: 2495574Smx205022 return (IOC_INVAL); 2505574Smx205022 2515574Smx205022 case NGE_LOOP_NONE: 2525574Smx205022 case NGE_LOOP_EXTERNAL_100: 2535574Smx205022 case NGE_LOOP_EXTERNAL_10: 2545574Smx205022 case NGE_LOOP_INTERNAL_PHY: 2555574Smx205022 break; 2565574Smx205022 } 2575574Smx205022 2585574Smx205022 /* 2595574Smx205022 * All OK; tell the caller to reprogram 2605574Smx205022 * the PHY and/or MAC for the new mode ... 2615574Smx205022 */ 2625574Smx205022 ngep->param_loop_mode = mode; 2635574Smx205022 return (IOC_RESTART_ACK); 2645574Smx205022 } 2655574Smx205022 2665574Smx205022 #undef NGE_DBG 2675574Smx205022 #define NGE_DBG NGE_DBG_INIT 2685574Smx205022 2695574Smx205022 /* 2705574Smx205022 * Utility routine to carve a slice off a chunk of allocated memory, 2715574Smx205022 * updating the chunk descriptor accordingly. The size of the slice 2725574Smx205022 * is given by the product of the <qty> and <size> parameters. 2735574Smx205022 */ 2745574Smx205022 void 2755574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 2765574Smx205022 uint32_t qty, uint32_t size) 2775574Smx205022 { 2785574Smx205022 size_t totsize; 2795574Smx205022 2805574Smx205022 totsize = qty*size; 2815574Smx205022 ASSERT(size > 0); 2825574Smx205022 ASSERT(totsize <= chunk->alength); 2835574Smx205022 2845574Smx205022 *slice = *chunk; 2855574Smx205022 slice->nslots = qty; 2865574Smx205022 slice->size = size; 2875574Smx205022 slice->alength = totsize; 2885574Smx205022 2895574Smx205022 chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 2905574Smx205022 chunk->alength -= totsize; 2915574Smx205022 chunk->offset += totsize; 2925574Smx205022 chunk->cookie.dmac_laddress += totsize; 2935574Smx205022 chunk->cookie.dmac_size -= totsize; 2945574Smx205022 } 2955574Smx205022 2965574Smx205022 /* 2975574Smx205022 * Allocate an area of memory and a DMA handle for accessing it 2985574Smx205022 */ 2995574Smx205022 int 3005574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p, 3015574Smx205022 uint_t dma_flags, dma_area_t *dma_p) 3025574Smx205022 { 3035574Smx205022 int err; 3045574Smx205022 caddr_t va; 3055574Smx205022 3065574Smx205022 NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 3075574Smx205022 (void *)ngep, memsize, attr_p, dma_flags, dma_p)); 3085574Smx205022 /* 3095574Smx205022 * Allocate handle 3105574Smx205022 */ 3115574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr, 3125574Smx205022 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 3135574Smx205022 if (err != DDI_SUCCESS) 3145574Smx205022 goto fail; 3155574Smx205022 3165574Smx205022 /* 3175574Smx205022 * Allocate memory 3185574Smx205022 */ 3195574Smx205022 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 3205574Smx205022 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 3215574Smx205022 DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl); 3225574Smx205022 if (err != DDI_SUCCESS) 3235574Smx205022 goto fail; 3245574Smx205022 3255574Smx205022 /* 3265574Smx205022 * Bind the two together 3275574Smx205022 */ 3285574Smx205022 dma_p->mem_va = va; 3295574Smx205022 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 3305574Smx205022 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 3315574Smx205022 &dma_p->cookie, &dma_p->ncookies); 3325574Smx205022 3335574Smx205022 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 3345574Smx205022 goto fail; 3355574Smx205022 3365574Smx205022 dma_p->nslots = ~0U; 3375574Smx205022 dma_p->size = ~0U; 3385574Smx205022 dma_p->offset = 0; 3395574Smx205022 3405574Smx205022 return (DDI_SUCCESS); 3415574Smx205022 3425574Smx205022 fail: 3435574Smx205022 nge_free_dma_mem(dma_p); 3445574Smx205022 NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!")); 3455574Smx205022 3465574Smx205022 return (DDI_FAILURE); 3475574Smx205022 } 3485574Smx205022 3495574Smx205022 /* 3505574Smx205022 * Free one allocated area of DMAable memory 3515574Smx205022 */ 3525574Smx205022 void 3535574Smx205022 nge_free_dma_mem(dma_area_t *dma_p) 3545574Smx205022 { 3555574Smx205022 if (dma_p->dma_hdl != NULL) { 3565574Smx205022 if (dma_p->ncookies) { 3575574Smx205022 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 3585574Smx205022 dma_p->ncookies = 0; 3595574Smx205022 } 3605574Smx205022 } 3615574Smx205022 if (dma_p->acc_hdl != NULL) { 3625574Smx205022 ddi_dma_mem_free(&dma_p->acc_hdl); 3635574Smx205022 dma_p->acc_hdl = NULL; 3645574Smx205022 } 3655574Smx205022 if (dma_p->dma_hdl != NULL) { 3665574Smx205022 ddi_dma_free_handle(&dma_p->dma_hdl); 3675574Smx205022 dma_p->dma_hdl = NULL; 3685574Smx205022 } 3695574Smx205022 } 3705574Smx205022 3715574Smx205022 #define ALLOC_TX_BUF 0x1 3725574Smx205022 #define ALLOC_TX_DESC 0x2 3735574Smx205022 #define ALLOC_RX_DESC 0x4 3745574Smx205022 3755574Smx205022 int 3765574Smx205022 nge_alloc_bufs(nge_t *ngep) 3775574Smx205022 { 3785574Smx205022 int err; 3795574Smx205022 int split; 3805574Smx205022 int progress; 3815574Smx205022 size_t txbuffsize; 3825574Smx205022 size_t rxdescsize; 3835574Smx205022 size_t txdescsize; 3845574Smx205022 3855574Smx205022 txbuffsize = ngep->tx_desc * ngep->buf_size; 3865574Smx205022 rxdescsize = ngep->rx_desc; 3875574Smx205022 txdescsize = ngep->tx_desc; 3885574Smx205022 rxdescsize *= ngep->desc_attr.rxd_size; 3895574Smx205022 txdescsize *= ngep->desc_attr.txd_size; 3905574Smx205022 progress = 0; 3915574Smx205022 3925574Smx205022 NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep)); 3935574Smx205022 /* 3945574Smx205022 * Allocate memory & handles for TX buffers 3955574Smx205022 */ 3965574Smx205022 ASSERT((txbuffsize % ngep->nge_split) == 0); 3975574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 3985574Smx205022 err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split, 3995574Smx205022 &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE, 4005574Smx205022 &ngep->send->buf[split]); 4015574Smx205022 if (err != DDI_SUCCESS) 4025574Smx205022 goto fail; 4035574Smx205022 } 4045574Smx205022 4055574Smx205022 progress |= ALLOC_TX_BUF; 4065574Smx205022 4075574Smx205022 /* 4085574Smx205022 * Allocate memory & handles for receive return rings and 4095574Smx205022 * buffer (producer) descriptor rings 4105574Smx205022 */ 4115574Smx205022 err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr, 4125574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc); 4135574Smx205022 if (err != DDI_SUCCESS) 4145574Smx205022 goto fail; 4155574Smx205022 progress |= ALLOC_RX_DESC; 4165574Smx205022 4175574Smx205022 /* 4185574Smx205022 * Allocate memory & handles for TX descriptor rings, 4195574Smx205022 */ 4205574Smx205022 err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr, 4215574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc); 4225574Smx205022 if (err != DDI_SUCCESS) 4235574Smx205022 goto fail; 4245574Smx205022 return (DDI_SUCCESS); 4255574Smx205022 4265574Smx205022 fail: 4275574Smx205022 if (progress & ALLOC_RX_DESC) 4285574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4295574Smx205022 if (progress & ALLOC_TX_BUF) { 4305574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4315574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4325574Smx205022 } 4335574Smx205022 4345574Smx205022 return (DDI_FAILURE); 4355574Smx205022 } 4365574Smx205022 4375574Smx205022 /* 4385574Smx205022 * This routine frees the transmit and receive buffers and descriptors. 4395574Smx205022 * Make sure the chip is stopped before calling it! 4405574Smx205022 */ 4415574Smx205022 void 4425574Smx205022 nge_free_bufs(nge_t *ngep) 4435574Smx205022 { 4445574Smx205022 int split; 4455574Smx205022 4465574Smx205022 NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep)); 4475574Smx205022 4485574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4495574Smx205022 nge_free_dma_mem(&ngep->send->desc); 4505574Smx205022 4515574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4525574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4535574Smx205022 } 4545574Smx205022 4555574Smx205022 /* 4565574Smx205022 * Clean up initialisation done above before the memory is freed 4575574Smx205022 */ 4585574Smx205022 static void 4595574Smx205022 nge_fini_send_ring(nge_t *ngep) 4605574Smx205022 { 4615574Smx205022 uint32_t slot; 4625574Smx205022 size_t dmah_num; 4635574Smx205022 send_ring_t *srp; 4645574Smx205022 sw_tx_sbd_t *ssbdp; 4655574Smx205022 4665574Smx205022 srp = ngep->send; 4675574Smx205022 ssbdp = srp->sw_sbds; 4685574Smx205022 4695574Smx205022 NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep)); 4705574Smx205022 4715574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 4725574Smx205022 4735574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 4745574Smx205022 if (srp->dmahndl[slot].hndl) { 4755574Smx205022 (void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl); 4765574Smx205022 ddi_dma_free_handle(&srp->dmahndl[slot].hndl); 4775574Smx205022 srp->dmahndl[slot].hndl = NULL; 4785574Smx205022 srp->dmahndl[slot].next = NULL; 4795574Smx205022 } 4805574Smx205022 } 4815574Smx205022 4825574Smx205022 srp->dmah_free.head = NULL; 4835574Smx205022 srp->dmah_free.tail = NULL; 4845574Smx205022 4855574Smx205022 kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp)); 4865574Smx205022 4875574Smx205022 } 4885574Smx205022 4895574Smx205022 /* 4905574Smx205022 * Initialise the specified Send Ring, using the information in the 4915574Smx205022 * <dma_area> descriptors that it contains to set up all the other 4925574Smx205022 * fields. This routine should be called only once for each ring. 4935574Smx205022 */ 4945574Smx205022 static int 4955574Smx205022 nge_init_send_ring(nge_t *ngep) 4965574Smx205022 { 4975574Smx205022 size_t dmah_num; 4985574Smx205022 uint32_t nslots; 4995574Smx205022 uint32_t err; 5005574Smx205022 uint32_t slot; 5015574Smx205022 uint32_t split; 5025574Smx205022 send_ring_t *srp; 5035574Smx205022 sw_tx_sbd_t *ssbdp; 5045574Smx205022 dma_area_t desc; 5055574Smx205022 dma_area_t pbuf; 5065574Smx205022 5075574Smx205022 srp = ngep->send; 5085574Smx205022 srp->desc.nslots = ngep->tx_desc; 5095574Smx205022 nslots = srp->desc.nslots; 5105574Smx205022 5115574Smx205022 NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep)); 5125574Smx205022 /* 5135574Smx205022 * Other one-off initialisation of per-ring data 5145574Smx205022 */ 5155574Smx205022 srp->ngep = ngep; 5165574Smx205022 5175574Smx205022 /* 5185574Smx205022 * Allocate the array of s/w Send Buffer Descriptors 5195574Smx205022 */ 5205574Smx205022 ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 5215574Smx205022 srp->sw_sbds = ssbdp; 5225574Smx205022 5235574Smx205022 /* 5245574Smx205022 * Now initialise each array element once and for all 5255574Smx205022 */ 5265574Smx205022 desc = srp->desc; 5275574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 5285574Smx205022 pbuf = srp->buf[split]; 5295574Smx205022 for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) { 5305574Smx205022 nge_slice_chunk(&ssbdp->desc, &desc, 1, 5315574Smx205022 ngep->desc_attr.txd_size); 5325574Smx205022 nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1, 5335574Smx205022 ngep->buf_size); 5345574Smx205022 } 5355574Smx205022 ASSERT(pbuf.alength == 0); 5365574Smx205022 } 5375574Smx205022 ASSERT(desc.alength == 0); 5385574Smx205022 5395574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5405574Smx205022 5415574Smx205022 /* preallocate dma handles for tx buffer */ 5425574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 5435574Smx205022 5445574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, 5455574Smx205022 ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT, 5465574Smx205022 NULL, &srp->dmahndl[slot].hndl); 5475574Smx205022 5485574Smx205022 if (err != DDI_SUCCESS) { 5495574Smx205022 nge_fini_send_ring(ngep); 5505574Smx205022 nge_error(ngep, 5515574Smx205022 "nge_init_send_ring: alloc dma handle fails"); 5525574Smx205022 return (DDI_FAILURE); 5535574Smx205022 } 5545574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5555574Smx205022 } 5565574Smx205022 5575574Smx205022 srp->dmah_free.head = srp->dmahndl; 5585574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5595574Smx205022 srp->dmah_free.tail->next = NULL; 5605574Smx205022 5615574Smx205022 return (DDI_SUCCESS); 5625574Smx205022 } 5635574Smx205022 5645574Smx205022 /* 5655574Smx205022 * Intialize the tx recycle pointer and tx sending pointer of tx ring 5665574Smx205022 * and set the type of tx's data descriptor by default. 5675574Smx205022 */ 5685574Smx205022 static void 5695574Smx205022 nge_reinit_send_ring(nge_t *ngep) 5705574Smx205022 { 5715574Smx205022 size_t dmah_num; 5725574Smx205022 uint32_t slot; 5735574Smx205022 send_ring_t *srp; 5745574Smx205022 sw_tx_sbd_t *ssbdp; 5755574Smx205022 5765574Smx205022 srp = ngep->send; 5775574Smx205022 5785574Smx205022 /* 5795574Smx205022 * Reinitialise control variables ... 5805574Smx205022 */ 5815574Smx205022 5825574Smx205022 srp->tx_hwmark = NGE_DESC_MIN; 5835574Smx205022 srp->tx_lwmark = NGE_DESC_MIN; 5845574Smx205022 5855574Smx205022 srp->tx_next = 0; 5865574Smx205022 srp->tx_free = srp->desc.nslots; 5875574Smx205022 srp->tc_next = 0; 5885574Smx205022 5895574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5905574Smx205022 5915574Smx205022 for (slot = 0; slot - dmah_num != 0; ++slot) 5925574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5935574Smx205022 5945574Smx205022 srp->dmah_free.head = srp->dmahndl; 5955574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5965574Smx205022 srp->dmah_free.tail->next = NULL; 5975574Smx205022 5985574Smx205022 /* 5995574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 6005574Smx205022 */ 6015574Smx205022 for (slot = 0; slot < srp->desc.nslots; ++slot) { 6025574Smx205022 ssbdp = &srp->sw_sbds[slot]; 6035574Smx205022 ssbdp->flags = HOST_OWN; 6045574Smx205022 } 6055574Smx205022 6065574Smx205022 DMA_ZERO(srp->desc); 6075574Smx205022 DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 6085574Smx205022 } 6095574Smx205022 6105574Smx205022 /* 6115574Smx205022 * Initialize the slot number of rx's ring 6125574Smx205022 */ 6135574Smx205022 static void 6145574Smx205022 nge_init_recv_ring(nge_t *ngep) 6155574Smx205022 { 6165574Smx205022 recv_ring_t *rrp; 6175574Smx205022 6185574Smx205022 rrp = ngep->recv; 6195574Smx205022 rrp->desc.nslots = ngep->rx_desc; 6205574Smx205022 rrp->ngep = ngep; 6215574Smx205022 } 6225574Smx205022 6235574Smx205022 /* 6245574Smx205022 * Intialize the rx recycle pointer and rx sending pointer of rx ring 6255574Smx205022 */ 6265574Smx205022 static void 6275574Smx205022 nge_reinit_recv_ring(nge_t *ngep) 6285574Smx205022 { 6295574Smx205022 recv_ring_t *rrp; 6305574Smx205022 6315574Smx205022 rrp = ngep->recv; 6325574Smx205022 6335574Smx205022 /* 6345574Smx205022 * Reinitialise control variables ... 6355574Smx205022 */ 6365574Smx205022 rrp->prod_index = 0; 6375574Smx205022 /* 6385574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 6395574Smx205022 */ 6405574Smx205022 DMA_ZERO(rrp->desc); 6415574Smx205022 DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV); 6425574Smx205022 } 6435574Smx205022 6445574Smx205022 /* 6455574Smx205022 * Clean up initialisation done above before the memory is freed 6465574Smx205022 */ 6475574Smx205022 static void 6485574Smx205022 nge_fini_buff_ring(nge_t *ngep) 6495574Smx205022 { 6505574Smx205022 uint32_t i; 6515574Smx205022 buff_ring_t *brp; 6525574Smx205022 dma_area_t *bufp; 6535574Smx205022 sw_rx_sbd_t *bsbdp; 6545574Smx205022 6555574Smx205022 brp = ngep->buff; 6565574Smx205022 bsbdp = brp->sw_rbds; 6575574Smx205022 6585574Smx205022 NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep)); 6595574Smx205022 6605574Smx205022 mutex_enter(brp->recycle_lock); 6615574Smx205022 brp->buf_sign++; 6625574Smx205022 mutex_exit(brp->recycle_lock); 6635574Smx205022 for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) { 6645574Smx205022 if (bsbdp->bufp) { 6655574Smx205022 if (bsbdp->bufp->mp) 6665574Smx205022 freemsg(bsbdp->bufp->mp); 6675574Smx205022 nge_free_dma_mem(bsbdp->bufp); 6685574Smx205022 kmem_free(bsbdp->bufp, sizeof (dma_area_t)); 6695574Smx205022 bsbdp->bufp = NULL; 6705574Smx205022 } 6715574Smx205022 } 6725574Smx205022 while (brp->free_list != NULL) { 6735574Smx205022 bufp = brp->free_list; 6745574Smx205022 brp->free_list = bufp->next; 6755574Smx205022 bufp->next = NULL; 6765574Smx205022 if (bufp->mp) 6775574Smx205022 freemsg(bufp->mp); 6785574Smx205022 nge_free_dma_mem(bufp); 6795574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6805574Smx205022 } 6815574Smx205022 while (brp->recycle_list != NULL) { 6825574Smx205022 bufp = brp->recycle_list; 6835574Smx205022 brp->recycle_list = bufp->next; 6845574Smx205022 bufp->next = NULL; 6855574Smx205022 if (bufp->mp) 6865574Smx205022 freemsg(bufp->mp); 6875574Smx205022 nge_free_dma_mem(bufp); 6885574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6895574Smx205022 } 6905574Smx205022 6915574Smx205022 6925574Smx205022 kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp))); 6935574Smx205022 brp->sw_rbds = NULL; 6945574Smx205022 } 6955574Smx205022 6965574Smx205022 /* 6975574Smx205022 * Intialize the Rx's data ring and free ring 6985574Smx205022 */ 6995574Smx205022 static int 7005574Smx205022 nge_init_buff_ring(nge_t *ngep) 7015574Smx205022 { 7025574Smx205022 uint32_t err; 7035574Smx205022 uint32_t slot; 7045574Smx205022 uint32_t nslots_buff; 7055574Smx205022 uint32_t nslots_recv; 7065574Smx205022 buff_ring_t *brp; 7075574Smx205022 recv_ring_t *rrp; 7085574Smx205022 dma_area_t desc; 7095574Smx205022 dma_area_t *bufp; 7105574Smx205022 sw_rx_sbd_t *bsbdp; 7115574Smx205022 7125574Smx205022 rrp = ngep->recv; 7135574Smx205022 brp = ngep->buff; 7145574Smx205022 brp->nslots = ngep->rx_buf; 7155574Smx205022 brp->rx_bcopy = B_FALSE; 7165574Smx205022 nslots_recv = rrp->desc.nslots; 7175574Smx205022 nslots_buff = brp->nslots; 7185574Smx205022 brp->ngep = ngep; 7195574Smx205022 7205574Smx205022 NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep)); 7215574Smx205022 7225574Smx205022 /* 7235574Smx205022 * Allocate the array of s/w Recv Buffer Descriptors 7245574Smx205022 */ 7255574Smx205022 bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP); 7265574Smx205022 brp->sw_rbds = bsbdp; 7275574Smx205022 brp->free_list = NULL; 7285574Smx205022 brp->recycle_list = NULL; 7295574Smx205022 for (slot = 0; slot < nslots_buff; ++slot) { 7305574Smx205022 bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP); 7315574Smx205022 err = nge_alloc_dma_mem(ngep, (ngep->buf_size 7325574Smx205022 + NGE_HEADROOM), 7335574Smx205022 &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp); 7345574Smx205022 if (err != DDI_SUCCESS) { 7355574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 7365574Smx205022 return (DDI_FAILURE); 7375574Smx205022 } 7385574Smx205022 7395574Smx205022 bufp->alength -= NGE_HEADROOM; 7405574Smx205022 bufp->offset += NGE_HEADROOM; 7415574Smx205022 bufp->private = (caddr_t)ngep; 7425574Smx205022 bufp->rx_recycle.free_func = nge_recv_recycle; 7435574Smx205022 bufp->rx_recycle.free_arg = (caddr_t)bufp; 7445574Smx205022 bufp->signature = brp->buf_sign; 7455574Smx205022 bufp->rx_delivered = B_FALSE; 7465574Smx205022 bufp->mp = desballoc(DMA_VPTR(*bufp), 7475574Smx205022 ngep->buf_size + NGE_HEADROOM, 7485574Smx205022 0, &bufp->rx_recycle); 7495574Smx205022 7505574Smx205022 if (bufp->mp == NULL) { 7515574Smx205022 return (DDI_FAILURE); 7525574Smx205022 } 7535574Smx205022 bufp->next = brp->free_list; 7545574Smx205022 brp->free_list = bufp; 7555574Smx205022 } 7565574Smx205022 7575574Smx205022 /* 7585574Smx205022 * Now initialise each array element once and for all 7595574Smx205022 */ 7605574Smx205022 desc = rrp->desc; 7615574Smx205022 for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) { 7625574Smx205022 nge_slice_chunk(&bsbdp->desc, &desc, 1, 7635574Smx205022 ngep->desc_attr.rxd_size); 7645574Smx205022 bufp = brp->free_list; 7655574Smx205022 brp->free_list = bufp->next; 7665574Smx205022 bsbdp->bufp = bufp; 7675574Smx205022 bsbdp->flags = CONTROLER_OWN; 7685574Smx205022 bufp->next = NULL; 7695574Smx205022 } 7705574Smx205022 7715574Smx205022 ASSERT(desc.alength == 0); 7725574Smx205022 return (DDI_SUCCESS); 7735574Smx205022 } 7745574Smx205022 7755574Smx205022 /* 7765574Smx205022 * Fill the host address of data in rx' descriptor 7775574Smx205022 * and initialize free pointers of rx free ring 7785574Smx205022 */ 7795574Smx205022 static int 7805574Smx205022 nge_reinit_buff_ring(nge_t *ngep) 7815574Smx205022 { 7825574Smx205022 uint32_t slot; 7835574Smx205022 uint32_t nslots_recv; 7845574Smx205022 buff_ring_t *brp; 7855574Smx205022 recv_ring_t *rrp; 7865574Smx205022 sw_rx_sbd_t *bsbdp; 7875574Smx205022 void *hw_bd_p; 7885574Smx205022 7895574Smx205022 brp = ngep->buff; 7905574Smx205022 rrp = ngep->recv; 7915574Smx205022 bsbdp = brp->sw_rbds; 7925574Smx205022 nslots_recv = rrp->desc.nslots; 7935574Smx205022 for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) { 7945574Smx205022 hw_bd_p = DMA_VPTR(bsbdp->desc); 7955574Smx205022 /* 7965574Smx205022 * There is a scenario: When the traffic of small tcp 7975574Smx205022 * packet is heavy, suspending the tcp traffic will 7985574Smx205022 * cause the preallocated buffers for rx not to be 7995574Smx205022 * released in time by tcp taffic and cause rx's buffer 8005574Smx205022 * pointers not to be refilled in time. 8015574Smx205022 * 8025574Smx205022 * At this point, if we reinitialize the driver, the bufp 8035574Smx205022 * pointer for rx's traffic will be NULL. 8045574Smx205022 * So the result of the reinitializion fails. 8055574Smx205022 */ 8065574Smx205022 if (bsbdp->bufp == NULL) 8075574Smx205022 return (DDI_FAILURE); 8085574Smx205022 8095574Smx205022 ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie, 8105574Smx205022 bsbdp->bufp->alength); 8115574Smx205022 } 8125574Smx205022 return (DDI_SUCCESS); 8135574Smx205022 } 8145574Smx205022 8155574Smx205022 static void 8165574Smx205022 nge_init_ring_param_lock(nge_t *ngep) 8175574Smx205022 { 8185574Smx205022 buff_ring_t *brp; 8195574Smx205022 send_ring_t *srp; 8205574Smx205022 8215574Smx205022 srp = ngep->send; 8225574Smx205022 brp = ngep->buff; 8235574Smx205022 8245574Smx205022 /* Init the locks for send ring */ 8255574Smx205022 mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 8265574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8275574Smx205022 mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 8285574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8295574Smx205022 mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER, 8305574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8315574Smx205022 8325574Smx205022 /* Init parameters of buffer ring */ 8335574Smx205022 brp->free_list = NULL; 8345574Smx205022 brp->recycle_list = NULL; 8355574Smx205022 brp->rx_hold = 0; 8365574Smx205022 brp->buf_sign = 0; 8375574Smx205022 8385574Smx205022 /* Init recycle list lock */ 8395574Smx205022 mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER, 8405574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8415574Smx205022 } 8425574Smx205022 8435574Smx205022 int 8445574Smx205022 nge_init_rings(nge_t *ngep) 8455574Smx205022 { 8465574Smx205022 uint32_t err; 8475574Smx205022 8485574Smx205022 err = nge_init_send_ring(ngep); 8495574Smx205022 if (err != DDI_SUCCESS) { 8505574Smx205022 return (err); 8515574Smx205022 } 8525574Smx205022 nge_init_recv_ring(ngep); 8535574Smx205022 8545574Smx205022 err = nge_init_buff_ring(ngep); 8555574Smx205022 if (err != DDI_SUCCESS) { 8565574Smx205022 nge_fini_send_ring(ngep); 8575574Smx205022 return (DDI_FAILURE); 8585574Smx205022 } 8595574Smx205022 8605574Smx205022 return (err); 8615574Smx205022 } 8625574Smx205022 8635574Smx205022 static int 8645574Smx205022 nge_reinit_ring(nge_t *ngep) 8655574Smx205022 { 8665574Smx205022 int err; 8675574Smx205022 8685574Smx205022 nge_reinit_recv_ring(ngep); 8695574Smx205022 nge_reinit_send_ring(ngep); 8705574Smx205022 err = nge_reinit_buff_ring(ngep); 8715574Smx205022 return (err); 8725574Smx205022 } 8735574Smx205022 8745574Smx205022 8755574Smx205022 void 8765574Smx205022 nge_fini_rings(nge_t *ngep) 8775574Smx205022 { 8785574Smx205022 /* 8795574Smx205022 * For receive ring, nothing need to be finished. 8805574Smx205022 * So only finish buffer ring and send ring here. 8815574Smx205022 */ 8825574Smx205022 nge_fini_buff_ring(ngep); 8835574Smx205022 nge_fini_send_ring(ngep); 8845574Smx205022 } 8855574Smx205022 8865574Smx205022 /* 8875574Smx205022 * Loopback ioctl code 8885574Smx205022 */ 8895574Smx205022 8905574Smx205022 static lb_property_t loopmodes[] = { 8915574Smx205022 { normal, "normal", NGE_LOOP_NONE }, 8925574Smx205022 { external, "100Mbps", NGE_LOOP_EXTERNAL_100 }, 8935574Smx205022 { external, "10Mbps", NGE_LOOP_EXTERNAL_10 }, 8945574Smx205022 { internal, "PHY", NGE_LOOP_INTERNAL_PHY }, 8955574Smx205022 }; 8965574Smx205022 8975574Smx205022 enum ioc_reply 8985574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp) 8995574Smx205022 { 9005574Smx205022 int cmd; 9015574Smx205022 uint32_t *lbmp; 9025574Smx205022 lb_info_sz_t *lbsp; 9035574Smx205022 lb_property_t *lbpp; 9045574Smx205022 9055574Smx205022 /* 9065574Smx205022 * Validate format of ioctl 9075574Smx205022 */ 9085574Smx205022 if (mp->b_cont == NULL) 9095574Smx205022 return (IOC_INVAL); 9105574Smx205022 9115574Smx205022 cmd = iocp->ioc_cmd; 9125574Smx205022 9135574Smx205022 switch (cmd) { 9145574Smx205022 default: 9155574Smx205022 return (IOC_INVAL); 9165574Smx205022 9175574Smx205022 case LB_GET_INFO_SIZE: 9185574Smx205022 if (iocp->ioc_count != sizeof (lb_info_sz_t)) 9195574Smx205022 return (IOC_INVAL); 9205574Smx205022 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 9215574Smx205022 *lbsp = sizeof (loopmodes); 9225574Smx205022 return (IOC_REPLY); 9235574Smx205022 9245574Smx205022 case LB_GET_INFO: 9255574Smx205022 if (iocp->ioc_count != sizeof (loopmodes)) 9265574Smx205022 return (IOC_INVAL); 9275574Smx205022 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 9285574Smx205022 bcopy(loopmodes, lbpp, sizeof (loopmodes)); 9295574Smx205022 return (IOC_REPLY); 9305574Smx205022 9315574Smx205022 case LB_GET_MODE: 9325574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9335574Smx205022 return (IOC_INVAL); 9345574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9355574Smx205022 *lbmp = ngep->param_loop_mode; 9365574Smx205022 return (IOC_REPLY); 9375574Smx205022 9385574Smx205022 case LB_SET_MODE: 9395574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9405574Smx205022 return (IOC_INVAL); 9415574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9425574Smx205022 return (nge_set_loop_mode(ngep, *lbmp)); 9435574Smx205022 } 9445574Smx205022 } 9455574Smx205022 9465574Smx205022 #undef NGE_DBG 9475574Smx205022 #define NGE_DBG NGE_DBG_NEMO 9485574Smx205022 9495574Smx205022 9505574Smx205022 static void 9515574Smx205022 nge_check_desc_prop(nge_t *ngep) 9525574Smx205022 { 9535574Smx205022 if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD) 9545574Smx205022 ngep->desc_mode = DESC_HOT; 9555574Smx205022 9565574Smx205022 if (ngep->desc_mode == DESC_OFFLOAD) { 9575574Smx205022 9585574Smx205022 ngep->desc_attr = nge_sum_desc; 9595574Smx205022 9605574Smx205022 } else if (ngep->desc_mode == DESC_HOT) { 9615574Smx205022 9625574Smx205022 ngep->desc_attr = nge_hot_desc; 9635574Smx205022 } 9645574Smx205022 } 9655574Smx205022 9665574Smx205022 /* 9675574Smx205022 * nge_get_props -- get the parameters to tune the driver 9685574Smx205022 */ 9695574Smx205022 static void 9705574Smx205022 nge_get_props(nge_t *ngep) 9715574Smx205022 { 9725574Smx205022 chip_info_t *infop; 9735574Smx205022 dev_info_t *devinfo; 9745574Smx205022 nge_dev_spec_param_t *dev_param_p; 9755574Smx205022 9765574Smx205022 devinfo = ngep->devinfo; 9775574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 9785574Smx205022 dev_param_p = &ngep->dev_spec_param; 9795574Smx205022 9805574Smx205022 infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9815574Smx205022 DDI_PROP_DONTPASS, clsize_propname, 32); 9825574Smx205022 9835574Smx205022 infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9845574Smx205022 DDI_PROP_DONTPASS, latency_propname, 64); 9855659Sjj146644 ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9865659Sjj146644 DDI_PROP_DONTPASS, intr_moderation, NGE_SET); 9875574Smx205022 ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9885574Smx205022 DDI_PROP_DONTPASS, rx_data_hw, 0x20); 9895574Smx205022 ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9905574Smx205022 DDI_PROP_DONTPASS, rx_prd_lw, 0x4); 9915574Smx205022 ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9925574Smx205022 DDI_PROP_DONTPASS, rx_prd_hw, 0xc); 9935574Smx205022 9945574Smx205022 ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9955574Smx205022 DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC); 9965574Smx205022 ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9975574Smx205022 DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP); 9985574Smx205022 ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9995574Smx205022 DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type); 10005574Smx205022 ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 10015574Smx205022 DDI_PROP_DONTPASS, low_memory_mode, 0); 1002*8218SMin.Xu@Sun.COM ngep->mac_addr_reversion = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 1003*8218SMin.Xu@Sun.COM DDI_PROP_DONTPASS, mac_addr_reversion, 0); 10045574Smx205022 10055574Smx205022 if (dev_param_p->jumbo) { 10065574Smx205022 ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 10075574Smx205022 DDI_PROP_DONTPASS, default_mtu, ETHERMTU); 10085574Smx205022 } else 10095574Smx205022 ngep->default_mtu = ETHERMTU; 10105574Smx205022 10115574Smx205022 if (ngep->default_mtu > ETHERMTU && 10125574Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 10135574Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 10145574Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 10155574Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 10165574Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 10175574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10185574Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 10195574Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 10205574Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 10215574Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 10225574Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 10235574Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 10245574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10255574Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 10265574Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 10275574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10285574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10295574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10305574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10315574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10325574Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 10335574Smx205022 ngep->default_mtu = NGE_MAX_MTU; 10345574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10355574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10365574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10375574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10385574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10395574Smx205022 } else if (ngep->lowmem_mode != 0) { 10405574Smx205022 ngep->default_mtu = ETHERMTU; 10415574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10425574Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 10435574Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 10445574Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 10455574Smx205022 ngep->nge_split = NGE_SPLIT_32; 10465574Smx205022 } else { 10475574Smx205022 ngep->default_mtu = ETHERMTU; 10485574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10495574Smx205022 ngep->tx_desc = dev_param_p->tx_desc_num; 10505574Smx205022 ngep->rx_desc = dev_param_p->rx_desc_num; 10515574Smx205022 ngep->rx_buf = dev_param_p->rx_desc_num * 2; 10525574Smx205022 ngep->nge_split = dev_param_p->nge_split; 10535574Smx205022 } 10545574Smx205022 10555574Smx205022 nge_check_desc_prop(ngep); 10565574Smx205022 } 10575574Smx205022 10585574Smx205022 10595574Smx205022 static int 10607656SSherry.Moore@Sun.COM nge_reset_dev(nge_t *ngep) 10615574Smx205022 { 10625574Smx205022 int err; 10635869Smx205022 nge_mul_addr1 maddr1; 10645869Smx205022 nge_sw_statistics_t *sw_stp; 10655869Smx205022 sw_stp = &ngep->statistics.sw_statistics; 10665574Smx205022 send_ring_t *srp = ngep->send; 10675574Smx205022 10685574Smx205022 ASSERT(mutex_owned(ngep->genlock)); 10695574Smx205022 mutex_enter(srp->tc_lock); 10705574Smx205022 mutex_enter(srp->tx_lock); 10715574Smx205022 10725574Smx205022 nge_tx_recycle_all(ngep); 10735574Smx205022 err = nge_reinit_ring(ngep); 10745574Smx205022 if (err == DDI_FAILURE) { 10755574Smx205022 mutex_exit(srp->tx_lock); 10765574Smx205022 mutex_exit(srp->tc_lock); 10775574Smx205022 return (err); 10785574Smx205022 } 10795574Smx205022 err = nge_chip_reset(ngep); 10805869Smx205022 /* 10815869Smx205022 * Clear the Multicast mac address table 10825869Smx205022 */ 10835869Smx205022 nge_reg_put32(ngep, NGE_MUL_ADDR0, 0); 10845869Smx205022 maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1); 10855869Smx205022 maddr1.addr_bits.addr = 0; 10865869Smx205022 nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val); 10875869Smx205022 10885574Smx205022 mutex_exit(srp->tx_lock); 10895574Smx205022 mutex_exit(srp->tc_lock); 10905574Smx205022 if (err == DDI_FAILURE) 10915574Smx205022 return (err); 10925574Smx205022 ngep->watchdog = 0; 10935574Smx205022 ngep->resched_needed = B_FALSE; 10945574Smx205022 ngep->promisc = B_FALSE; 10955574Smx205022 ngep->param_loop_mode = NGE_LOOP_NONE; 10965574Smx205022 ngep->factotum_flag = 0; 10975574Smx205022 ngep->resched_needed = 0; 10985574Smx205022 ngep->nge_mac_state = NGE_MAC_RESET; 10995574Smx205022 ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL; 11005574Smx205022 ngep->max_sdu += VTAG_SIZE; 11015574Smx205022 ngep->rx_def = 0x16; 11025869Smx205022 11035869Smx205022 /* Clear the software statistics */ 11045869Smx205022 sw_stp->recv_count = 0; 11055869Smx205022 sw_stp->xmit_count = 0; 11065869Smx205022 sw_stp->rbytes = 0; 11075869Smx205022 sw_stp->obytes = 0; 11085869Smx205022 11095574Smx205022 return (DDI_SUCCESS); 11105574Smx205022 } 11115574Smx205022 11125574Smx205022 static void 11135574Smx205022 nge_m_stop(void *arg) 11145574Smx205022 { 11155574Smx205022 nge_t *ngep = arg; /* private device info */ 11165574Smx205022 11175574Smx205022 NGE_TRACE(("nge_m_stop($%p)", arg)); 11185574Smx205022 11195574Smx205022 /* 11205574Smx205022 * Just stop processing, then record new MAC state 11215574Smx205022 */ 11225574Smx205022 mutex_enter(ngep->genlock); 11235869Smx205022 /* If suspended, the adapter is already stopped, just return. */ 11245869Smx205022 if (ngep->suspended) { 11255869Smx205022 ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED); 11265869Smx205022 mutex_exit(ngep->genlock); 11275869Smx205022 return; 11285869Smx205022 } 11295574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 11305574Smx205022 11315574Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 11325574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 11335574Smx205022 11345574Smx205022 /* Recycle all the TX BD */ 11355574Smx205022 nge_tx_recycle_all(ngep); 11365574Smx205022 nge_fini_rings(ngep); 11375574Smx205022 nge_free_bufs(ngep); 11385574Smx205022 11395574Smx205022 NGE_DEBUG(("nge_m_stop($%p) done", arg)); 11405574Smx205022 11415574Smx205022 rw_exit(ngep->rwlock); 11425574Smx205022 mutex_exit(ngep->genlock); 11435574Smx205022 } 11445574Smx205022 11455574Smx205022 static int 11465574Smx205022 nge_m_start(void *arg) 11475574Smx205022 { 11485574Smx205022 int err; 11495574Smx205022 nge_t *ngep = arg; 11505574Smx205022 11515574Smx205022 NGE_TRACE(("nge_m_start($%p)", arg)); 11525869Smx205022 11535869Smx205022 /* 11545869Smx205022 * Start processing and record new MAC state 11555869Smx205022 */ 11565869Smx205022 mutex_enter(ngep->genlock); 11575574Smx205022 /* 11585574Smx205022 * If suspended, don't start, as the resume processing 11595574Smx205022 * will recall this function with the suspended flag off. 11605574Smx205022 */ 11615869Smx205022 if (ngep->suspended) { 11625869Smx205022 mutex_exit(ngep->genlock); 11635988Svb160487 return (EIO); 11645869Smx205022 } 11655574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 11665574Smx205022 err = nge_alloc_bufs(ngep); 11675574Smx205022 if (err != DDI_SUCCESS) { 11685574Smx205022 nge_problem(ngep, "nge_m_start: DMA buffer allocation failed"); 11695574Smx205022 goto finish; 11705574Smx205022 } 11715574Smx205022 err = nge_init_rings(ngep); 11725574Smx205022 if (err != DDI_SUCCESS) { 11735574Smx205022 nge_free_bufs(ngep); 11745988Svb160487 nge_problem(ngep, "nge_init_rings() failed,err=%x", err); 11755574Smx205022 goto finish; 11765574Smx205022 } 11775574Smx205022 err = nge_restart(ngep); 11785574Smx205022 11795574Smx205022 NGE_DEBUG(("nge_m_start($%p) done", arg)); 11805988Svb160487 finish: 11815988Svb160487 rw_exit(ngep->rwlock); 11825988Svb160487 mutex_exit(ngep->genlock); 11835574Smx205022 11845988Svb160487 return (err == DDI_SUCCESS ? 0 : EIO); 11855574Smx205022 } 11865574Smx205022 11875574Smx205022 static int 11885574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr) 11895574Smx205022 { 11905574Smx205022 nge_t *ngep = arg; 11915574Smx205022 11925574Smx205022 NGE_TRACE(("nge_m_unicst($%p)", arg)); 11935574Smx205022 /* 11945574Smx205022 * Remember the new current address in the driver state 11955574Smx205022 * Sync the chip's idea of the address too ... 11965574Smx205022 */ 11975574Smx205022 mutex_enter(ngep->genlock); 11985574Smx205022 11995574Smx205022 ethaddr_copy(macaddr, ngep->cur_uni_addr.addr); 12005574Smx205022 ngep->cur_uni_addr.set = 1; 12015574Smx205022 12025574Smx205022 /* 12035574Smx205022 * If we are suspended, we want to quit now, and not update 12045574Smx205022 * the chip. Doing so might put it in a bad state, but the 12055574Smx205022 * resume will get the unicast address installed. 12065574Smx205022 */ 12075869Smx205022 if (ngep->suspended) { 12085869Smx205022 mutex_exit(ngep->genlock); 12095574Smx205022 return (DDI_SUCCESS); 12105869Smx205022 } 12115574Smx205022 nge_chip_sync(ngep); 12125574Smx205022 12135574Smx205022 NGE_DEBUG(("nge_m_unicst($%p) done", arg)); 12145574Smx205022 mutex_exit(ngep->genlock); 12155574Smx205022 12165574Smx205022 return (0); 12175574Smx205022 } 12185574Smx205022 12195574Smx205022 static int 12205574Smx205022 nge_m_promisc(void *arg, boolean_t on) 12215574Smx205022 { 12225574Smx205022 nge_t *ngep = arg; 12235574Smx205022 12245574Smx205022 NGE_TRACE(("nge_m_promisc($%p)", arg)); 12255574Smx205022 12265574Smx205022 /* 12275574Smx205022 * Store specified mode and pass to chip layer to update h/w 12285574Smx205022 */ 12295574Smx205022 mutex_enter(ngep->genlock); 12305869Smx205022 /* 12315869Smx205022 * If suspended, there is no need to do anything, even 12325869Smx205022 * recording the promiscuious mode is not neccessary, as 12335869Smx205022 * it won't be properly set on resume. Just return failing. 12345869Smx205022 */ 12355869Smx205022 if (ngep->suspended) { 12365869Smx205022 mutex_exit(ngep->genlock); 12375869Smx205022 return (DDI_FAILURE); 12385869Smx205022 } 12395574Smx205022 if (ngep->promisc == on) { 12405574Smx205022 mutex_exit(ngep->genlock); 12415574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12425574Smx205022 return (0); 12435574Smx205022 } 12445574Smx205022 ngep->promisc = on; 12457155Smx205022 ngep->record_promisc = ngep->promisc; 12465574Smx205022 nge_chip_sync(ngep); 12475574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12485574Smx205022 mutex_exit(ngep->genlock); 12495574Smx205022 12505574Smx205022 return (0); 12515574Smx205022 } 12525574Smx205022 12535574Smx205022 static void nge_mulparam(nge_t *ngep) 12545574Smx205022 { 12555574Smx205022 uint8_t number; 12565574Smx205022 ether_addr_t pand; 12575574Smx205022 ether_addr_t por; 12585574Smx205022 mul_item *plist; 12595574Smx205022 12605574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12615574Smx205022 pand[number] = 0x00; 12625574Smx205022 por[number] = 0x00; 12635574Smx205022 } 12645574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) { 12655574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12665574Smx205022 pand[number] &= plist->mul_addr[number]; 12675574Smx205022 por[number] |= plist->mul_addr[number]; 12685574Smx205022 } 12695574Smx205022 } 12705574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12715574Smx205022 ngep->cur_mul_addr.addr[number] 12725574Smx205022 = pand[number] & por[number]; 12735574Smx205022 ngep->cur_mul_mask.addr[number] 12745574Smx205022 = pand [number] | (~por[number]); 12755574Smx205022 } 12765574Smx205022 } 12775574Smx205022 static int 12785574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12795574Smx205022 { 12805574Smx205022 boolean_t update; 12815574Smx205022 boolean_t b_eq; 12825574Smx205022 nge_t *ngep = arg; 12835574Smx205022 mul_item *plist; 12845574Smx205022 mul_item *plist_prev; 12855574Smx205022 mul_item *pitem; 12865574Smx205022 12875574Smx205022 NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg, 12885574Smx205022 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 12895574Smx205022 12905574Smx205022 update = B_FALSE; 12915574Smx205022 plist = plist_prev = NULL; 12925574Smx205022 mutex_enter(ngep->genlock); 12935574Smx205022 if (add) { 12945574Smx205022 if (ngep->pcur_mulist != NULL) { 12955574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 12965574Smx205022 plist = plist->next) { 12975574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 12985574Smx205022 if (b_eq) { 12995574Smx205022 plist->ref_cnt++; 13005574Smx205022 break; 13015574Smx205022 } 13025574Smx205022 plist_prev = plist; 13035574Smx205022 } 13045574Smx205022 } 13055574Smx205022 13065574Smx205022 if (plist == NULL) { 13075574Smx205022 pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP); 13085574Smx205022 ether_copy(mca, pitem->mul_addr); 13095574Smx205022 pitem ->ref_cnt++; 13105574Smx205022 pitem ->next = NULL; 13115574Smx205022 if (plist_prev == NULL) 13125574Smx205022 ngep->pcur_mulist = pitem; 13135574Smx205022 else 13145574Smx205022 plist_prev->next = pitem; 13155574Smx205022 update = B_TRUE; 13165574Smx205022 } 13175574Smx205022 } else { 13185574Smx205022 if (ngep->pcur_mulist != NULL) { 13195574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 13205574Smx205022 plist = plist->next) { 13215574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 13225574Smx205022 if (b_eq) { 13235574Smx205022 update = B_TRUE; 13245574Smx205022 break; 13255574Smx205022 } 13265574Smx205022 plist_prev = plist; 13275574Smx205022 } 13285574Smx205022 13295574Smx205022 if (update) { 13305574Smx205022 if ((plist_prev == NULL) && 13315574Smx205022 (plist->next == NULL)) 13325574Smx205022 ngep->pcur_mulist = NULL; 13335574Smx205022 else if ((plist_prev == NULL) && 13345574Smx205022 (plist->next != NULL)) 13355574Smx205022 ngep->pcur_mulist = plist->next; 13365574Smx205022 else 13375574Smx205022 plist_prev->next = plist->next; 13385574Smx205022 kmem_free(plist, sizeof (mul_item)); 13395574Smx205022 } 13405574Smx205022 } 13415574Smx205022 } 13425574Smx205022 13435869Smx205022 if (update && !ngep->suspended) { 13445574Smx205022 nge_mulparam(ngep); 13455574Smx205022 nge_chip_sync(ngep); 13465574Smx205022 } 13475574Smx205022 NGE_DEBUG(("nge_m_multicst($%p) done", arg)); 13485574Smx205022 mutex_exit(ngep->genlock); 13495574Smx205022 13505574Smx205022 return (0); 13515574Smx205022 } 13525574Smx205022 13535574Smx205022 static void 13545574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 13555574Smx205022 { 13565574Smx205022 int err; 13575574Smx205022 int cmd; 13585574Smx205022 nge_t *ngep = arg; 13595574Smx205022 struct iocblk *iocp; 13605574Smx205022 enum ioc_reply status; 13615574Smx205022 boolean_t need_privilege; 13625574Smx205022 13635574Smx205022 /* 13645574Smx205022 * If suspended, we might actually be able to do some of 13655574Smx205022 * these ioctls, but it is harder to make sure they occur 13665574Smx205022 * without actually putting the hardware in an undesireable 13675574Smx205022 * state. So just NAK it. 13685574Smx205022 */ 13695869Smx205022 mutex_enter(ngep->genlock); 13705574Smx205022 if (ngep->suspended) { 13715574Smx205022 miocnak(wq, mp, 0, EINVAL); 13725869Smx205022 mutex_exit(ngep->genlock); 13735574Smx205022 return; 13745574Smx205022 } 13755869Smx205022 mutex_exit(ngep->genlock); 13765574Smx205022 13775574Smx205022 /* 13785574Smx205022 * Validate the command before bothering with the mutex ... 13795574Smx205022 */ 13805574Smx205022 iocp = (struct iocblk *)mp->b_rptr; 13815574Smx205022 iocp->ioc_error = 0; 13825574Smx205022 need_privilege = B_TRUE; 13835574Smx205022 cmd = iocp->ioc_cmd; 13845574Smx205022 13855574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x", cmd)); 13865574Smx205022 switch (cmd) { 13875574Smx205022 default: 13885574Smx205022 NGE_LDB(NGE_DBG_BADIOC, 13895574Smx205022 ("nge_m_ioctl: unknown cmd 0x%x", cmd)); 13905574Smx205022 13915574Smx205022 miocnak(wq, mp, 0, EINVAL); 13925574Smx205022 return; 13935574Smx205022 13945574Smx205022 case NGE_MII_READ: 13955574Smx205022 case NGE_MII_WRITE: 13965574Smx205022 case NGE_SEE_READ: 13975574Smx205022 case NGE_SEE_WRITE: 13985574Smx205022 case NGE_DIAG: 13995574Smx205022 case NGE_PEEK: 14005574Smx205022 case NGE_POKE: 14015574Smx205022 case NGE_PHY_RESET: 14025574Smx205022 case NGE_SOFT_RESET: 14035574Smx205022 case NGE_HARD_RESET: 14045574Smx205022 break; 14055574Smx205022 14065574Smx205022 case LB_GET_INFO_SIZE: 14075574Smx205022 case LB_GET_INFO: 14085574Smx205022 case LB_GET_MODE: 14095574Smx205022 need_privilege = B_FALSE; 14105574Smx205022 break; 14115574Smx205022 case LB_SET_MODE: 14125574Smx205022 break; 14135574Smx205022 } 14145574Smx205022 14155574Smx205022 if (need_privilege) { 14165574Smx205022 /* 14175574Smx205022 * Check for specific net_config privilege. 14185574Smx205022 */ 14195574Smx205022 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 14205574Smx205022 if (err != 0) { 14215574Smx205022 NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d", 14225574Smx205022 cmd, err)); 14235574Smx205022 miocnak(wq, mp, 0, err); 14245574Smx205022 return; 14255574Smx205022 } 14265574Smx205022 } 14275574Smx205022 14285574Smx205022 mutex_enter(ngep->genlock); 14295574Smx205022 14305574Smx205022 switch (cmd) { 14315574Smx205022 default: 14325574Smx205022 _NOTE(NOTREACHED) 14335574Smx205022 status = IOC_INVAL; 14345574Smx205022 break; 14355574Smx205022 14365574Smx205022 case NGE_MII_READ: 14375574Smx205022 case NGE_MII_WRITE: 14385574Smx205022 case NGE_SEE_READ: 14395574Smx205022 case NGE_SEE_WRITE: 14405574Smx205022 case NGE_DIAG: 14415574Smx205022 case NGE_PEEK: 14425574Smx205022 case NGE_POKE: 14435574Smx205022 case NGE_PHY_RESET: 14445574Smx205022 case NGE_SOFT_RESET: 14455574Smx205022 case NGE_HARD_RESET: 14465574Smx205022 status = nge_chip_ioctl(ngep, mp, iocp); 14475574Smx205022 break; 14485574Smx205022 14495574Smx205022 case LB_GET_INFO_SIZE: 14505574Smx205022 case LB_GET_INFO: 14515574Smx205022 case LB_GET_MODE: 14525574Smx205022 case LB_SET_MODE: 14535574Smx205022 status = nge_loop_ioctl(ngep, mp, iocp); 14545574Smx205022 break; 14555574Smx205022 14565574Smx205022 } 14575574Smx205022 14585574Smx205022 /* 14595574Smx205022 * Do we need to reprogram the PHY and/or the MAC? 14605574Smx205022 * Do it now, while we still have the mutex. 14615574Smx205022 * 14625574Smx205022 * Note: update the PHY first, 'cos it controls the 14635574Smx205022 * speed/duplex parameters that the MAC code uses. 14645574Smx205022 */ 14655574Smx205022 14665574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status)); 14675574Smx205022 14685574Smx205022 switch (status) { 14695574Smx205022 case IOC_RESTART_REPLY: 14705574Smx205022 case IOC_RESTART_ACK: 14715574Smx205022 (*ngep->physops->phys_update)(ngep); 14725574Smx205022 nge_chip_sync(ngep); 14735574Smx205022 break; 14745574Smx205022 14755574Smx205022 default: 14765574Smx205022 break; 14775574Smx205022 } 14785574Smx205022 14795574Smx205022 mutex_exit(ngep->genlock); 14805574Smx205022 14815574Smx205022 /* 14825574Smx205022 * Finally, decide how to reply 14835574Smx205022 */ 14845574Smx205022 switch (status) { 14855574Smx205022 14865574Smx205022 default: 14875574Smx205022 case IOC_INVAL: 14885574Smx205022 miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 14895574Smx205022 EINVAL : iocp->ioc_error); 14905574Smx205022 break; 14915574Smx205022 14925574Smx205022 case IOC_DONE: 14935574Smx205022 break; 14945574Smx205022 14955574Smx205022 case IOC_RESTART_ACK: 14965574Smx205022 case IOC_ACK: 14975574Smx205022 miocack(wq, mp, 0, 0); 14985574Smx205022 break; 14995574Smx205022 15005574Smx205022 case IOC_RESTART_REPLY: 15015574Smx205022 case IOC_REPLY: 15025574Smx205022 mp->b_datap->db_type = iocp->ioc_error == 0 ? 15035574Smx205022 M_IOCACK : M_IOCNAK; 15045574Smx205022 qreply(wq, mp); 15055574Smx205022 break; 15065574Smx205022 } 15075574Smx205022 } 15085574Smx205022 15096200Smx205022 static boolean_t 15106200Smx205022 nge_param_locked(mac_prop_id_t pr_num) 15116200Smx205022 { 15126200Smx205022 /* 15136200Smx205022 * All adv_* parameters are locked (read-only) while 15146200Smx205022 * the device is in any sort of loopback mode ... 15156200Smx205022 */ 15166200Smx205022 switch (pr_num) { 15176789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 15186789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 15196789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 15206789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 15216789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 15226789Sam223141 case MAC_PROP_EN_100FDX_CAP: 15236789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 15246789Sam223141 case MAC_PROP_EN_100HDX_CAP: 15256789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 15266789Sam223141 case MAC_PROP_EN_10FDX_CAP: 15276789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 15286789Sam223141 case MAC_PROP_EN_10HDX_CAP: 15296789Sam223141 case MAC_PROP_AUTONEG: 15306789Sam223141 case MAC_PROP_FLOWCTRL: 15316200Smx205022 return (B_TRUE); 15326200Smx205022 } 15336200Smx205022 return (B_FALSE); 15346200Smx205022 } 15356200Smx205022 15366200Smx205022 /* 15376200Smx205022 * callback functions for set/get of properties 15386200Smx205022 */ 15396200Smx205022 static int 15406200Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 15416200Smx205022 uint_t pr_valsize, const void *pr_val) 15426200Smx205022 { 15436200Smx205022 nge_t *ngep = barg; 15446200Smx205022 int err = 0; 15456512Ssowmini uint32_t cur_mtu, new_mtu; 15466200Smx205022 link_flowctrl_t fl; 15476200Smx205022 15486200Smx205022 mutex_enter(ngep->genlock); 15496200Smx205022 if (ngep->param_loop_mode != NGE_LOOP_NONE && 15506200Smx205022 nge_param_locked(pr_num)) { 15516200Smx205022 /* 15526200Smx205022 * All adv_* parameters are locked (read-only) 15536200Smx205022 * while the device is in any sort of loopback mode. 15546200Smx205022 */ 15556200Smx205022 mutex_exit(ngep->genlock); 15566200Smx205022 return (EBUSY); 15576200Smx205022 } 15586200Smx205022 switch (pr_num) { 15596789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 15606200Smx205022 ngep->param_en_1000fdx = *(uint8_t *)pr_val; 15616200Smx205022 ngep->param_adv_1000fdx = *(uint8_t *)pr_val; 15626200Smx205022 goto reprogram; 15636789Sam223141 case MAC_PROP_EN_100FDX_CAP: 15646200Smx205022 ngep->param_en_100fdx = *(uint8_t *)pr_val; 15656200Smx205022 ngep->param_adv_100fdx = *(uint8_t *)pr_val; 15666200Smx205022 goto reprogram; 15676789Sam223141 case MAC_PROP_EN_100HDX_CAP: 15686200Smx205022 ngep->param_en_100hdx = *(uint8_t *)pr_val; 15696200Smx205022 ngep->param_adv_100hdx = *(uint8_t *)pr_val; 15706200Smx205022 goto reprogram; 15716789Sam223141 case MAC_PROP_EN_10FDX_CAP: 15726200Smx205022 ngep->param_en_10fdx = *(uint8_t *)pr_val; 15736200Smx205022 ngep->param_adv_10fdx = *(uint8_t *)pr_val; 15746200Smx205022 goto reprogram; 15756789Sam223141 case MAC_PROP_EN_10HDX_CAP: 15766200Smx205022 ngep->param_en_10hdx = *(uint8_t *)pr_val; 15776200Smx205022 ngep->param_adv_10hdx = *(uint8_t *)pr_val; 15786200Smx205022 reprogram: 15796200Smx205022 (*ngep->physops->phys_update)(ngep); 15806200Smx205022 nge_chip_sync(ngep); 15816200Smx205022 break; 15826200Smx205022 15836789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 15846789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 15856789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 15866789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 15876789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 15886789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 15896789Sam223141 case MAC_PROP_STATUS: 15906789Sam223141 case MAC_PROP_SPEED: 15916789Sam223141 case MAC_PROP_DUPLEX: 15926789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 15936200Smx205022 err = ENOTSUP; /* read-only prop. Can't set this */ 15946200Smx205022 break; 15956789Sam223141 case MAC_PROP_AUTONEG: 15966200Smx205022 ngep->param_adv_autoneg = *(uint8_t *)pr_val; 15976200Smx205022 (*ngep->physops->phys_update)(ngep); 15986200Smx205022 nge_chip_sync(ngep); 15996200Smx205022 break; 16006789Sam223141 case MAC_PROP_MTU: 16016200Smx205022 cur_mtu = ngep->default_mtu; 16026200Smx205022 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 16036200Smx205022 if (new_mtu == cur_mtu) { 16046200Smx205022 err = 0; 16056200Smx205022 break; 16066200Smx205022 } 16076200Smx205022 if (new_mtu < ETHERMTU || 16086200Smx205022 new_mtu > NGE_MAX_MTU) { 16096200Smx205022 err = EINVAL; 16106200Smx205022 break; 16116200Smx205022 } 16126200Smx205022 if ((new_mtu > ETHERMTU) && 16136200Smx205022 (!ngep->dev_spec_param.jumbo)) { 16146200Smx205022 err = EINVAL; 16156200Smx205022 break; 16166200Smx205022 } 16176200Smx205022 if (ngep->nge_mac_state == NGE_MAC_STARTED) { 16186200Smx205022 err = EBUSY; 16196200Smx205022 break; 16206200Smx205022 } 16216200Smx205022 16226200Smx205022 ngep->default_mtu = new_mtu; 16236200Smx205022 if (ngep->default_mtu > ETHERMTU && 16246200Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 16256200Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 16266200Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 16276200Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 16286200Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 16296200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16306200Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 16316200Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 16326200Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 16336200Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 16346200Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 16356200Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 16366200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16376200Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 16386200Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 16396200Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16406200Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16416200Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16426200Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16436200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16446200Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 16456200Smx205022 ngep->default_mtu = NGE_MAX_MTU; 16466200Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16476200Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16486200Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16496200Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16506200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16516200Smx205022 } else if (ngep->lowmem_mode != 0) { 16526200Smx205022 ngep->default_mtu = ETHERMTU; 16536200Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16546200Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 16556200Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 16566200Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 16576200Smx205022 ngep->nge_split = NGE_SPLIT_32; 16586200Smx205022 } else { 16596200Smx205022 ngep->default_mtu = ETHERMTU; 16606200Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16616200Smx205022 ngep->tx_desc = 16626200Smx205022 ngep->dev_spec_param.tx_desc_num; 16636200Smx205022 ngep->rx_desc = 16646200Smx205022 ngep->dev_spec_param.rx_desc_num; 16656200Smx205022 ngep->rx_buf = 16666200Smx205022 ngep->dev_spec_param.rx_desc_num * 2; 16676200Smx205022 ngep->nge_split = 16686200Smx205022 ngep->dev_spec_param.nge_split; 16696200Smx205022 } 16706200Smx205022 16716200Smx205022 err = mac_maxsdu_update(ngep->mh, ngep->default_mtu); 16726200Smx205022 16736200Smx205022 break; 16746789Sam223141 case MAC_PROP_FLOWCTRL: 16756200Smx205022 bcopy(pr_val, &fl, sizeof (fl)); 16766200Smx205022 switch (fl) { 16776200Smx205022 default: 16786200Smx205022 err = ENOTSUP; 16796200Smx205022 break; 16806200Smx205022 case LINK_FLOWCTRL_NONE: 16816200Smx205022 ngep->param_adv_pause = 0; 16826200Smx205022 ngep->param_adv_asym_pause = 0; 16836200Smx205022 16846200Smx205022 ngep->param_link_rx_pause = B_FALSE; 16856200Smx205022 ngep->param_link_tx_pause = B_FALSE; 16866200Smx205022 break; 16876200Smx205022 case LINK_FLOWCTRL_RX: 16886200Smx205022 if (!((ngep->param_lp_pause == 0) && 16896200Smx205022 (ngep->param_lp_asym_pause == 1))) { 16906200Smx205022 err = EINVAL; 16916200Smx205022 break; 16926200Smx205022 } 16936200Smx205022 ngep->param_adv_pause = 1; 16946200Smx205022 ngep->param_adv_asym_pause = 1; 16956200Smx205022 16966200Smx205022 ngep->param_link_rx_pause = B_TRUE; 16976200Smx205022 ngep->param_link_tx_pause = B_FALSE; 16986200Smx205022 break; 16996200Smx205022 case LINK_FLOWCTRL_TX: 17006200Smx205022 if (!((ngep->param_lp_pause == 1) && 17016200Smx205022 (ngep->param_lp_asym_pause == 1))) { 17026200Smx205022 err = EINVAL; 17036200Smx205022 break; 17046200Smx205022 } 17056200Smx205022 ngep->param_adv_pause = 0; 17066200Smx205022 ngep->param_adv_asym_pause = 1; 17076200Smx205022 17086200Smx205022 ngep->param_link_rx_pause = B_FALSE; 17096200Smx205022 ngep->param_link_tx_pause = B_TRUE; 17106200Smx205022 break; 17116200Smx205022 case LINK_FLOWCTRL_BI: 17126200Smx205022 if (ngep->param_lp_pause != 1) { 17136200Smx205022 err = EINVAL; 17146200Smx205022 break; 17156200Smx205022 } 17166200Smx205022 ngep->param_adv_pause = 1; 17176200Smx205022 17186200Smx205022 ngep->param_link_rx_pause = B_TRUE; 17196200Smx205022 ngep->param_link_tx_pause = B_TRUE; 17206200Smx205022 break; 17216200Smx205022 } 17226200Smx205022 17236200Smx205022 if (err == 0) { 17246200Smx205022 (*ngep->physops->phys_update)(ngep); 17256200Smx205022 nge_chip_sync(ngep); 17266200Smx205022 } 17276200Smx205022 17286200Smx205022 break; 17296789Sam223141 case MAC_PROP_PRIVATE: 17306200Smx205022 err = nge_set_priv_prop(ngep, pr_name, pr_valsize, 17316200Smx205022 pr_val); 17326200Smx205022 if (err == 0) { 17336200Smx205022 (*ngep->physops->phys_update)(ngep); 17346200Smx205022 nge_chip_sync(ngep); 17356200Smx205022 } 17366200Smx205022 break; 17376200Smx205022 default: 17386200Smx205022 err = ENOTSUP; 17396200Smx205022 } 17406200Smx205022 mutex_exit(ngep->genlock); 17416200Smx205022 return (err); 17426200Smx205022 } 17436200Smx205022 17446200Smx205022 static int 17456200Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 17468118SVasumathi.Sundaram@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 17476200Smx205022 { 17486200Smx205022 nge_t *ngep = barg; 17496512Ssowmini int err = 0; 17506200Smx205022 link_flowctrl_t fl; 17516512Ssowmini uint64_t speed; 17526789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 17536512Ssowmini 17546512Ssowmini if (pr_valsize == 0) 17556512Ssowmini return (EINVAL); 17566200Smx205022 17578118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_RW; 17588118SVasumathi.Sundaram@Sun.COM 17596200Smx205022 bzero(pr_val, pr_valsize); 17608118SVasumathi.Sundaram@Sun.COM 17616200Smx205022 switch (pr_num) { 17626789Sam223141 case MAC_PROP_DUPLEX: 17638118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 17646512Ssowmini if (pr_valsize >= sizeof (link_duplex_t)) { 17656512Ssowmini bcopy(&ngep->param_link_duplex, pr_val, 17666512Ssowmini sizeof (link_duplex_t)); 17676512Ssowmini } else 17686512Ssowmini err = EINVAL; 17696200Smx205022 break; 17706789Sam223141 case MAC_PROP_SPEED: 17718118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 17726200Smx205022 if (pr_valsize >= sizeof (uint64_t)) { 17736512Ssowmini speed = ngep->param_link_speed * 1000000ull; 17746512Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 17756512Ssowmini } else 17766512Ssowmini err = EINVAL; 17776200Smx205022 break; 17786789Sam223141 case MAC_PROP_AUTONEG: 17796512Ssowmini if (is_default) { 17806512Ssowmini *(uint8_t *)pr_val = 1; 17816512Ssowmini } else { 17826200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_autoneg; 17836200Smx205022 } 17846200Smx205022 break; 17856789Sam223141 case MAC_PROP_FLOWCTRL: 17866200Smx205022 if (pr_valsize >= sizeof (link_flowctrl_t)) { 17876789Sam223141 if (pr_flags & MAC_PROP_DEFAULT) { 17886512Ssowmini fl = LINK_FLOWCTRL_BI; 17896512Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 17906512Ssowmini break; 17916512Ssowmini } 17926200Smx205022 if (ngep->param_link_rx_pause && 17936200Smx205022 !ngep->param_link_tx_pause) 17946200Smx205022 fl = LINK_FLOWCTRL_RX; 17956200Smx205022 17966200Smx205022 if (!ngep->param_link_rx_pause && 17976200Smx205022 !ngep->param_link_tx_pause) 17986200Smx205022 fl = LINK_FLOWCTRL_NONE; 17996200Smx205022 18006200Smx205022 if (!ngep->param_link_rx_pause && 18016200Smx205022 ngep->param_link_tx_pause) 18026200Smx205022 fl = LINK_FLOWCTRL_TX; 18036200Smx205022 18046200Smx205022 if (ngep->param_link_rx_pause && 18056200Smx205022 ngep->param_link_tx_pause) 18066200Smx205022 fl = LINK_FLOWCTRL_BI; 18076200Smx205022 bcopy(&fl, pr_val, sizeof (fl)); 18086512Ssowmini } else 18096512Ssowmini err = EINVAL; 18106200Smx205022 break; 18116789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 18128118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18136512Ssowmini if (is_default) { 18146512Ssowmini *(uint8_t *)pr_val = 1; 18156512Ssowmini } else { 18166200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_1000fdx; 18176200Smx205022 } 18186200Smx205022 break; 18196789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 18206512Ssowmini if (is_default) { 18216512Ssowmini *(uint8_t *)pr_val = 1; 18226512Ssowmini } else { 18236200Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000fdx; 18246200Smx205022 } 18256200Smx205022 break; 18266789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 18278118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18286512Ssowmini if (is_default) { 18296512Ssowmini *(uint8_t *)pr_val = 0; 18306512Ssowmini } else { 18316200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_1000hdx; 18326200Smx205022 } 18336200Smx205022 break; 18346789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 18358118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18366512Ssowmini if (is_default) { 18376512Ssowmini *(uint8_t *)pr_val = 0; 18386512Ssowmini } else { 18396200Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000hdx; 18406200Smx205022 } 18416200Smx205022 break; 18426789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 18438118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18446512Ssowmini if (is_default) { 18456512Ssowmini *(uint8_t *)pr_val = 1; 18466512Ssowmini } else { 18476200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100fdx; 18486200Smx205022 } 18496200Smx205022 break; 18506789Sam223141 case MAC_PROP_EN_100FDX_CAP: 18516512Ssowmini if (is_default) { 18526512Ssowmini *(uint8_t *)pr_val = 1; 18536512Ssowmini } else { 18546200Smx205022 *(uint8_t *)pr_val = ngep->param_en_100fdx; 18556200Smx205022 } 18566200Smx205022 break; 18576789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 18588118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18596512Ssowmini if (is_default) { 18606512Ssowmini *(uint8_t *)pr_val = 1; 18616512Ssowmini } else { 18626200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100hdx; 18636200Smx205022 } 18646200Smx205022 break; 18656789Sam223141 case MAC_PROP_EN_100HDX_CAP: 18666512Ssowmini if (is_default) { 18676512Ssowmini *(uint8_t *)pr_val = 1; 18686512Ssowmini } else { 18696200Smx205022 *(uint8_t *)pr_val = ngep->param_en_100hdx; 18706200Smx205022 } 18716200Smx205022 break; 18726789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 18738118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18746512Ssowmini if (is_default) { 18756512Ssowmini *(uint8_t *)pr_val = 1; 18766512Ssowmini } else { 18776200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10fdx; 18786200Smx205022 } 18796200Smx205022 break; 18806789Sam223141 case MAC_PROP_EN_10FDX_CAP: 18816512Ssowmini if (is_default) { 18826512Ssowmini *(uint8_t *)pr_val = 1; 18836512Ssowmini } else { 18846200Smx205022 *(uint8_t *)pr_val = ngep->param_en_10fdx; 18856200Smx205022 } 18866200Smx205022 break; 18876789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 18888118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18896512Ssowmini if (is_default) { 18906512Ssowmini *(uint8_t *)pr_val = 1; 18916512Ssowmini } else { 18926200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10hdx; 18936200Smx205022 } 18946200Smx205022 break; 18956789Sam223141 case MAC_PROP_EN_10HDX_CAP: 18966512Ssowmini if (is_default) { 18976512Ssowmini *(uint8_t *)pr_val = 1; 18986512Ssowmini } else { 18996200Smx205022 *(uint8_t *)pr_val = ngep->param_en_10hdx; 19006200Smx205022 } 19016200Smx205022 break; 19026789Sam223141 case MAC_PROP_ADV_100T4_CAP: 19036789Sam223141 case MAC_PROP_EN_100T4_CAP: 19048118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 19056512Ssowmini *(uint8_t *)pr_val = 0; 19066512Ssowmini break; 19076789Sam223141 case MAC_PROP_PRIVATE: 19086512Ssowmini err = nge_get_priv_prop(ngep, pr_name, pr_flags, 19096512Ssowmini pr_valsize, pr_val); 19106200Smx205022 break; 19116200Smx205022 default: 19126200Smx205022 err = ENOTSUP; 19136200Smx205022 } 19146200Smx205022 return (err); 19156200Smx205022 } 19166200Smx205022 19176200Smx205022 /* ARGSUSED */ 19186200Smx205022 static int 19196200Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize, 19206200Smx205022 const void *pr_val) 19216200Smx205022 { 19226200Smx205022 int err = 0; 19236200Smx205022 long result; 19246200Smx205022 19256200Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 19266200Smx205022 if (pr_val == NULL) { 19276200Smx205022 err = EINVAL; 19286200Smx205022 return (err); 19296200Smx205022 } 19306200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19316200Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19326200Smx205022 err = EINVAL; 19336200Smx205022 } else { 19346200Smx205022 ngep->param_txbcopy_threshold = (uint32_t)result; 19356200Smx205022 goto reprogram; 19366200Smx205022 } 19376200Smx205022 return (err); 19386200Smx205022 } 19396200Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 19406200Smx205022 if (pr_val == NULL) { 19416200Smx205022 err = EINVAL; 19426200Smx205022 return (err); 19436200Smx205022 } 19446200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19456200Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19466200Smx205022 err = EINVAL; 19476200Smx205022 } else { 19486200Smx205022 ngep->param_rxbcopy_threshold = (uint32_t)result; 19496200Smx205022 goto reprogram; 19506200Smx205022 } 19516200Smx205022 return (err); 19526200Smx205022 } 19536200Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 19546200Smx205022 if (pr_val == NULL) { 19556200Smx205022 err = EINVAL; 19566200Smx205022 return (err); 19576200Smx205022 } 19586200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19596200Smx205022 if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 19606200Smx205022 err = EINVAL; 19616200Smx205022 } else { 19626200Smx205022 ngep->param_recv_max_packet = (uint32_t)result; 19636200Smx205022 goto reprogram; 19646200Smx205022 } 19656200Smx205022 return (err); 19666200Smx205022 } 19676200Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 19686200Smx205022 if (pr_val == NULL) { 19696200Smx205022 err = EINVAL; 19706200Smx205022 return (err); 19716200Smx205022 } 19726200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19736200Smx205022 if (result < 0 || result > 10000) { 19746200Smx205022 err = EINVAL; 19756200Smx205022 } else { 19766200Smx205022 ngep->param_poll_quiet_time = (uint32_t)result; 19776200Smx205022 goto reprogram; 19786200Smx205022 } 19796200Smx205022 return (err); 19806200Smx205022 } 19816200Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 19826200Smx205022 if (pr_val == NULL) { 19836200Smx205022 err = EINVAL; 19846200Smx205022 return (err); 19856200Smx205022 } 19866200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19876200Smx205022 if (result < 0 || result > 10000) { 19886200Smx205022 err = EINVAL; 19896200Smx205022 } else { 19906200Smx205022 ngep->param_poll_busy_time = (uint32_t)result; 19916200Smx205022 goto reprogram; 19926200Smx205022 } 19936200Smx205022 return (err); 19946200Smx205022 } 19956200Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 19966200Smx205022 if (pr_val == NULL) { 19976200Smx205022 err = EINVAL; 19986200Smx205022 return (err); 19996200Smx205022 } 20006200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20016512Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20026200Smx205022 err = EINVAL; 20036200Smx205022 } else { 20046200Smx205022 ngep->param_rx_intr_hwater = (uint32_t)result; 20056200Smx205022 goto reprogram; 20066200Smx205022 } 20076200Smx205022 return (err); 20086200Smx205022 } 20096200Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 20106200Smx205022 if (pr_val == NULL) { 20116200Smx205022 err = EINVAL; 20126200Smx205022 return (err); 20136200Smx205022 } 20146200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20156512Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20166200Smx205022 err = EINVAL; 20176200Smx205022 } else { 20186200Smx205022 ngep->param_rx_intr_lwater = (uint32_t)result; 20196200Smx205022 goto reprogram; 20206200Smx205022 } 20216200Smx205022 return (err); 20226200Smx205022 } 20236200Smx205022 if (strcmp(pr_name, "_tx_n_intr") == 0) { 20246200Smx205022 if (pr_val == NULL) { 20256200Smx205022 err = EINVAL; 20266200Smx205022 return (err); 20276200Smx205022 } 20286200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20296200Smx205022 if (result < 1 || result > 10000) { 20306200Smx205022 err = EINVAL; 20316200Smx205022 } else { 20326200Smx205022 ngep->param_tx_n_intr = (uint32_t)result; 20336200Smx205022 goto reprogram; 20346200Smx205022 } 20356200Smx205022 return (err); 20366200Smx205022 } 20376200Smx205022 20386200Smx205022 err = ENOTSUP; 20396200Smx205022 return (err); 20406200Smx205022 20416200Smx205022 reprogram: 20426200Smx205022 if (err == 0) { 20436200Smx205022 (*ngep->physops->phys_update)(ngep); 20446200Smx205022 nge_chip_sync(ngep); 20456200Smx205022 } 20466200Smx205022 20476200Smx205022 return (err); 20486200Smx205022 } 20496200Smx205022 20506200Smx205022 static int 20516512Ssowmini nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_flags, 20526512Ssowmini uint_t pr_valsize, void *pr_val) 20536200Smx205022 { 20546200Smx205022 int err = ENOTSUP; 20556789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 20566512Ssowmini int value; 20576512Ssowmini 20586512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 20596512Ssowmini value = (is_default ? 1 : ngep->param_adv_pause); 20606512Ssowmini err = 0; 20616512Ssowmini goto done; 20626512Ssowmini } 20636512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 20646512Ssowmini value = (is_default ? 1 : ngep->param_adv_asym_pause); 20656512Ssowmini err = 0; 20666512Ssowmini goto done; 20676512Ssowmini } 20686200Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 20696512Ssowmini value = (is_default ? NGE_TX_COPY_SIZE : 20706512Ssowmini ngep->param_txbcopy_threshold); 20716200Smx205022 err = 0; 20726200Smx205022 goto done; 20736200Smx205022 } 20746200Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 20756512Ssowmini value = (is_default ? NGE_RX_COPY_SIZE : 20766512Ssowmini ngep->param_rxbcopy_threshold); 20776200Smx205022 err = 0; 20786200Smx205022 goto done; 20796200Smx205022 } 20806200Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 20816512Ssowmini value = (is_default ? 128 : ngep->param_recv_max_packet); 20826200Smx205022 err = 0; 20836200Smx205022 goto done; 20846200Smx205022 } 20856200Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 20866512Ssowmini value = (is_default ? NGE_POLL_QUIET_TIME : 20876512Ssowmini ngep->param_poll_quiet_time); 20886200Smx205022 err = 0; 20896200Smx205022 goto done; 20906200Smx205022 } 20916200Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 20926512Ssowmini value = (is_default ? NGE_POLL_BUSY_TIME : 20936512Ssowmini ngep->param_poll_busy_time); 20946200Smx205022 err = 0; 20956200Smx205022 goto done; 20966200Smx205022 } 20976200Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 20986512Ssowmini value = (is_default ? 1 : ngep->param_rx_intr_hwater); 20996200Smx205022 err = 0; 21006200Smx205022 goto done; 21016200Smx205022 } 21026200Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 21036512Ssowmini value = (is_default ? 8 : ngep->param_rx_intr_lwater); 21046200Smx205022 err = 0; 21056200Smx205022 goto done; 21066200Smx205022 } 21076200Smx205022 if (strcmp(pr_name, "_tx_n_intr") == 0) { 21086512Ssowmini value = (is_default ? NGE_TX_N_INTR : 21096512Ssowmini ngep->param_tx_n_intr); 21106200Smx205022 err = 0; 21116200Smx205022 goto done; 21126200Smx205022 } 21136200Smx205022 21146200Smx205022 done: 21156200Smx205022 if (err == 0) { 21166512Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 21176200Smx205022 } 21186200Smx205022 return (err); 21196200Smx205022 } 21206200Smx205022 21215574Smx205022 /* ARGSUSED */ 21225574Smx205022 static boolean_t 21235574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 21245574Smx205022 { 21255574Smx205022 nge_t *ngep = arg; 21265574Smx205022 nge_dev_spec_param_t *dev_param_p; 21275574Smx205022 21285574Smx205022 dev_param_p = &ngep->dev_spec_param; 21295574Smx205022 21305574Smx205022 switch (cap) { 21315574Smx205022 case MAC_CAPAB_HCKSUM: { 21325574Smx205022 uint32_t *hcksum_txflags = cap_data; 21335574Smx205022 21345574Smx205022 if (dev_param_p->tx_hw_checksum) { 21355574Smx205022 *hcksum_txflags = dev_param_p->tx_hw_checksum; 21365574Smx205022 } else 21375574Smx205022 return (B_FALSE); 21385574Smx205022 break; 21395574Smx205022 } 21405574Smx205022 case MAC_CAPAB_POLL: 21415574Smx205022 /* 21425574Smx205022 * There's nothing for us to fill in, simply returning 21435574Smx205022 * B_TRUE, stating that we support polling is sufficient. 21445574Smx205022 */ 21455574Smx205022 break; 21465574Smx205022 default: 21475574Smx205022 return (B_FALSE); 21485574Smx205022 } 21495574Smx205022 return (B_TRUE); 21505574Smx205022 } 21515574Smx205022 21525574Smx205022 #undef NGE_DBG 21535574Smx205022 #define NGE_DBG NGE_DBG_INIT /* debug flag for this code */ 21545574Smx205022 int 21555574Smx205022 nge_restart(nge_t *ngep) 21565574Smx205022 { 21575574Smx205022 int err = 0; 21587656SSherry.Moore@Sun.COM err = nge_reset_dev(ngep); 21597155Smx205022 /* write back the promisc setting */ 21607155Smx205022 ngep->promisc = ngep->record_promisc; 21616366Smx205022 nge_chip_sync(ngep); 21625869Smx205022 if (!err) 21635869Smx205022 err = nge_chip_start(ngep); 21645574Smx205022 21655574Smx205022 if (err) { 21665574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 21675574Smx205022 return (DDI_FAILURE); 21685574Smx205022 } else { 21695574Smx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 21705574Smx205022 return (DDI_SUCCESS); 21715574Smx205022 } 21725574Smx205022 } 21735574Smx205022 21745574Smx205022 void 21755574Smx205022 nge_wake_factotum(nge_t *ngep) 21765574Smx205022 { 21775574Smx205022 mutex_enter(ngep->softlock); 21785574Smx205022 if (ngep->factotum_flag == 0) { 21795574Smx205022 ngep->factotum_flag = 1; 21805574Smx205022 (void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL); 21815574Smx205022 } 21825574Smx205022 mutex_exit(ngep->softlock); 21835574Smx205022 } 21845574Smx205022 21855574Smx205022 /* 21865574Smx205022 * High-level cyclic handler 21875574Smx205022 * 21885574Smx205022 * This routine schedules a (low-level) softint callback to the 21895574Smx205022 * factotum. 21905574Smx205022 */ 21915574Smx205022 21925574Smx205022 static void 21935574Smx205022 nge_chip_cyclic(void *arg) 21945574Smx205022 { 21955574Smx205022 nge_t *ngep; 21965574Smx205022 21975574Smx205022 ngep = (nge_t *)arg; 21985574Smx205022 21995574Smx205022 switch (ngep->nge_chip_state) { 22005574Smx205022 default: 22015574Smx205022 return; 22025574Smx205022 22035574Smx205022 case NGE_CHIP_RUNNING: 22045574Smx205022 break; 22055574Smx205022 22065574Smx205022 case NGE_CHIP_FAULT: 22075574Smx205022 case NGE_CHIP_ERROR: 22085574Smx205022 break; 22095574Smx205022 } 22105574Smx205022 22115574Smx205022 nge_wake_factotum(ngep); 22125574Smx205022 } 22135574Smx205022 22145574Smx205022 static void 22155574Smx205022 nge_unattach(nge_t *ngep) 22165574Smx205022 { 22175574Smx205022 send_ring_t *srp; 22185574Smx205022 buff_ring_t *brp; 22195574Smx205022 22205574Smx205022 srp = ngep->send; 22215574Smx205022 brp = ngep->buff; 22225574Smx205022 NGE_TRACE(("nge_unattach($%p)", (void *)ngep)); 22235574Smx205022 22245574Smx205022 /* 22255574Smx205022 * Flag that no more activity may be initiated 22265574Smx205022 */ 22275574Smx205022 ngep->progress &= ~PROGRESS_READY; 22285574Smx205022 ngep->nge_mac_state = NGE_MAC_UNATTACH; 22295574Smx205022 22305574Smx205022 /* 22315574Smx205022 * Quiesce the PHY and MAC (leave it reset but still powered). 22325574Smx205022 * Clean up and free all NGE data structures 22335574Smx205022 */ 22345574Smx205022 if (ngep->periodic_id != NULL) { 22355574Smx205022 ddi_periodic_delete(ngep->periodic_id); 22365574Smx205022 ngep->periodic_id = NULL; 22375574Smx205022 } 22385574Smx205022 22395574Smx205022 if (ngep->progress & PROGRESS_KSTATS) 22405574Smx205022 nge_fini_kstats(ngep); 22415574Smx205022 22425574Smx205022 if (ngep->progress & PROGRESS_HWINT) { 22435574Smx205022 mutex_enter(ngep->genlock); 22445574Smx205022 nge_restore_mac_addr(ngep); 22455574Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 22465574Smx205022 mutex_exit(ngep->genlock); 22475574Smx205022 } 22485574Smx205022 22495574Smx205022 if (ngep->progress & PROGRESS_SWINT) 22505574Smx205022 nge_rem_intrs(ngep); 22515574Smx205022 22525574Smx205022 if (ngep->progress & PROGRESS_FACTOTUM) 22535574Smx205022 (void) ddi_intr_remove_softint(ngep->factotum_hdl); 22545574Smx205022 22555574Smx205022 if (ngep->progress & PROGRESS_RESCHED) 22565574Smx205022 (void) ddi_intr_remove_softint(ngep->resched_hdl); 22575574Smx205022 22585574Smx205022 if (ngep->progress & PROGRESS_INTR) { 22595574Smx205022 mutex_destroy(srp->tx_lock); 22605574Smx205022 mutex_destroy(srp->tc_lock); 22615574Smx205022 mutex_destroy(&srp->dmah_lock); 22625574Smx205022 mutex_destroy(brp->recycle_lock); 22635574Smx205022 22645574Smx205022 mutex_destroy(ngep->genlock); 22655574Smx205022 mutex_destroy(ngep->softlock); 22665574Smx205022 rw_destroy(ngep->rwlock); 22675574Smx205022 } 22685574Smx205022 22695574Smx205022 if (ngep->progress & PROGRESS_REGS) 22705574Smx205022 ddi_regs_map_free(&ngep->io_handle); 22715574Smx205022 22725574Smx205022 if (ngep->progress & PROGRESS_CFG) 22735574Smx205022 pci_config_teardown(&ngep->cfg_handle); 22745574Smx205022 22755574Smx205022 ddi_remove_minor_node(ngep->devinfo, NULL); 22765574Smx205022 22775574Smx205022 kmem_free(ngep, sizeof (*ngep)); 22785574Smx205022 } 22795574Smx205022 22805574Smx205022 static int 22815574Smx205022 nge_resume(dev_info_t *devinfo) 22825574Smx205022 { 22835574Smx205022 nge_t *ngep; 22845574Smx205022 chip_info_t *infop; 22855869Smx205022 int err; 22865574Smx205022 22875574Smx205022 ASSERT(devinfo != NULL); 22885574Smx205022 22895574Smx205022 ngep = ddi_get_driver_private(devinfo); 22905869Smx205022 err = 0; 22915869Smx205022 22925574Smx205022 /* 22935574Smx205022 * If there are state inconsistancies, this is bad. Returning 22945574Smx205022 * DDI_FAILURE here will eventually cause the machine to panic, 22955574Smx205022 * so it is best done here so that there is a possibility of 22965574Smx205022 * debugging the problem. 22975574Smx205022 */ 22985574Smx205022 if (ngep == NULL) 22995574Smx205022 cmn_err(CE_PANIC, 23005574Smx205022 "nge: ngep returned from ddi_get_driver_private was NULL"); 23015574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 23025574Smx205022 23035574Smx205022 if (ngep->devinfo != devinfo) 23045574Smx205022 cmn_err(CE_PANIC, 23055869Smx205022 "nge: passed devinfo not the same as saved devinfo"); 23065574Smx205022 23075869Smx205022 mutex_enter(ngep->genlock); 23085869Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 23095574Smx205022 23105574Smx205022 /* 23115574Smx205022 * Fetch the config space. Even though we have most of it cached, 23125574Smx205022 * some values *might* change across a suspend/resume. 23135574Smx205022 */ 23145574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 23155574Smx205022 23165574Smx205022 /* 23175869Smx205022 * Only in one case, this conditional branch can be executed: the port 23185869Smx205022 * hasn't been plumbed. 23195574Smx205022 */ 23205869Smx205022 if (ngep->suspended == B_FALSE) { 23215869Smx205022 rw_exit(ngep->rwlock); 23225869Smx205022 mutex_exit(ngep->genlock); 23235869Smx205022 return (DDI_SUCCESS); 23245869Smx205022 } 23255869Smx205022 23265869Smx205022 nge_tx_recycle_all(ngep); 23275869Smx205022 err = nge_reinit_ring(ngep); 23285869Smx205022 if (!err) { 23295869Smx205022 err = nge_chip_reset(ngep); 23305869Smx205022 if (!err) 23315869Smx205022 err = nge_chip_start(ngep); 23325869Smx205022 } 23335869Smx205022 23345869Smx205022 if (err) { 23355574Smx205022 /* 23365574Smx205022 * We note the failure, but return success, as the 23375574Smx205022 * system is still usable without this controller. 23385574Smx205022 */ 23395574Smx205022 cmn_err(CE_WARN, "nge: resume: failed to restart controller"); 23405869Smx205022 } else { 23415869Smx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 23425574Smx205022 } 23435869Smx205022 ngep->suspended = B_FALSE; 23445869Smx205022 23455869Smx205022 rw_exit(ngep->rwlock); 23465869Smx205022 mutex_exit(ngep->genlock); 23475869Smx205022 23485574Smx205022 return (DDI_SUCCESS); 23495574Smx205022 } 23505574Smx205022 23515574Smx205022 /* 23525574Smx205022 * attach(9E) -- Attach a device to the system 23535574Smx205022 * 23545574Smx205022 * Called once for each board successfully probed. 23555574Smx205022 */ 23565574Smx205022 static int 23575574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 23585574Smx205022 { 23595574Smx205022 int err; 23605574Smx205022 int i; 23615574Smx205022 int instance; 23625574Smx205022 caddr_t regs; 23635574Smx205022 nge_t *ngep; 23645574Smx205022 chip_info_t *infop; 23655574Smx205022 mac_register_t *macp; 23665574Smx205022 23675574Smx205022 switch (cmd) { 23685574Smx205022 default: 23695574Smx205022 return (DDI_FAILURE); 23705574Smx205022 23715574Smx205022 case DDI_RESUME: 23725574Smx205022 return (nge_resume(devinfo)); 23735574Smx205022 23745574Smx205022 case DDI_ATTACH: 23755574Smx205022 break; 23765574Smx205022 } 23775574Smx205022 23785574Smx205022 ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP); 23795574Smx205022 instance = ddi_get_instance(devinfo); 23805574Smx205022 ddi_set_driver_private(devinfo, ngep); 23815574Smx205022 ngep->devinfo = devinfo; 23825574Smx205022 23835574Smx205022 (void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d", 23845574Smx205022 NGE_DRIVER_NAME, instance); 23855574Smx205022 err = pci_config_setup(devinfo, &ngep->cfg_handle); 23865574Smx205022 if (err != DDI_SUCCESS) { 23875574Smx205022 nge_problem(ngep, "nge_attach: pci_config_setup() failed"); 23885574Smx205022 goto attach_fail; 23895574Smx205022 } 23906512Ssowmini /* 23916512Ssowmini * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy 23926512Ssowmini * thresholds. Bounds: min 0, max NGE_MAX_SDU 23936512Ssowmini */ 23946512Ssowmini ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE; 23956512Ssowmini ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE; 23966512Ssowmini 23976512Ssowmini /* 23986512Ssowmini * param_recv_max_packet is max packet received per interupt. 23996512Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024 24006512Ssowmini */ 24016512Ssowmini ngep->param_recv_max_packet = 128; 24026512Ssowmini 24036512Ssowmini /* 24046512Ssowmini * param_poll_quiet_time and param_poll_busy_time are quiet/busy time 24056512Ssowmini * switch from per packet interrupt to polling interrupt. 24066512Ssowmini * Bounds: min 0, max 10000 24076512Ssowmini */ 24086512Ssowmini ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME; 24096512Ssowmini ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME; 24106512Ssowmini 24116512Ssowmini /* 24126512Ssowmini * param_rx_intr_hwater/param_rx_intr_lwater: ackets received 24136512Ssowmini * to trigger the poll_quiet_time/poll_busy_time counter. 24146512Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024. 24156512Ssowmini */ 24166512Ssowmini ngep->param_rx_intr_hwater = 1; 24176512Ssowmini ngep->param_rx_intr_lwater = 8; 24186512Ssowmini 24196512Ssowmini /* 24206512Ssowmini * param_tx_n_intr: Per N tx packets to do tx recycle in poll mode. 24216512Ssowmini * Bounds: min 1, max 10000. 24226512Ssowmini */ 24236512Ssowmini ngep->param_tx_n_intr = NGE_TX_N_INTR; 24246512Ssowmini 24255574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 24265574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 24275574Smx205022 nge_init_dev_spec_param(ngep); 24285574Smx205022 nge_get_props(ngep); 24295574Smx205022 ngep->progress |= PROGRESS_CFG; 24305574Smx205022 24315574Smx205022 err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER, 24325574Smx205022 ®s, 0, 0, &nge_reg_accattr, &ngep->io_handle); 24335574Smx205022 if (err != DDI_SUCCESS) { 24345574Smx205022 nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed"); 24355574Smx205022 goto attach_fail; 24365574Smx205022 } 24375574Smx205022 ngep->io_regs = regs; 24385574Smx205022 ngep->progress |= PROGRESS_REGS; 24395574Smx205022 24405574Smx205022 err = nge_register_intrs_and_init_locks(ngep); 24415574Smx205022 if (err != DDI_SUCCESS) { 24425574Smx205022 nge_problem(ngep, "nge_attach:" 24435574Smx205022 " register intrs and init locks failed"); 24445574Smx205022 goto attach_fail; 24455574Smx205022 } 24465574Smx205022 nge_init_ring_param_lock(ngep); 24475574Smx205022 ngep->progress |= PROGRESS_INTR; 24485574Smx205022 24495574Smx205022 mutex_enter(ngep->genlock); 24505574Smx205022 24515574Smx205022 /* 24525574Smx205022 * Initialise link state variables 24535574Smx205022 * Stop, reset & reinitialise the chip. 24545574Smx205022 * Initialise the (internal) PHY. 24555574Smx205022 */ 24565574Smx205022 nge_phys_init(ngep); 2457*8218SMin.Xu@Sun.COM ngep->nge_chip_state = NGE_CHIP_INITIAL; 24585574Smx205022 err = nge_chip_reset(ngep); 24595574Smx205022 if (err != DDI_SUCCESS) { 24605574Smx205022 nge_problem(ngep, "nge_attach: nge_chip_reset() failed"); 24615574Smx205022 mutex_exit(ngep->genlock); 24625574Smx205022 goto attach_fail; 24635574Smx205022 } 24645574Smx205022 nge_chip_sync(ngep); 24655574Smx205022 24665574Smx205022 /* 24675574Smx205022 * Now that mutex locks are initialized, enable interrupts. 24685574Smx205022 */ 24695574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 24705574Smx205022 /* Call ddi_intr_block_enable() for MSI interrupts */ 24715574Smx205022 (void) ddi_intr_block_enable(ngep->htable, 24725574Smx205022 ngep->intr_actual_cnt); 24735574Smx205022 } else { 24745574Smx205022 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 24755574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 24765574Smx205022 (void) ddi_intr_enable(ngep->htable[i]); 24775574Smx205022 } 24785574Smx205022 } 24795574Smx205022 24805574Smx205022 ngep->link_state = LINK_STATE_UNKNOWN; 24815574Smx205022 ngep->progress |= PROGRESS_HWINT; 24825574Smx205022 24835574Smx205022 /* 24845574Smx205022 * Register NDD-tweakable parameters 24855574Smx205022 */ 24865574Smx205022 if (nge_nd_init(ngep)) { 24875574Smx205022 nge_problem(ngep, "nge_attach: nge_nd_init() failed"); 24885574Smx205022 mutex_exit(ngep->genlock); 24895574Smx205022 goto attach_fail; 24905574Smx205022 } 24915574Smx205022 ngep->progress |= PROGRESS_NDD; 24925574Smx205022 24935574Smx205022 /* 24945574Smx205022 * Create & initialise named kstats 24955574Smx205022 */ 24965574Smx205022 nge_init_kstats(ngep, instance); 24975574Smx205022 ngep->progress |= PROGRESS_KSTATS; 24985574Smx205022 24995574Smx205022 mutex_exit(ngep->genlock); 25005574Smx205022 25015574Smx205022 if ((macp = mac_alloc(MAC_VERSION)) == NULL) 25025574Smx205022 goto attach_fail; 25035574Smx205022 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 25045574Smx205022 macp->m_driver = ngep; 25055574Smx205022 macp->m_dip = devinfo; 25065574Smx205022 macp->m_src_addr = infop->vendor_addr.addr; 25075574Smx205022 macp->m_callbacks = &nge_m_callbacks; 25085574Smx205022 macp->m_min_sdu = 0; 25095574Smx205022 macp->m_max_sdu = ngep->default_mtu; 25105895Syz147064 macp->m_margin = VTAG_SIZE; 25116512Ssowmini macp->m_priv_props = nge_priv_props; 25126512Ssowmini macp->m_priv_prop_count = NGE_MAX_PRIV_PROPS; 25135574Smx205022 /* 25145574Smx205022 * Finally, we're ready to register ourselves with the mac 25155574Smx205022 * interface; if this succeeds, we're all ready to start() 25165574Smx205022 */ 25175574Smx205022 err = mac_register(macp, &ngep->mh); 25185574Smx205022 mac_free(macp); 25195574Smx205022 if (err != 0) 25205574Smx205022 goto attach_fail; 25215574Smx205022 25225574Smx205022 /* 25235574Smx205022 * Register a periodical handler. 25245574Smx205022 * nge_chip_cyclic() is invoked in kernel context. 25255574Smx205022 */ 25265574Smx205022 ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep, 25275574Smx205022 NGE_CYCLIC_PERIOD, DDI_IPL_0); 25285574Smx205022 25295574Smx205022 ngep->progress |= PROGRESS_READY; 25305574Smx205022 return (DDI_SUCCESS); 25315574Smx205022 25325574Smx205022 attach_fail: 25335574Smx205022 nge_unattach(ngep); 25345574Smx205022 return (DDI_FAILURE); 25355574Smx205022 } 25365574Smx205022 25375869Smx205022 static int 25385869Smx205022 nge_suspend(nge_t *ngep) 25395869Smx205022 { 25405869Smx205022 mutex_enter(ngep->genlock); 25415869Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 25425869Smx205022 25435869Smx205022 /* if the port hasn't been plumbed, just return */ 25445869Smx205022 if (ngep->nge_mac_state != NGE_MAC_STARTED) { 25455869Smx205022 rw_exit(ngep->rwlock); 25465869Smx205022 mutex_exit(ngep->genlock); 25475869Smx205022 return (DDI_SUCCESS); 25485869Smx205022 } 25495869Smx205022 ngep->suspended = B_TRUE; 25505869Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 25515869Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 25525869Smx205022 25535869Smx205022 rw_exit(ngep->rwlock); 25545869Smx205022 mutex_exit(ngep->genlock); 25555869Smx205022 return (DDI_SUCCESS); 25565869Smx205022 } 25575869Smx205022 25585574Smx205022 /* 25595574Smx205022 * detach(9E) -- Detach a device from the system 25605574Smx205022 */ 25615574Smx205022 static int 25625574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 25635574Smx205022 { 25645574Smx205022 int i; 25655574Smx205022 nge_t *ngep; 25665574Smx205022 mul_item *p, *nextp; 25675574Smx205022 buff_ring_t *brp; 25685574Smx205022 25695574Smx205022 NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd)); 25705574Smx205022 25715574Smx205022 ngep = ddi_get_driver_private(devinfo); 25725574Smx205022 brp = ngep->buff; 25735574Smx205022 25745574Smx205022 switch (cmd) { 25755574Smx205022 default: 25765574Smx205022 return (DDI_FAILURE); 25775574Smx205022 25785574Smx205022 case DDI_SUSPEND: 25795574Smx205022 /* 25805574Smx205022 * Stop the NIC 25815574Smx205022 * Note: This driver doesn't currently support WOL, but 25825574Smx205022 * should it in the future, it is important to 25835574Smx205022 * make sure the PHY remains powered so that the 25845574Smx205022 * wakeup packet can actually be recieved. 25855574Smx205022 */ 25865869Smx205022 return (nge_suspend(ngep)); 25875574Smx205022 25885574Smx205022 case DDI_DETACH: 25895574Smx205022 break; 25905574Smx205022 } 25915574Smx205022 25925574Smx205022 /* Try to wait all the buffer post to upper layer be released */ 25935574Smx205022 for (i = 0; i < 1000; i++) { 25945574Smx205022 if (brp->rx_hold == 0) 25955574Smx205022 break; 25965574Smx205022 drv_usecwait(1000); 25975574Smx205022 } 25985574Smx205022 25995574Smx205022 /* If there is any posted buffer, reject to detach */ 26005574Smx205022 if (brp->rx_hold != 0) 26015574Smx205022 return (DDI_FAILURE); 26025574Smx205022 26035574Smx205022 /* 26045574Smx205022 * Unregister from the GLD subsystem. This can fail, in 26055574Smx205022 * particular if there are DLPI style-2 streams still open - 26065574Smx205022 * in which case we just return failure without shutting 26075574Smx205022 * down chip operations. 26085574Smx205022 */ 26095574Smx205022 if (mac_unregister(ngep->mh) != DDI_SUCCESS) 26105574Smx205022 return (DDI_FAILURE); 26115574Smx205022 26125574Smx205022 /* 26136366Smx205022 * Recycle the multicast table. mac_unregister() should be called 26146366Smx205022 * before it to ensure the multicast table can be used even if 26156366Smx205022 * mac_unregister() fails. 26166366Smx205022 */ 26176366Smx205022 for (p = ngep->pcur_mulist; p != NULL; p = nextp) { 26186366Smx205022 nextp = p->next; 26196366Smx205022 kmem_free(p, sizeof (mul_item)); 26206366Smx205022 } 26216366Smx205022 ngep->pcur_mulist = NULL; 26226366Smx205022 26236366Smx205022 /* 26245574Smx205022 * All activity stopped, so we can clean up & exit 26255574Smx205022 */ 26265574Smx205022 nge_unattach(ngep); 26275574Smx205022 return (DDI_SUCCESS); 26285574Smx205022 } 26295574Smx205022 26307656SSherry.Moore@Sun.COM /* 26317656SSherry.Moore@Sun.COM * quiesce(9E) entry point. 26327656SSherry.Moore@Sun.COM * 26337656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high 26347656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 26357656SSherry.Moore@Sun.COM * blocked. 26367656SSherry.Moore@Sun.COM * 26377656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 26387656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 26397656SSherry.Moore@Sun.COM */ 26407656SSherry.Moore@Sun.COM static int 26417656SSherry.Moore@Sun.COM nge_quiesce(dev_info_t *devinfo) 26427656SSherry.Moore@Sun.COM { 26437656SSherry.Moore@Sun.COM nge_t *ngep; 26447656SSherry.Moore@Sun.COM 26457656SSherry.Moore@Sun.COM ngep = ddi_get_driver_private(devinfo); 26467656SSherry.Moore@Sun.COM 26477656SSherry.Moore@Sun.COM if (ngep == NULL) 26487656SSherry.Moore@Sun.COM return (DDI_FAILURE); 26497656SSherry.Moore@Sun.COM 26507656SSherry.Moore@Sun.COM /* 26517656SSherry.Moore@Sun.COM * Turn off debug tracing 26527656SSherry.Moore@Sun.COM */ 26537656SSherry.Moore@Sun.COM nge_debug = 0; 26547656SSherry.Moore@Sun.COM ngep->debug = 0; 26557656SSherry.Moore@Sun.COM 26567656SSherry.Moore@Sun.COM nge_restore_mac_addr(ngep); 26577656SSherry.Moore@Sun.COM (void) nge_chip_stop(ngep, B_FALSE); 26587656SSherry.Moore@Sun.COM 26597656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 26607656SSherry.Moore@Sun.COM } 26617656SSherry.Moore@Sun.COM 26627656SSherry.Moore@Sun.COM 26635574Smx205022 26645574Smx205022 /* 26655574Smx205022 * ========== Module Loading Data & Entry Points ========== 26665574Smx205022 */ 26675574Smx205022 26685574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach, 26697656SSherry.Moore@Sun.COM NULL, NULL, D_MP, NULL, nge_quiesce); 26705574Smx205022 26715574Smx205022 26725574Smx205022 static struct modldrv nge_modldrv = { 26735574Smx205022 &mod_driverops, /* Type of module. This one is a driver */ 26745574Smx205022 nge_ident, /* short description */ 26755574Smx205022 &nge_dev_ops /* driver specific ops */ 26765574Smx205022 }; 26775574Smx205022 26785574Smx205022 static struct modlinkage modlinkage = { 26795574Smx205022 MODREV_1, (void *)&nge_modldrv, NULL 26805574Smx205022 }; 26815574Smx205022 26825574Smx205022 26835574Smx205022 int 26845574Smx205022 _info(struct modinfo *modinfop) 26855574Smx205022 { 26865574Smx205022 return (mod_info(&modlinkage, modinfop)); 26875574Smx205022 } 26885574Smx205022 26895574Smx205022 int 26905574Smx205022 _init(void) 26915574Smx205022 { 26925574Smx205022 int status; 26935574Smx205022 26945574Smx205022 mac_init_ops(&nge_dev_ops, "nge"); 26955574Smx205022 status = mod_install(&modlinkage); 26965574Smx205022 if (status != DDI_SUCCESS) 26975574Smx205022 mac_fini_ops(&nge_dev_ops); 26985574Smx205022 else 26995574Smx205022 mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL); 27005574Smx205022 27015574Smx205022 return (status); 27025574Smx205022 } 27035574Smx205022 27045574Smx205022 int 27055574Smx205022 _fini(void) 27065574Smx205022 { 27075574Smx205022 int status; 27085574Smx205022 27095574Smx205022 status = mod_remove(&modlinkage); 27105574Smx205022 if (status == DDI_SUCCESS) { 27115574Smx205022 mac_fini_ops(&nge_dev_ops); 27125574Smx205022 mutex_destroy(nge_log_mutex); 27135574Smx205022 } 27145574Smx205022 27155574Smx205022 return (status); 27165574Smx205022 } 27175574Smx205022 27185574Smx205022 /* 27195574Smx205022 * ============ Init MSI/Fixed/SoftInterrupt routines ============== 27205574Smx205022 */ 27215574Smx205022 27225574Smx205022 /* 27235574Smx205022 * Register interrupts and initialize each mutex and condition variables 27245574Smx205022 */ 27255574Smx205022 27265574Smx205022 static int 27275574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep) 27285574Smx205022 { 27295574Smx205022 int err; 27305574Smx205022 int intr_types; 27315574Smx205022 uint_t soft_prip; 27325574Smx205022 nge_msi_mask msi_mask; 27335574Smx205022 nge_msi_map0_vec map0_vec; 27345574Smx205022 nge_msi_map1_vec map1_vec; 27355574Smx205022 27365574Smx205022 /* 27375574Smx205022 * Add the softint handlers: 27385574Smx205022 * 27395574Smx205022 * Both of these handlers are used to avoid restrictions on the 27405574Smx205022 * context and/or mutexes required for some operations. In 27415574Smx205022 * particular, the hardware interrupt handler and its subfunctions 27425574Smx205022 * can detect a number of conditions that we don't want to handle 27435574Smx205022 * in that context or with that set of mutexes held. So, these 27445574Smx205022 * softints are triggered instead: 27455574Smx205022 * 27465574Smx205022 * the <resched> softint is triggered if if we have previously 27475574Smx205022 * had to refuse to send a packet because of resource shortage 27485574Smx205022 * (we've run out of transmit buffers), but the send completion 27495574Smx205022 * interrupt handler has now detected that more buffers have 27505574Smx205022 * become available. Its only purpose is to call gld_sched() 27515574Smx205022 * to retry the pending transmits (we're not allowed to hold 27525574Smx205022 * driver-defined mutexes across gld_sched()). 27535574Smx205022 * 27545574Smx205022 * the <factotum> is triggered if the h/w interrupt handler 27555574Smx205022 * sees the <link state changed> or <error> bits in the status 27565574Smx205022 * block. It's also triggered periodically to poll the link 27575574Smx205022 * state, just in case we aren't getting link status change 27585574Smx205022 * interrupts ... 27595574Smx205022 */ 27605574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl, 27615574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep); 27625574Smx205022 if (err != DDI_SUCCESS) { 27635574Smx205022 nge_problem(ngep, 27645574Smx205022 "nge_attach: add nge_reschedule softintr failed"); 27655574Smx205022 27665574Smx205022 return (DDI_FAILURE); 27675574Smx205022 } 27685574Smx205022 ngep->progress |= PROGRESS_RESCHED; 27695574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl, 27705574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep); 27715574Smx205022 if (err != DDI_SUCCESS) { 27725574Smx205022 nge_problem(ngep, 27735574Smx205022 "nge_attach: add nge_chip_factotum softintr failed!"); 27745574Smx205022 27755574Smx205022 return (DDI_FAILURE); 27765574Smx205022 } 27775574Smx205022 if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip) 27785574Smx205022 != DDI_SUCCESS) { 27795574Smx205022 nge_problem(ngep, "nge_attach: get softintr priority failed\n"); 27805574Smx205022 27815574Smx205022 return (DDI_FAILURE); 27825574Smx205022 } 27835574Smx205022 ngep->soft_pri = soft_prip; 27845574Smx205022 27855574Smx205022 ngep->progress |= PROGRESS_FACTOTUM; 27865574Smx205022 /* Get supported interrupt types */ 27875574Smx205022 if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types) 27885574Smx205022 != DDI_SUCCESS) { 27895574Smx205022 nge_error(ngep, "ddi_intr_get_supported_types failed\n"); 27905574Smx205022 27915574Smx205022 return (DDI_FAILURE); 27925574Smx205022 } 27935574Smx205022 27945574Smx205022 NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x", 27955574Smx205022 intr_types)); 27965574Smx205022 27975574Smx205022 if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) { 27985574Smx205022 27995574Smx205022 /* MSI Configurations for mcp55 chipset */ 28005574Smx205022 if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 28015574Smx205022 ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 28025574Smx205022 28035574Smx205022 28045574Smx205022 /* Enable the 8 vectors */ 28055574Smx205022 msi_mask.msi_mask_val = 28065574Smx205022 nge_reg_get32(ngep, NGE_MSI_MASK); 28075574Smx205022 msi_mask.msi_msk_bits.vec0 = NGE_SET; 28085574Smx205022 msi_mask.msi_msk_bits.vec1 = NGE_SET; 28095574Smx205022 msi_mask.msi_msk_bits.vec2 = NGE_SET; 28105574Smx205022 msi_mask.msi_msk_bits.vec3 = NGE_SET; 28115574Smx205022 msi_mask.msi_msk_bits.vec4 = NGE_SET; 28125574Smx205022 msi_mask.msi_msk_bits.vec5 = NGE_SET; 28135574Smx205022 msi_mask.msi_msk_bits.vec6 = NGE_SET; 28145574Smx205022 msi_mask.msi_msk_bits.vec7 = NGE_SET; 28155574Smx205022 nge_reg_put32(ngep, NGE_MSI_MASK, 28165574Smx205022 msi_mask.msi_mask_val); 28175574Smx205022 28185574Smx205022 /* 28195574Smx205022 * Remapping the MSI MAP0 and MAP1. MCP55 28205574Smx205022 * is default mapping all the interrupt to 0 vector. 28215574Smx205022 * Software needs to remapping this. 28225574Smx205022 * This mapping is same as CK804. 28235574Smx205022 */ 28245574Smx205022 map0_vec.msi_map0_val = 28255574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP0); 28265574Smx205022 map1_vec.msi_map1_val = 28275574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP1); 28285574Smx205022 map0_vec.vecs_bits.reint_vec = 0; 28295574Smx205022 map0_vec.vecs_bits.rcint_vec = 0; 28305574Smx205022 map0_vec.vecs_bits.miss_vec = 3; 28315574Smx205022 map0_vec.vecs_bits.teint_vec = 5; 28325574Smx205022 map0_vec.vecs_bits.tcint_vec = 5; 28335574Smx205022 map0_vec.vecs_bits.stint_vec = 2; 28345574Smx205022 map0_vec.vecs_bits.mint_vec = 6; 28355574Smx205022 map0_vec.vecs_bits.rfint_vec = 0; 28365574Smx205022 map1_vec.vecs_bits.tfint_vec = 5; 28375574Smx205022 map1_vec.vecs_bits.feint_vec = 6; 28385574Smx205022 map1_vec.vecs_bits.resv8_11 = 3; 28395574Smx205022 map1_vec.vecs_bits.resv12_15 = 1; 28405574Smx205022 map1_vec.vecs_bits.resv16_19 = 0; 28415574Smx205022 map1_vec.vecs_bits.resv20_23 = 7; 28425574Smx205022 map1_vec.vecs_bits.resv24_31 = 0xff; 28435574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP0, 28445574Smx205022 map0_vec.msi_map0_val); 28455574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP1, 28465574Smx205022 map1_vec.msi_map1_val); 28475574Smx205022 } 28485574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 28495574Smx205022 NGE_DEBUG(("MSI registration failed, " 28505574Smx205022 "trying FIXED interrupt type\n")); 28515574Smx205022 } else { 28525574Smx205022 nge_log(ngep, "Using MSI interrupt type\n"); 28535574Smx205022 28545574Smx205022 ngep->intr_type = DDI_INTR_TYPE_MSI; 28555574Smx205022 ngep->progress |= PROGRESS_SWINT; 28565574Smx205022 } 28575574Smx205022 } 28585574Smx205022 28595574Smx205022 if (!(ngep->progress & PROGRESS_SWINT) && 28605574Smx205022 (intr_types & DDI_INTR_TYPE_FIXED)) { 28615574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 28625574Smx205022 nge_error(ngep, "FIXED interrupt " 28635574Smx205022 "registration failed\n"); 28645574Smx205022 28655574Smx205022 return (DDI_FAILURE); 28665574Smx205022 } 28675574Smx205022 28685574Smx205022 nge_log(ngep, "Using FIXED interrupt type\n"); 28695574Smx205022 28705574Smx205022 ngep->intr_type = DDI_INTR_TYPE_FIXED; 28715574Smx205022 ngep->progress |= PROGRESS_SWINT; 28725574Smx205022 } 28735574Smx205022 28745574Smx205022 28755574Smx205022 if (!(ngep->progress & PROGRESS_SWINT)) { 28765574Smx205022 nge_error(ngep, "No interrupts registered\n"); 28775574Smx205022 28785574Smx205022 return (DDI_FAILURE); 28795574Smx205022 } 28805574Smx205022 mutex_init(ngep->genlock, NULL, MUTEX_DRIVER, 28815574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 28825574Smx205022 mutex_init(ngep->softlock, NULL, MUTEX_DRIVER, 28835574Smx205022 DDI_INTR_PRI(ngep->soft_pri)); 28845574Smx205022 rw_init(ngep->rwlock, NULL, RW_DRIVER, 28855574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 28865574Smx205022 28875574Smx205022 return (DDI_SUCCESS); 28885574Smx205022 } 28895574Smx205022 28905574Smx205022 /* 28915574Smx205022 * nge_add_intrs: 28925574Smx205022 * 28935574Smx205022 * Register FIXED or MSI interrupts. 28945574Smx205022 */ 28955574Smx205022 static int 28965574Smx205022 nge_add_intrs(nge_t *ngep, int intr_type) 28975574Smx205022 { 28985574Smx205022 dev_info_t *dip = ngep->devinfo; 28995574Smx205022 int avail, actual, intr_size, count = 0; 29005574Smx205022 int i, flag, ret; 29015574Smx205022 29025574Smx205022 NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type)); 29035574Smx205022 29045574Smx205022 /* Get number of interrupts */ 29055574Smx205022 ret = ddi_intr_get_nintrs(dip, intr_type, &count); 29065574Smx205022 if ((ret != DDI_SUCCESS) || (count == 0)) { 29075574Smx205022 nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, " 29085574Smx205022 "count: %d", ret, count); 29095574Smx205022 29105574Smx205022 return (DDI_FAILURE); 29115574Smx205022 } 29125574Smx205022 29135574Smx205022 /* Get number of available interrupts */ 29145574Smx205022 ret = ddi_intr_get_navail(dip, intr_type, &avail); 29155574Smx205022 if ((ret != DDI_SUCCESS) || (avail == 0)) { 29165574Smx205022 nge_error(ngep, "ddi_intr_get_navail() failure, " 29175574Smx205022 "ret: %d, avail: %d\n", ret, avail); 29185574Smx205022 29195574Smx205022 return (DDI_FAILURE); 29205574Smx205022 } 29215574Smx205022 29225574Smx205022 if (avail < count) { 29235574Smx205022 NGE_DEBUG(("nitrs() returned %d, navail returned %d\n", 29245574Smx205022 count, avail)); 29255574Smx205022 } 29265574Smx205022 flag = DDI_INTR_ALLOC_NORMAL; 29275574Smx205022 29285574Smx205022 /* Allocate an array of interrupt handles */ 29295574Smx205022 intr_size = count * sizeof (ddi_intr_handle_t); 29305574Smx205022 ngep->htable = kmem_alloc(intr_size, KM_SLEEP); 29315574Smx205022 29325574Smx205022 /* Call ddi_intr_alloc() */ 29335574Smx205022 ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0, 29345574Smx205022 count, &actual, flag); 29355574Smx205022 29365574Smx205022 if ((ret != DDI_SUCCESS) || (actual == 0)) { 29375574Smx205022 nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret); 29385574Smx205022 29395574Smx205022 kmem_free(ngep->htable, intr_size); 29405574Smx205022 return (DDI_FAILURE); 29415574Smx205022 } 29425574Smx205022 29435574Smx205022 if (actual < count) { 29445574Smx205022 NGE_DEBUG(("Requested: %d, Received: %d\n", 29455574Smx205022 count, actual)); 29465574Smx205022 } 29475574Smx205022 29485574Smx205022 ngep->intr_actual_cnt = actual; 29495574Smx205022 ngep->intr_req_cnt = count; 29505574Smx205022 29515574Smx205022 /* 29525574Smx205022 * Get priority for first msi, assume remaining are all the same 29535574Smx205022 */ 29545574Smx205022 if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) != 29555574Smx205022 DDI_SUCCESS) { 29565574Smx205022 nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret); 29575574Smx205022 29585574Smx205022 /* Free already allocated intr */ 29595574Smx205022 for (i = 0; i < actual; i++) { 29605574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 29615574Smx205022 } 29625574Smx205022 29635574Smx205022 kmem_free(ngep->htable, intr_size); 29645574Smx205022 29655574Smx205022 return (DDI_FAILURE); 29665574Smx205022 } 29675574Smx205022 /* Test for high level mutex */ 29685574Smx205022 if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) { 29695574Smx205022 nge_error(ngep, "nge_add_intrs:" 29705574Smx205022 "Hi level interrupt not supported"); 29715574Smx205022 29725574Smx205022 for (i = 0; i < actual; i++) 29735574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 29745574Smx205022 29755574Smx205022 kmem_free(ngep->htable, intr_size); 29765574Smx205022 29775574Smx205022 return (DDI_FAILURE); 29785574Smx205022 } 29795574Smx205022 29805574Smx205022 29815574Smx205022 /* Call ddi_intr_add_handler() */ 29825574Smx205022 for (i = 0; i < actual; i++) { 29835574Smx205022 if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr, 29845574Smx205022 (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 29855574Smx205022 nge_error(ngep, "ddi_intr_add_handler() " 29865574Smx205022 "failed %d\n", ret); 29875574Smx205022 29885574Smx205022 /* Free already allocated intr */ 29895574Smx205022 for (i = 0; i < actual; i++) { 29905574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 29915574Smx205022 } 29925574Smx205022 29935574Smx205022 kmem_free(ngep->htable, intr_size); 29945574Smx205022 29955574Smx205022 return (DDI_FAILURE); 29965574Smx205022 } 29975574Smx205022 } 29985574Smx205022 29995574Smx205022 if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap)) 30005574Smx205022 != DDI_SUCCESS) { 30015574Smx205022 nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret); 30025574Smx205022 30035574Smx205022 for (i = 0; i < actual; i++) { 30045574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 30055574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30065574Smx205022 } 30075574Smx205022 30085574Smx205022 kmem_free(ngep->htable, intr_size); 30095574Smx205022 30105574Smx205022 return (DDI_FAILURE); 30115574Smx205022 } 30125574Smx205022 30135574Smx205022 return (DDI_SUCCESS); 30145574Smx205022 } 30155574Smx205022 30165574Smx205022 /* 30175574Smx205022 * nge_rem_intrs: 30185574Smx205022 * 30195574Smx205022 * Unregister FIXED or MSI interrupts 30205574Smx205022 */ 30215574Smx205022 static void 30225574Smx205022 nge_rem_intrs(nge_t *ngep) 30235574Smx205022 { 30245574Smx205022 int i; 30255574Smx205022 30265574Smx205022 NGE_DEBUG(("nge_rem_intrs\n")); 30275574Smx205022 30285574Smx205022 /* Disable all interrupts */ 30295574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 30305574Smx205022 /* Call ddi_intr_block_disable() */ 30315574Smx205022 (void) ddi_intr_block_disable(ngep->htable, 30325574Smx205022 ngep->intr_actual_cnt); 30335574Smx205022 } else { 30345574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 30355574Smx205022 (void) ddi_intr_disable(ngep->htable[i]); 30365574Smx205022 } 30375574Smx205022 } 30385574Smx205022 30395574Smx205022 /* Call ddi_intr_remove_handler() */ 30405574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 30415574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 30425574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30435574Smx205022 } 30445574Smx205022 30455574Smx205022 kmem_free(ngep->htable, 30465574Smx205022 ngep->intr_req_cnt * sizeof (ddi_intr_handle_t)); 30475574Smx205022 } 3048