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 /* 239514SGirish.Moodalbail@Sun.COM * Copyright 2009 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"; 1688218SMin.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, 1995574Smx205022 nge_m_ioctl, 2006200Smx205022 nge_m_getcapab, 2016200Smx205022 NULL, 2026200Smx205022 NULL, 2036200Smx205022 nge_m_setprop, 2046200Smx205022 nge_m_getprop 2055574Smx205022 }; 2065574Smx205022 2076512Ssowmini mac_priv_prop_t nge_priv_props[] = { 2086512Ssowmini {"_tx_bcopy_threshold", MAC_PROP_PERM_RW}, 2096512Ssowmini {"_rx_bcopy_threshold", MAC_PROP_PERM_RW}, 2106512Ssowmini {"_recv_max_packet", MAC_PROP_PERM_RW}, 2116512Ssowmini {"_poll_quiet_time", MAC_PROP_PERM_RW}, 2126512Ssowmini {"_poll_busy_time", MAC_PROP_PERM_RW}, 2136512Ssowmini {"_rx_intr_hwater", MAC_PROP_PERM_RW}, 2146512Ssowmini {"_rx_intr_lwater", MAC_PROP_PERM_RW}, 2156512Ssowmini {"_adv_pause_cap", MAC_PROP_PERM_RW}, 2166512Ssowmini {"_adv_asym_pause_cap", MAC_PROP_PERM_RW}, 2176512Ssowmini {"_tx_n_intr", MAC_PROP_PERM_RW} 2186512Ssowmini }; 2196512Ssowmini 2206512Ssowmini #define NGE_MAX_PRIV_PROPS \ 2216512Ssowmini (sizeof (nge_priv_props)/sizeof (mac_priv_prop_t)) 2226512Ssowmini 2235574Smx205022 static int nge_add_intrs(nge_t *, int); 2245574Smx205022 static void nge_rem_intrs(nge_t *); 2255574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *); 2265574Smx205022 2275574Smx205022 /* 2285574Smx205022 * NGE MSI tunable: 2295574Smx205022 */ 2305574Smx205022 boolean_t nge_enable_msi = B_FALSE; 2315574Smx205022 2325574Smx205022 static enum ioc_reply 2335574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode) 2345574Smx205022 { 2355574Smx205022 /* 2365574Smx205022 * If the mode isn't being changed, there's nothing to do ... 2375574Smx205022 */ 2385574Smx205022 if (mode == ngep->param_loop_mode) 2395574Smx205022 return (IOC_ACK); 2405574Smx205022 2415574Smx205022 /* 2425574Smx205022 * Validate the requested mode and prepare a suitable message 2435574Smx205022 * to explain the link down/up cycle that the change will 2445574Smx205022 * probably induce ... 2455574Smx205022 */ 2465574Smx205022 switch (mode) { 2475574Smx205022 default: 2485574Smx205022 return (IOC_INVAL); 2495574Smx205022 2505574Smx205022 case NGE_LOOP_NONE: 2515574Smx205022 case NGE_LOOP_EXTERNAL_100: 2525574Smx205022 case NGE_LOOP_EXTERNAL_10: 2535574Smx205022 case NGE_LOOP_INTERNAL_PHY: 2545574Smx205022 break; 2555574Smx205022 } 2565574Smx205022 2575574Smx205022 /* 2585574Smx205022 * All OK; tell the caller to reprogram 2595574Smx205022 * the PHY and/or MAC for the new mode ... 2605574Smx205022 */ 2615574Smx205022 ngep->param_loop_mode = mode; 2625574Smx205022 return (IOC_RESTART_ACK); 2635574Smx205022 } 2645574Smx205022 2655574Smx205022 #undef NGE_DBG 2665574Smx205022 #define NGE_DBG NGE_DBG_INIT 2675574Smx205022 2685574Smx205022 /* 2695574Smx205022 * Utility routine to carve a slice off a chunk of allocated memory, 2705574Smx205022 * updating the chunk descriptor accordingly. The size of the slice 2715574Smx205022 * is given by the product of the <qty> and <size> parameters. 2725574Smx205022 */ 2735574Smx205022 void 2745574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 2755574Smx205022 uint32_t qty, uint32_t size) 2765574Smx205022 { 2775574Smx205022 size_t totsize; 2785574Smx205022 2795574Smx205022 totsize = qty*size; 2805574Smx205022 ASSERT(size > 0); 2815574Smx205022 ASSERT(totsize <= chunk->alength); 2825574Smx205022 2835574Smx205022 *slice = *chunk; 2845574Smx205022 slice->nslots = qty; 2855574Smx205022 slice->size = size; 2865574Smx205022 slice->alength = totsize; 2875574Smx205022 2885574Smx205022 chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 2895574Smx205022 chunk->alength -= totsize; 2905574Smx205022 chunk->offset += totsize; 2915574Smx205022 chunk->cookie.dmac_laddress += totsize; 2925574Smx205022 chunk->cookie.dmac_size -= totsize; 2935574Smx205022 } 2945574Smx205022 2955574Smx205022 /* 2965574Smx205022 * Allocate an area of memory and a DMA handle for accessing it 2975574Smx205022 */ 2985574Smx205022 int 2995574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p, 3005574Smx205022 uint_t dma_flags, dma_area_t *dma_p) 3015574Smx205022 { 3025574Smx205022 int err; 3035574Smx205022 caddr_t va; 3045574Smx205022 3055574Smx205022 NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 3065574Smx205022 (void *)ngep, memsize, attr_p, dma_flags, dma_p)); 3075574Smx205022 /* 3085574Smx205022 * Allocate handle 3095574Smx205022 */ 3105574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr, 3115574Smx205022 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 3125574Smx205022 if (err != DDI_SUCCESS) 3135574Smx205022 goto fail; 3145574Smx205022 3155574Smx205022 /* 3165574Smx205022 * Allocate memory 3175574Smx205022 */ 3185574Smx205022 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 3195574Smx205022 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 3205574Smx205022 DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl); 3215574Smx205022 if (err != DDI_SUCCESS) 3225574Smx205022 goto fail; 3235574Smx205022 3245574Smx205022 /* 3255574Smx205022 * Bind the two together 3265574Smx205022 */ 3275574Smx205022 dma_p->mem_va = va; 3285574Smx205022 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 3295574Smx205022 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 3305574Smx205022 &dma_p->cookie, &dma_p->ncookies); 3315574Smx205022 3325574Smx205022 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 3335574Smx205022 goto fail; 3345574Smx205022 3355574Smx205022 dma_p->nslots = ~0U; 3365574Smx205022 dma_p->size = ~0U; 3375574Smx205022 dma_p->offset = 0; 3385574Smx205022 3395574Smx205022 return (DDI_SUCCESS); 3405574Smx205022 3415574Smx205022 fail: 3425574Smx205022 nge_free_dma_mem(dma_p); 3435574Smx205022 NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!")); 3445574Smx205022 3455574Smx205022 return (DDI_FAILURE); 3465574Smx205022 } 3475574Smx205022 3485574Smx205022 /* 3495574Smx205022 * Free one allocated area of DMAable memory 3505574Smx205022 */ 3515574Smx205022 void 3525574Smx205022 nge_free_dma_mem(dma_area_t *dma_p) 3535574Smx205022 { 3545574Smx205022 if (dma_p->dma_hdl != NULL) { 3555574Smx205022 if (dma_p->ncookies) { 3565574Smx205022 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 3575574Smx205022 dma_p->ncookies = 0; 3585574Smx205022 } 3595574Smx205022 } 3605574Smx205022 if (dma_p->acc_hdl != NULL) { 3615574Smx205022 ddi_dma_mem_free(&dma_p->acc_hdl); 3625574Smx205022 dma_p->acc_hdl = NULL; 3635574Smx205022 } 3645574Smx205022 if (dma_p->dma_hdl != NULL) { 3655574Smx205022 ddi_dma_free_handle(&dma_p->dma_hdl); 3665574Smx205022 dma_p->dma_hdl = NULL; 3675574Smx205022 } 3685574Smx205022 } 3695574Smx205022 3705574Smx205022 #define ALLOC_TX_BUF 0x1 3715574Smx205022 #define ALLOC_TX_DESC 0x2 3725574Smx205022 #define ALLOC_RX_DESC 0x4 3735574Smx205022 3745574Smx205022 int 3755574Smx205022 nge_alloc_bufs(nge_t *ngep) 3765574Smx205022 { 3775574Smx205022 int err; 3785574Smx205022 int split; 3795574Smx205022 int progress; 3805574Smx205022 size_t txbuffsize; 3815574Smx205022 size_t rxdescsize; 3825574Smx205022 size_t txdescsize; 3835574Smx205022 3845574Smx205022 txbuffsize = ngep->tx_desc * ngep->buf_size; 3855574Smx205022 rxdescsize = ngep->rx_desc; 3865574Smx205022 txdescsize = ngep->tx_desc; 3875574Smx205022 rxdescsize *= ngep->desc_attr.rxd_size; 3885574Smx205022 txdescsize *= ngep->desc_attr.txd_size; 3895574Smx205022 progress = 0; 3905574Smx205022 3915574Smx205022 NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep)); 3925574Smx205022 /* 3935574Smx205022 * Allocate memory & handles for TX buffers 3945574Smx205022 */ 3955574Smx205022 ASSERT((txbuffsize % ngep->nge_split) == 0); 3965574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 3975574Smx205022 err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split, 3985574Smx205022 &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE, 3995574Smx205022 &ngep->send->buf[split]); 4005574Smx205022 if (err != DDI_SUCCESS) 4015574Smx205022 goto fail; 4025574Smx205022 } 4035574Smx205022 4045574Smx205022 progress |= ALLOC_TX_BUF; 4055574Smx205022 4065574Smx205022 /* 4075574Smx205022 * Allocate memory & handles for receive return rings and 4085574Smx205022 * buffer (producer) descriptor rings 4095574Smx205022 */ 4105574Smx205022 err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr, 4115574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc); 4125574Smx205022 if (err != DDI_SUCCESS) 4135574Smx205022 goto fail; 4145574Smx205022 progress |= ALLOC_RX_DESC; 4155574Smx205022 4165574Smx205022 /* 4175574Smx205022 * Allocate memory & handles for TX descriptor rings, 4185574Smx205022 */ 4195574Smx205022 err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr, 4205574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc); 4215574Smx205022 if (err != DDI_SUCCESS) 4225574Smx205022 goto fail; 4235574Smx205022 return (DDI_SUCCESS); 4245574Smx205022 4255574Smx205022 fail: 4265574Smx205022 if (progress & ALLOC_RX_DESC) 4275574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4285574Smx205022 if (progress & ALLOC_TX_BUF) { 4295574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4305574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4315574Smx205022 } 4325574Smx205022 4335574Smx205022 return (DDI_FAILURE); 4345574Smx205022 } 4355574Smx205022 4365574Smx205022 /* 4375574Smx205022 * This routine frees the transmit and receive buffers and descriptors. 4385574Smx205022 * Make sure the chip is stopped before calling it! 4395574Smx205022 */ 4405574Smx205022 void 4415574Smx205022 nge_free_bufs(nge_t *ngep) 4425574Smx205022 { 4435574Smx205022 int split; 4445574Smx205022 4455574Smx205022 NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep)); 4465574Smx205022 4475574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4485574Smx205022 nge_free_dma_mem(&ngep->send->desc); 4495574Smx205022 4505574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4515574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4525574Smx205022 } 4535574Smx205022 4545574Smx205022 /* 4555574Smx205022 * Clean up initialisation done above before the memory is freed 4565574Smx205022 */ 4575574Smx205022 static void 4585574Smx205022 nge_fini_send_ring(nge_t *ngep) 4595574Smx205022 { 4605574Smx205022 uint32_t slot; 4615574Smx205022 size_t dmah_num; 4625574Smx205022 send_ring_t *srp; 4635574Smx205022 sw_tx_sbd_t *ssbdp; 4645574Smx205022 4655574Smx205022 srp = ngep->send; 4665574Smx205022 ssbdp = srp->sw_sbds; 4675574Smx205022 4685574Smx205022 NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep)); 4695574Smx205022 4705574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 4715574Smx205022 4725574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 4735574Smx205022 if (srp->dmahndl[slot].hndl) { 4745574Smx205022 (void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl); 4755574Smx205022 ddi_dma_free_handle(&srp->dmahndl[slot].hndl); 4765574Smx205022 srp->dmahndl[slot].hndl = NULL; 4775574Smx205022 srp->dmahndl[slot].next = NULL; 4785574Smx205022 } 4795574Smx205022 } 4805574Smx205022 4815574Smx205022 srp->dmah_free.head = NULL; 4825574Smx205022 srp->dmah_free.tail = NULL; 4835574Smx205022 4845574Smx205022 kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp)); 4855574Smx205022 4865574Smx205022 } 4875574Smx205022 4885574Smx205022 /* 4895574Smx205022 * Initialise the specified Send Ring, using the information in the 4905574Smx205022 * <dma_area> descriptors that it contains to set up all the other 4915574Smx205022 * fields. This routine should be called only once for each ring. 4925574Smx205022 */ 4935574Smx205022 static int 4945574Smx205022 nge_init_send_ring(nge_t *ngep) 4955574Smx205022 { 4965574Smx205022 size_t dmah_num; 4975574Smx205022 uint32_t nslots; 4985574Smx205022 uint32_t err; 4995574Smx205022 uint32_t slot; 5005574Smx205022 uint32_t split; 5015574Smx205022 send_ring_t *srp; 5025574Smx205022 sw_tx_sbd_t *ssbdp; 5035574Smx205022 dma_area_t desc; 5045574Smx205022 dma_area_t pbuf; 5055574Smx205022 5065574Smx205022 srp = ngep->send; 5075574Smx205022 srp->desc.nslots = ngep->tx_desc; 5085574Smx205022 nslots = srp->desc.nslots; 5095574Smx205022 5105574Smx205022 NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep)); 5115574Smx205022 /* 5125574Smx205022 * Other one-off initialisation of per-ring data 5135574Smx205022 */ 5145574Smx205022 srp->ngep = ngep; 5155574Smx205022 5165574Smx205022 /* 5175574Smx205022 * Allocate the array of s/w Send Buffer Descriptors 5185574Smx205022 */ 5195574Smx205022 ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 5205574Smx205022 srp->sw_sbds = ssbdp; 5215574Smx205022 5225574Smx205022 /* 5235574Smx205022 * Now initialise each array element once and for all 5245574Smx205022 */ 5255574Smx205022 desc = srp->desc; 5265574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 5275574Smx205022 pbuf = srp->buf[split]; 5285574Smx205022 for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) { 5295574Smx205022 nge_slice_chunk(&ssbdp->desc, &desc, 1, 5305574Smx205022 ngep->desc_attr.txd_size); 5315574Smx205022 nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1, 5325574Smx205022 ngep->buf_size); 5335574Smx205022 } 5345574Smx205022 ASSERT(pbuf.alength == 0); 5355574Smx205022 } 5365574Smx205022 ASSERT(desc.alength == 0); 5375574Smx205022 5385574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5395574Smx205022 5405574Smx205022 /* preallocate dma handles for tx buffer */ 5415574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 5425574Smx205022 5435574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, 5445574Smx205022 ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT, 5455574Smx205022 NULL, &srp->dmahndl[slot].hndl); 5465574Smx205022 5475574Smx205022 if (err != DDI_SUCCESS) { 5485574Smx205022 nge_fini_send_ring(ngep); 5495574Smx205022 nge_error(ngep, 5505574Smx205022 "nge_init_send_ring: alloc dma handle fails"); 5515574Smx205022 return (DDI_FAILURE); 5525574Smx205022 } 5535574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5545574Smx205022 } 5555574Smx205022 5565574Smx205022 srp->dmah_free.head = srp->dmahndl; 5575574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5585574Smx205022 srp->dmah_free.tail->next = NULL; 5595574Smx205022 5605574Smx205022 return (DDI_SUCCESS); 5615574Smx205022 } 5625574Smx205022 5635574Smx205022 /* 5645574Smx205022 * Intialize the tx recycle pointer and tx sending pointer of tx ring 5655574Smx205022 * and set the type of tx's data descriptor by default. 5665574Smx205022 */ 5675574Smx205022 static void 5685574Smx205022 nge_reinit_send_ring(nge_t *ngep) 5695574Smx205022 { 5705574Smx205022 size_t dmah_num; 5715574Smx205022 uint32_t slot; 5725574Smx205022 send_ring_t *srp; 5735574Smx205022 sw_tx_sbd_t *ssbdp; 5745574Smx205022 5755574Smx205022 srp = ngep->send; 5765574Smx205022 5775574Smx205022 /* 5785574Smx205022 * Reinitialise control variables ... 5795574Smx205022 */ 5805574Smx205022 5815574Smx205022 srp->tx_hwmark = NGE_DESC_MIN; 5825574Smx205022 srp->tx_lwmark = NGE_DESC_MIN; 5835574Smx205022 5845574Smx205022 srp->tx_next = 0; 5855574Smx205022 srp->tx_free = srp->desc.nslots; 5865574Smx205022 srp->tc_next = 0; 5875574Smx205022 5885574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5895574Smx205022 5905574Smx205022 for (slot = 0; slot - dmah_num != 0; ++slot) 5915574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5925574Smx205022 5935574Smx205022 srp->dmah_free.head = srp->dmahndl; 5945574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5955574Smx205022 srp->dmah_free.tail->next = NULL; 5965574Smx205022 5975574Smx205022 /* 5985574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 5995574Smx205022 */ 6005574Smx205022 for (slot = 0; slot < srp->desc.nslots; ++slot) { 6015574Smx205022 ssbdp = &srp->sw_sbds[slot]; 6025574Smx205022 ssbdp->flags = HOST_OWN; 6035574Smx205022 } 6045574Smx205022 6055574Smx205022 DMA_ZERO(srp->desc); 6065574Smx205022 DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 6075574Smx205022 } 6085574Smx205022 6095574Smx205022 /* 6105574Smx205022 * Initialize the slot number of rx's ring 6115574Smx205022 */ 6125574Smx205022 static void 6135574Smx205022 nge_init_recv_ring(nge_t *ngep) 6145574Smx205022 { 6155574Smx205022 recv_ring_t *rrp; 6165574Smx205022 6175574Smx205022 rrp = ngep->recv; 6185574Smx205022 rrp->desc.nslots = ngep->rx_desc; 6195574Smx205022 rrp->ngep = ngep; 6205574Smx205022 } 6215574Smx205022 6225574Smx205022 /* 6235574Smx205022 * Intialize the rx recycle pointer and rx sending pointer of rx ring 6245574Smx205022 */ 6255574Smx205022 static void 6265574Smx205022 nge_reinit_recv_ring(nge_t *ngep) 6275574Smx205022 { 6285574Smx205022 recv_ring_t *rrp; 6295574Smx205022 6305574Smx205022 rrp = ngep->recv; 6315574Smx205022 6325574Smx205022 /* 6335574Smx205022 * Reinitialise control variables ... 6345574Smx205022 */ 6355574Smx205022 rrp->prod_index = 0; 6365574Smx205022 /* 6375574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 6385574Smx205022 */ 6395574Smx205022 DMA_ZERO(rrp->desc); 6405574Smx205022 DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV); 6415574Smx205022 } 6425574Smx205022 6435574Smx205022 /* 6445574Smx205022 * Clean up initialisation done above before the memory is freed 6455574Smx205022 */ 6465574Smx205022 static void 6475574Smx205022 nge_fini_buff_ring(nge_t *ngep) 6485574Smx205022 { 6495574Smx205022 uint32_t i; 6505574Smx205022 buff_ring_t *brp; 6515574Smx205022 dma_area_t *bufp; 6525574Smx205022 sw_rx_sbd_t *bsbdp; 6535574Smx205022 6545574Smx205022 brp = ngep->buff; 6555574Smx205022 bsbdp = brp->sw_rbds; 6565574Smx205022 6575574Smx205022 NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep)); 6585574Smx205022 6595574Smx205022 mutex_enter(brp->recycle_lock); 6605574Smx205022 brp->buf_sign++; 6615574Smx205022 mutex_exit(brp->recycle_lock); 6625574Smx205022 for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) { 6635574Smx205022 if (bsbdp->bufp) { 6645574Smx205022 if (bsbdp->bufp->mp) 6655574Smx205022 freemsg(bsbdp->bufp->mp); 6665574Smx205022 nge_free_dma_mem(bsbdp->bufp); 6675574Smx205022 kmem_free(bsbdp->bufp, sizeof (dma_area_t)); 6685574Smx205022 bsbdp->bufp = NULL; 6695574Smx205022 } 6705574Smx205022 } 6715574Smx205022 while (brp->free_list != NULL) { 6725574Smx205022 bufp = brp->free_list; 6735574Smx205022 brp->free_list = bufp->next; 6745574Smx205022 bufp->next = NULL; 6755574Smx205022 if (bufp->mp) 6765574Smx205022 freemsg(bufp->mp); 6775574Smx205022 nge_free_dma_mem(bufp); 6785574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6795574Smx205022 } 6805574Smx205022 while (brp->recycle_list != NULL) { 6815574Smx205022 bufp = brp->recycle_list; 6825574Smx205022 brp->recycle_list = bufp->next; 6835574Smx205022 bufp->next = NULL; 6845574Smx205022 if (bufp->mp) 6855574Smx205022 freemsg(bufp->mp); 6865574Smx205022 nge_free_dma_mem(bufp); 6875574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6885574Smx205022 } 6895574Smx205022 6905574Smx205022 6915574Smx205022 kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp))); 6925574Smx205022 brp->sw_rbds = NULL; 6935574Smx205022 } 6945574Smx205022 6955574Smx205022 /* 6965574Smx205022 * Intialize the Rx's data ring and free ring 6975574Smx205022 */ 6985574Smx205022 static int 6995574Smx205022 nge_init_buff_ring(nge_t *ngep) 7005574Smx205022 { 7015574Smx205022 uint32_t err; 7025574Smx205022 uint32_t slot; 7035574Smx205022 uint32_t nslots_buff; 7045574Smx205022 uint32_t nslots_recv; 7055574Smx205022 buff_ring_t *brp; 7065574Smx205022 recv_ring_t *rrp; 7075574Smx205022 dma_area_t desc; 7085574Smx205022 dma_area_t *bufp; 7095574Smx205022 sw_rx_sbd_t *bsbdp; 7105574Smx205022 7115574Smx205022 rrp = ngep->recv; 7125574Smx205022 brp = ngep->buff; 7135574Smx205022 brp->nslots = ngep->rx_buf; 7145574Smx205022 brp->rx_bcopy = B_FALSE; 7155574Smx205022 nslots_recv = rrp->desc.nslots; 7165574Smx205022 nslots_buff = brp->nslots; 7175574Smx205022 brp->ngep = ngep; 7185574Smx205022 7195574Smx205022 NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep)); 7205574Smx205022 7215574Smx205022 /* 7225574Smx205022 * Allocate the array of s/w Recv Buffer Descriptors 7235574Smx205022 */ 7245574Smx205022 bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP); 7255574Smx205022 brp->sw_rbds = bsbdp; 7265574Smx205022 brp->free_list = NULL; 7275574Smx205022 brp->recycle_list = NULL; 7285574Smx205022 for (slot = 0; slot < nslots_buff; ++slot) { 7295574Smx205022 bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP); 7305574Smx205022 err = nge_alloc_dma_mem(ngep, (ngep->buf_size 7315574Smx205022 + NGE_HEADROOM), 7325574Smx205022 &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp); 7335574Smx205022 if (err != DDI_SUCCESS) { 7345574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 7355574Smx205022 return (DDI_FAILURE); 7365574Smx205022 } 7375574Smx205022 7385574Smx205022 bufp->alength -= NGE_HEADROOM; 7395574Smx205022 bufp->offset += NGE_HEADROOM; 7405574Smx205022 bufp->private = (caddr_t)ngep; 7415574Smx205022 bufp->rx_recycle.free_func = nge_recv_recycle; 7425574Smx205022 bufp->rx_recycle.free_arg = (caddr_t)bufp; 7435574Smx205022 bufp->signature = brp->buf_sign; 7445574Smx205022 bufp->rx_delivered = B_FALSE; 7455574Smx205022 bufp->mp = desballoc(DMA_VPTR(*bufp), 7465574Smx205022 ngep->buf_size + NGE_HEADROOM, 7475574Smx205022 0, &bufp->rx_recycle); 7485574Smx205022 7495574Smx205022 if (bufp->mp == NULL) { 7505574Smx205022 return (DDI_FAILURE); 7515574Smx205022 } 7525574Smx205022 bufp->next = brp->free_list; 7535574Smx205022 brp->free_list = bufp; 7545574Smx205022 } 7555574Smx205022 7565574Smx205022 /* 7575574Smx205022 * Now initialise each array element once and for all 7585574Smx205022 */ 7595574Smx205022 desc = rrp->desc; 7605574Smx205022 for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) { 7615574Smx205022 nge_slice_chunk(&bsbdp->desc, &desc, 1, 7625574Smx205022 ngep->desc_attr.rxd_size); 7635574Smx205022 bufp = brp->free_list; 7645574Smx205022 brp->free_list = bufp->next; 7655574Smx205022 bsbdp->bufp = bufp; 7665574Smx205022 bsbdp->flags = CONTROLER_OWN; 7675574Smx205022 bufp->next = NULL; 7685574Smx205022 } 7695574Smx205022 7705574Smx205022 ASSERT(desc.alength == 0); 7715574Smx205022 return (DDI_SUCCESS); 7725574Smx205022 } 7735574Smx205022 7745574Smx205022 /* 7755574Smx205022 * Fill the host address of data in rx' descriptor 7765574Smx205022 * and initialize free pointers of rx free ring 7775574Smx205022 */ 7785574Smx205022 static int 7795574Smx205022 nge_reinit_buff_ring(nge_t *ngep) 7805574Smx205022 { 7815574Smx205022 uint32_t slot; 7825574Smx205022 uint32_t nslots_recv; 7835574Smx205022 buff_ring_t *brp; 7845574Smx205022 recv_ring_t *rrp; 7855574Smx205022 sw_rx_sbd_t *bsbdp; 7865574Smx205022 void *hw_bd_p; 7875574Smx205022 7885574Smx205022 brp = ngep->buff; 7895574Smx205022 rrp = ngep->recv; 7905574Smx205022 bsbdp = brp->sw_rbds; 7915574Smx205022 nslots_recv = rrp->desc.nslots; 7925574Smx205022 for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) { 7935574Smx205022 hw_bd_p = DMA_VPTR(bsbdp->desc); 7945574Smx205022 /* 7955574Smx205022 * There is a scenario: When the traffic of small tcp 7965574Smx205022 * packet is heavy, suspending the tcp traffic will 7975574Smx205022 * cause the preallocated buffers for rx not to be 7985574Smx205022 * released in time by tcp taffic and cause rx's buffer 7995574Smx205022 * pointers not to be refilled in time. 8005574Smx205022 * 8015574Smx205022 * At this point, if we reinitialize the driver, the bufp 8025574Smx205022 * pointer for rx's traffic will be NULL. 8035574Smx205022 * So the result of the reinitializion fails. 8045574Smx205022 */ 8055574Smx205022 if (bsbdp->bufp == NULL) 8065574Smx205022 return (DDI_FAILURE); 8075574Smx205022 8085574Smx205022 ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie, 8095574Smx205022 bsbdp->bufp->alength); 8105574Smx205022 } 8115574Smx205022 return (DDI_SUCCESS); 8125574Smx205022 } 8135574Smx205022 8145574Smx205022 static void 8155574Smx205022 nge_init_ring_param_lock(nge_t *ngep) 8165574Smx205022 { 8175574Smx205022 buff_ring_t *brp; 8185574Smx205022 send_ring_t *srp; 8195574Smx205022 8205574Smx205022 srp = ngep->send; 8215574Smx205022 brp = ngep->buff; 8225574Smx205022 8235574Smx205022 /* Init the locks for send ring */ 8245574Smx205022 mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 8255574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8265574Smx205022 mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 8275574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8285574Smx205022 mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER, 8295574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8305574Smx205022 8315574Smx205022 /* Init parameters of buffer ring */ 8325574Smx205022 brp->free_list = NULL; 8335574Smx205022 brp->recycle_list = NULL; 8345574Smx205022 brp->rx_hold = 0; 8355574Smx205022 brp->buf_sign = 0; 8365574Smx205022 8375574Smx205022 /* Init recycle list lock */ 8385574Smx205022 mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER, 8395574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8405574Smx205022 } 8415574Smx205022 8425574Smx205022 int 8435574Smx205022 nge_init_rings(nge_t *ngep) 8445574Smx205022 { 8455574Smx205022 uint32_t err; 8465574Smx205022 8475574Smx205022 err = nge_init_send_ring(ngep); 8485574Smx205022 if (err != DDI_SUCCESS) { 8495574Smx205022 return (err); 8505574Smx205022 } 8515574Smx205022 nge_init_recv_ring(ngep); 8525574Smx205022 8535574Smx205022 err = nge_init_buff_ring(ngep); 8545574Smx205022 if (err != DDI_SUCCESS) { 8555574Smx205022 nge_fini_send_ring(ngep); 8565574Smx205022 return (DDI_FAILURE); 8575574Smx205022 } 8585574Smx205022 8595574Smx205022 return (err); 8605574Smx205022 } 8615574Smx205022 8625574Smx205022 static int 8635574Smx205022 nge_reinit_ring(nge_t *ngep) 8645574Smx205022 { 8655574Smx205022 int err; 8665574Smx205022 8675574Smx205022 nge_reinit_recv_ring(ngep); 8685574Smx205022 nge_reinit_send_ring(ngep); 8695574Smx205022 err = nge_reinit_buff_ring(ngep); 8705574Smx205022 return (err); 8715574Smx205022 } 8725574Smx205022 8735574Smx205022 8745574Smx205022 void 8755574Smx205022 nge_fini_rings(nge_t *ngep) 8765574Smx205022 { 8775574Smx205022 /* 8785574Smx205022 * For receive ring, nothing need to be finished. 8795574Smx205022 * So only finish buffer ring and send ring here. 8805574Smx205022 */ 8815574Smx205022 nge_fini_buff_ring(ngep); 8825574Smx205022 nge_fini_send_ring(ngep); 8835574Smx205022 } 8845574Smx205022 8855574Smx205022 /* 8865574Smx205022 * Loopback ioctl code 8875574Smx205022 */ 8885574Smx205022 8895574Smx205022 static lb_property_t loopmodes[] = { 8905574Smx205022 { normal, "normal", NGE_LOOP_NONE }, 8915574Smx205022 { external, "100Mbps", NGE_LOOP_EXTERNAL_100 }, 8925574Smx205022 { external, "10Mbps", NGE_LOOP_EXTERNAL_10 }, 8935574Smx205022 { internal, "PHY", NGE_LOOP_INTERNAL_PHY }, 8945574Smx205022 }; 8955574Smx205022 8965574Smx205022 enum ioc_reply 8975574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp) 8985574Smx205022 { 8995574Smx205022 int cmd; 9005574Smx205022 uint32_t *lbmp; 9015574Smx205022 lb_info_sz_t *lbsp; 9025574Smx205022 lb_property_t *lbpp; 9035574Smx205022 9045574Smx205022 /* 9055574Smx205022 * Validate format of ioctl 9065574Smx205022 */ 9075574Smx205022 if (mp->b_cont == NULL) 9085574Smx205022 return (IOC_INVAL); 9095574Smx205022 9105574Smx205022 cmd = iocp->ioc_cmd; 9115574Smx205022 9125574Smx205022 switch (cmd) { 9135574Smx205022 default: 9145574Smx205022 return (IOC_INVAL); 9155574Smx205022 9165574Smx205022 case LB_GET_INFO_SIZE: 9175574Smx205022 if (iocp->ioc_count != sizeof (lb_info_sz_t)) 9185574Smx205022 return (IOC_INVAL); 9195574Smx205022 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 9205574Smx205022 *lbsp = sizeof (loopmodes); 9215574Smx205022 return (IOC_REPLY); 9225574Smx205022 9235574Smx205022 case LB_GET_INFO: 9245574Smx205022 if (iocp->ioc_count != sizeof (loopmodes)) 9255574Smx205022 return (IOC_INVAL); 9265574Smx205022 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 9275574Smx205022 bcopy(loopmodes, lbpp, sizeof (loopmodes)); 9285574Smx205022 return (IOC_REPLY); 9295574Smx205022 9305574Smx205022 case LB_GET_MODE: 9315574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9325574Smx205022 return (IOC_INVAL); 9335574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9345574Smx205022 *lbmp = ngep->param_loop_mode; 9355574Smx205022 return (IOC_REPLY); 9365574Smx205022 9375574Smx205022 case LB_SET_MODE: 9385574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9395574Smx205022 return (IOC_INVAL); 9405574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9415574Smx205022 return (nge_set_loop_mode(ngep, *lbmp)); 9425574Smx205022 } 9435574Smx205022 } 9445574Smx205022 9455574Smx205022 #undef NGE_DBG 9465574Smx205022 #define NGE_DBG NGE_DBG_NEMO 9475574Smx205022 9485574Smx205022 9495574Smx205022 static void 9505574Smx205022 nge_check_desc_prop(nge_t *ngep) 9515574Smx205022 { 9525574Smx205022 if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD) 9535574Smx205022 ngep->desc_mode = DESC_HOT; 9545574Smx205022 9555574Smx205022 if (ngep->desc_mode == DESC_OFFLOAD) { 9565574Smx205022 9575574Smx205022 ngep->desc_attr = nge_sum_desc; 9585574Smx205022 9595574Smx205022 } else if (ngep->desc_mode == DESC_HOT) { 9605574Smx205022 9615574Smx205022 ngep->desc_attr = nge_hot_desc; 9625574Smx205022 } 9635574Smx205022 } 9645574Smx205022 9655574Smx205022 /* 9665574Smx205022 * nge_get_props -- get the parameters to tune the driver 9675574Smx205022 */ 9685574Smx205022 static void 9695574Smx205022 nge_get_props(nge_t *ngep) 9705574Smx205022 { 9715574Smx205022 chip_info_t *infop; 9725574Smx205022 dev_info_t *devinfo; 9735574Smx205022 nge_dev_spec_param_t *dev_param_p; 9745574Smx205022 9755574Smx205022 devinfo = ngep->devinfo; 9765574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 9775574Smx205022 dev_param_p = &ngep->dev_spec_param; 9785574Smx205022 9795574Smx205022 infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9805574Smx205022 DDI_PROP_DONTPASS, clsize_propname, 32); 9815574Smx205022 9825574Smx205022 infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9835574Smx205022 DDI_PROP_DONTPASS, latency_propname, 64); 9845659Sjj146644 ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9855659Sjj146644 DDI_PROP_DONTPASS, intr_moderation, NGE_SET); 9865574Smx205022 ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9875574Smx205022 DDI_PROP_DONTPASS, rx_data_hw, 0x20); 9885574Smx205022 ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9895574Smx205022 DDI_PROP_DONTPASS, rx_prd_lw, 0x4); 9905574Smx205022 ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9915574Smx205022 DDI_PROP_DONTPASS, rx_prd_hw, 0xc); 9925574Smx205022 9935574Smx205022 ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9945574Smx205022 DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC); 9955574Smx205022 ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9965574Smx205022 DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP); 9975574Smx205022 ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9985574Smx205022 DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type); 9995574Smx205022 ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 10005574Smx205022 DDI_PROP_DONTPASS, low_memory_mode, 0); 10018218SMin.Xu@Sun.COM ngep->mac_addr_reversion = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 10028218SMin.Xu@Sun.COM DDI_PROP_DONTPASS, mac_addr_reversion, 0); 10035574Smx205022 10045574Smx205022 if (dev_param_p->jumbo) { 10055574Smx205022 ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 10065574Smx205022 DDI_PROP_DONTPASS, default_mtu, ETHERMTU); 10075574Smx205022 } else 10085574Smx205022 ngep->default_mtu = ETHERMTU; 10095574Smx205022 10105574Smx205022 if (ngep->default_mtu > ETHERMTU && 10115574Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 10125574Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 10135574Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 10145574Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 10155574Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 10165574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10175574Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 10185574Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 10195574Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 10205574Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 10215574Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 10225574Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 10235574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10245574Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 10255574Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 10265574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10275574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10285574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10295574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10305574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10315574Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 10325574Smx205022 ngep->default_mtu = NGE_MAX_MTU; 10335574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10345574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10355574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10365574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10375574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10385574Smx205022 } else if (ngep->lowmem_mode != 0) { 10395574Smx205022 ngep->default_mtu = ETHERMTU; 10405574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10415574Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 10425574Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 10435574Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 10445574Smx205022 ngep->nge_split = NGE_SPLIT_32; 10455574Smx205022 } else { 10465574Smx205022 ngep->default_mtu = ETHERMTU; 10475574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10485574Smx205022 ngep->tx_desc = dev_param_p->tx_desc_num; 10495574Smx205022 ngep->rx_desc = dev_param_p->rx_desc_num; 10505574Smx205022 ngep->rx_buf = dev_param_p->rx_desc_num * 2; 10515574Smx205022 ngep->nge_split = dev_param_p->nge_split; 10525574Smx205022 } 10535574Smx205022 10545574Smx205022 nge_check_desc_prop(ngep); 10555574Smx205022 } 10565574Smx205022 10575574Smx205022 10585574Smx205022 static int 10597656SSherry.Moore@Sun.COM nge_reset_dev(nge_t *ngep) 10605574Smx205022 { 10615574Smx205022 int err; 10625869Smx205022 nge_mul_addr1 maddr1; 10635869Smx205022 nge_sw_statistics_t *sw_stp; 10645869Smx205022 sw_stp = &ngep->statistics.sw_statistics; 10655574Smx205022 send_ring_t *srp = ngep->send; 10665574Smx205022 10675574Smx205022 ASSERT(mutex_owned(ngep->genlock)); 10685574Smx205022 mutex_enter(srp->tc_lock); 10695574Smx205022 mutex_enter(srp->tx_lock); 10705574Smx205022 10715574Smx205022 nge_tx_recycle_all(ngep); 10725574Smx205022 err = nge_reinit_ring(ngep); 10735574Smx205022 if (err == DDI_FAILURE) { 10745574Smx205022 mutex_exit(srp->tx_lock); 10755574Smx205022 mutex_exit(srp->tc_lock); 10765574Smx205022 return (err); 10775574Smx205022 } 10785574Smx205022 err = nge_chip_reset(ngep); 10795869Smx205022 /* 10805869Smx205022 * Clear the Multicast mac address table 10815869Smx205022 */ 10825869Smx205022 nge_reg_put32(ngep, NGE_MUL_ADDR0, 0); 10835869Smx205022 maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1); 10845869Smx205022 maddr1.addr_bits.addr = 0; 10855869Smx205022 nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val); 10865869Smx205022 10875574Smx205022 mutex_exit(srp->tx_lock); 10885574Smx205022 mutex_exit(srp->tc_lock); 10895574Smx205022 if (err == DDI_FAILURE) 10905574Smx205022 return (err); 10915574Smx205022 ngep->watchdog = 0; 10925574Smx205022 ngep->resched_needed = B_FALSE; 10935574Smx205022 ngep->promisc = B_FALSE; 10945574Smx205022 ngep->param_loop_mode = NGE_LOOP_NONE; 10955574Smx205022 ngep->factotum_flag = 0; 10965574Smx205022 ngep->resched_needed = 0; 10975574Smx205022 ngep->nge_mac_state = NGE_MAC_RESET; 10985574Smx205022 ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL; 10995574Smx205022 ngep->max_sdu += VTAG_SIZE; 11005574Smx205022 ngep->rx_def = 0x16; 11015869Smx205022 11025869Smx205022 /* Clear the software statistics */ 11035869Smx205022 sw_stp->recv_count = 0; 11045869Smx205022 sw_stp->xmit_count = 0; 11055869Smx205022 sw_stp->rbytes = 0; 11065869Smx205022 sw_stp->obytes = 0; 11075869Smx205022 11085574Smx205022 return (DDI_SUCCESS); 11095574Smx205022 } 11105574Smx205022 11115574Smx205022 static void 11125574Smx205022 nge_m_stop(void *arg) 11135574Smx205022 { 11145574Smx205022 nge_t *ngep = arg; /* private device info */ 11155574Smx205022 11165574Smx205022 NGE_TRACE(("nge_m_stop($%p)", arg)); 11175574Smx205022 11185574Smx205022 /* 11195574Smx205022 * Just stop processing, then record new MAC state 11205574Smx205022 */ 11215574Smx205022 mutex_enter(ngep->genlock); 11225869Smx205022 /* If suspended, the adapter is already stopped, just return. */ 11235869Smx205022 if (ngep->suspended) { 11245869Smx205022 ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED); 11255869Smx205022 mutex_exit(ngep->genlock); 11265869Smx205022 return; 11275869Smx205022 } 11285574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 11295574Smx205022 11305574Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 11315574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 11325574Smx205022 11335574Smx205022 /* Recycle all the TX BD */ 11345574Smx205022 nge_tx_recycle_all(ngep); 11355574Smx205022 nge_fini_rings(ngep); 11365574Smx205022 nge_free_bufs(ngep); 11375574Smx205022 11385574Smx205022 NGE_DEBUG(("nge_m_stop($%p) done", arg)); 11395574Smx205022 11405574Smx205022 rw_exit(ngep->rwlock); 11415574Smx205022 mutex_exit(ngep->genlock); 11425574Smx205022 } 11435574Smx205022 11445574Smx205022 static int 11455574Smx205022 nge_m_start(void *arg) 11465574Smx205022 { 11475574Smx205022 int err; 11485574Smx205022 nge_t *ngep = arg; 11495574Smx205022 11505574Smx205022 NGE_TRACE(("nge_m_start($%p)", arg)); 11515869Smx205022 11525869Smx205022 /* 11535869Smx205022 * Start processing and record new MAC state 11545869Smx205022 */ 11555869Smx205022 mutex_enter(ngep->genlock); 11565574Smx205022 /* 11575574Smx205022 * If suspended, don't start, as the resume processing 11585574Smx205022 * will recall this function with the suspended flag off. 11595574Smx205022 */ 11605869Smx205022 if (ngep->suspended) { 11615869Smx205022 mutex_exit(ngep->genlock); 11625988Svb160487 return (EIO); 11635869Smx205022 } 11645574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 11655574Smx205022 err = nge_alloc_bufs(ngep); 11665574Smx205022 if (err != DDI_SUCCESS) { 11675574Smx205022 nge_problem(ngep, "nge_m_start: DMA buffer allocation failed"); 11685574Smx205022 goto finish; 11695574Smx205022 } 11705574Smx205022 err = nge_init_rings(ngep); 11715574Smx205022 if (err != DDI_SUCCESS) { 11725574Smx205022 nge_free_bufs(ngep); 11735988Svb160487 nge_problem(ngep, "nge_init_rings() failed,err=%x", err); 11745574Smx205022 goto finish; 11755574Smx205022 } 11765574Smx205022 err = nge_restart(ngep); 11775574Smx205022 11785574Smx205022 NGE_DEBUG(("nge_m_start($%p) done", arg)); 11795988Svb160487 finish: 11805988Svb160487 rw_exit(ngep->rwlock); 11815988Svb160487 mutex_exit(ngep->genlock); 11825574Smx205022 11835988Svb160487 return (err == DDI_SUCCESS ? 0 : EIO); 11845574Smx205022 } 11855574Smx205022 11865574Smx205022 static int 11875574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr) 11885574Smx205022 { 11895574Smx205022 nge_t *ngep = arg; 11905574Smx205022 11915574Smx205022 NGE_TRACE(("nge_m_unicst($%p)", arg)); 11925574Smx205022 /* 11935574Smx205022 * Remember the new current address in the driver state 11945574Smx205022 * Sync the chip's idea of the address too ... 11955574Smx205022 */ 11965574Smx205022 mutex_enter(ngep->genlock); 11975574Smx205022 11985574Smx205022 ethaddr_copy(macaddr, ngep->cur_uni_addr.addr); 11995574Smx205022 ngep->cur_uni_addr.set = 1; 12005574Smx205022 12015574Smx205022 /* 12025574Smx205022 * If we are suspended, we want to quit now, and not update 12035574Smx205022 * the chip. Doing so might put it in a bad state, but the 12045574Smx205022 * resume will get the unicast address installed. 12055574Smx205022 */ 12065869Smx205022 if (ngep->suspended) { 12075869Smx205022 mutex_exit(ngep->genlock); 12085574Smx205022 return (DDI_SUCCESS); 12095869Smx205022 } 12105574Smx205022 nge_chip_sync(ngep); 12115574Smx205022 12125574Smx205022 NGE_DEBUG(("nge_m_unicst($%p) done", arg)); 12135574Smx205022 mutex_exit(ngep->genlock); 12145574Smx205022 12155574Smx205022 return (0); 12165574Smx205022 } 12175574Smx205022 12185574Smx205022 static int 12195574Smx205022 nge_m_promisc(void *arg, boolean_t on) 12205574Smx205022 { 12215574Smx205022 nge_t *ngep = arg; 12225574Smx205022 12235574Smx205022 NGE_TRACE(("nge_m_promisc($%p)", arg)); 12245574Smx205022 12255574Smx205022 /* 12265574Smx205022 * Store specified mode and pass to chip layer to update h/w 12275574Smx205022 */ 12285574Smx205022 mutex_enter(ngep->genlock); 12295869Smx205022 /* 12305869Smx205022 * If suspended, there is no need to do anything, even 12315869Smx205022 * recording the promiscuious mode is not neccessary, as 12325869Smx205022 * it won't be properly set on resume. Just return failing. 12335869Smx205022 */ 12345869Smx205022 if (ngep->suspended) { 12355869Smx205022 mutex_exit(ngep->genlock); 12365869Smx205022 return (DDI_FAILURE); 12375869Smx205022 } 12385574Smx205022 if (ngep->promisc == on) { 12395574Smx205022 mutex_exit(ngep->genlock); 12405574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12415574Smx205022 return (0); 12425574Smx205022 } 12435574Smx205022 ngep->promisc = on; 12447155Smx205022 ngep->record_promisc = ngep->promisc; 12455574Smx205022 nge_chip_sync(ngep); 12465574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12475574Smx205022 mutex_exit(ngep->genlock); 12485574Smx205022 12495574Smx205022 return (0); 12505574Smx205022 } 12515574Smx205022 12525574Smx205022 static void nge_mulparam(nge_t *ngep) 12535574Smx205022 { 12545574Smx205022 uint8_t number; 12555574Smx205022 ether_addr_t pand; 12565574Smx205022 ether_addr_t por; 12575574Smx205022 mul_item *plist; 12585574Smx205022 12595574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12605574Smx205022 pand[number] = 0x00; 12615574Smx205022 por[number] = 0x00; 12625574Smx205022 } 12635574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) { 12645574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12655574Smx205022 pand[number] &= plist->mul_addr[number]; 12665574Smx205022 por[number] |= plist->mul_addr[number]; 12675574Smx205022 } 12685574Smx205022 } 12695574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12705574Smx205022 ngep->cur_mul_addr.addr[number] 12715574Smx205022 = pand[number] & por[number]; 12725574Smx205022 ngep->cur_mul_mask.addr[number] 12735574Smx205022 = pand [number] | (~por[number]); 12745574Smx205022 } 12755574Smx205022 } 12765574Smx205022 static int 12775574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12785574Smx205022 { 12795574Smx205022 boolean_t update; 12805574Smx205022 boolean_t b_eq; 12815574Smx205022 nge_t *ngep = arg; 12825574Smx205022 mul_item *plist; 12835574Smx205022 mul_item *plist_prev; 12845574Smx205022 mul_item *pitem; 12855574Smx205022 12865574Smx205022 NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg, 12875574Smx205022 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 12885574Smx205022 12895574Smx205022 update = B_FALSE; 12905574Smx205022 plist = plist_prev = NULL; 12915574Smx205022 mutex_enter(ngep->genlock); 12925574Smx205022 if (add) { 12935574Smx205022 if (ngep->pcur_mulist != NULL) { 12945574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 12955574Smx205022 plist = plist->next) { 12965574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 12975574Smx205022 if (b_eq) { 12985574Smx205022 plist->ref_cnt++; 12995574Smx205022 break; 13005574Smx205022 } 13015574Smx205022 plist_prev = plist; 13025574Smx205022 } 13035574Smx205022 } 13045574Smx205022 13055574Smx205022 if (plist == NULL) { 13065574Smx205022 pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP); 13075574Smx205022 ether_copy(mca, pitem->mul_addr); 13085574Smx205022 pitem ->ref_cnt++; 13095574Smx205022 pitem ->next = NULL; 13105574Smx205022 if (plist_prev == NULL) 13115574Smx205022 ngep->pcur_mulist = pitem; 13125574Smx205022 else 13135574Smx205022 plist_prev->next = pitem; 13145574Smx205022 update = B_TRUE; 13155574Smx205022 } 13165574Smx205022 } else { 13175574Smx205022 if (ngep->pcur_mulist != NULL) { 13185574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 13195574Smx205022 plist = plist->next) { 13205574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 13215574Smx205022 if (b_eq) { 13225574Smx205022 update = B_TRUE; 13235574Smx205022 break; 13245574Smx205022 } 13255574Smx205022 plist_prev = plist; 13265574Smx205022 } 13275574Smx205022 13285574Smx205022 if (update) { 13295574Smx205022 if ((plist_prev == NULL) && 13305574Smx205022 (plist->next == NULL)) 13315574Smx205022 ngep->pcur_mulist = NULL; 13325574Smx205022 else if ((plist_prev == NULL) && 13335574Smx205022 (plist->next != NULL)) 13345574Smx205022 ngep->pcur_mulist = plist->next; 13355574Smx205022 else 13365574Smx205022 plist_prev->next = plist->next; 13375574Smx205022 kmem_free(plist, sizeof (mul_item)); 13385574Smx205022 } 13395574Smx205022 } 13405574Smx205022 } 13415574Smx205022 13425869Smx205022 if (update && !ngep->suspended) { 13435574Smx205022 nge_mulparam(ngep); 13445574Smx205022 nge_chip_sync(ngep); 13455574Smx205022 } 13465574Smx205022 NGE_DEBUG(("nge_m_multicst($%p) done", arg)); 13475574Smx205022 mutex_exit(ngep->genlock); 13485574Smx205022 13495574Smx205022 return (0); 13505574Smx205022 } 13515574Smx205022 13525574Smx205022 static void 13535574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 13545574Smx205022 { 13555574Smx205022 int err; 13565574Smx205022 int cmd; 13575574Smx205022 nge_t *ngep = arg; 13585574Smx205022 struct iocblk *iocp; 13595574Smx205022 enum ioc_reply status; 13605574Smx205022 boolean_t need_privilege; 13615574Smx205022 13625574Smx205022 /* 13635574Smx205022 * If suspended, we might actually be able to do some of 13645574Smx205022 * these ioctls, but it is harder to make sure they occur 13655574Smx205022 * without actually putting the hardware in an undesireable 13665574Smx205022 * state. So just NAK it. 13675574Smx205022 */ 13685869Smx205022 mutex_enter(ngep->genlock); 13695574Smx205022 if (ngep->suspended) { 13705574Smx205022 miocnak(wq, mp, 0, EINVAL); 13715869Smx205022 mutex_exit(ngep->genlock); 13725574Smx205022 return; 13735574Smx205022 } 13745869Smx205022 mutex_exit(ngep->genlock); 13755574Smx205022 13765574Smx205022 /* 13775574Smx205022 * Validate the command before bothering with the mutex ... 13785574Smx205022 */ 13795574Smx205022 iocp = (struct iocblk *)mp->b_rptr; 13805574Smx205022 iocp->ioc_error = 0; 13815574Smx205022 need_privilege = B_TRUE; 13825574Smx205022 cmd = iocp->ioc_cmd; 13835574Smx205022 13845574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x", cmd)); 13855574Smx205022 switch (cmd) { 13865574Smx205022 default: 13875574Smx205022 NGE_LDB(NGE_DBG_BADIOC, 13885574Smx205022 ("nge_m_ioctl: unknown cmd 0x%x", cmd)); 13895574Smx205022 13905574Smx205022 miocnak(wq, mp, 0, EINVAL); 13915574Smx205022 return; 13925574Smx205022 13935574Smx205022 case NGE_MII_READ: 13945574Smx205022 case NGE_MII_WRITE: 13955574Smx205022 case NGE_SEE_READ: 13965574Smx205022 case NGE_SEE_WRITE: 13975574Smx205022 case NGE_DIAG: 13985574Smx205022 case NGE_PEEK: 13995574Smx205022 case NGE_POKE: 14005574Smx205022 case NGE_PHY_RESET: 14015574Smx205022 case NGE_SOFT_RESET: 14025574Smx205022 case NGE_HARD_RESET: 14035574Smx205022 break; 14045574Smx205022 14055574Smx205022 case LB_GET_INFO_SIZE: 14065574Smx205022 case LB_GET_INFO: 14075574Smx205022 case LB_GET_MODE: 14085574Smx205022 need_privilege = B_FALSE; 14095574Smx205022 break; 14105574Smx205022 case LB_SET_MODE: 14115574Smx205022 break; 14125574Smx205022 } 14135574Smx205022 14145574Smx205022 if (need_privilege) { 14155574Smx205022 /* 14165574Smx205022 * Check for specific net_config privilege. 14175574Smx205022 */ 14185574Smx205022 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 14195574Smx205022 if (err != 0) { 14205574Smx205022 NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d", 14215574Smx205022 cmd, err)); 14225574Smx205022 miocnak(wq, mp, 0, err); 14235574Smx205022 return; 14245574Smx205022 } 14255574Smx205022 } 14265574Smx205022 14275574Smx205022 mutex_enter(ngep->genlock); 14285574Smx205022 14295574Smx205022 switch (cmd) { 14305574Smx205022 default: 14315574Smx205022 _NOTE(NOTREACHED) 14325574Smx205022 status = IOC_INVAL; 14335574Smx205022 break; 14345574Smx205022 14355574Smx205022 case NGE_MII_READ: 14365574Smx205022 case NGE_MII_WRITE: 14375574Smx205022 case NGE_SEE_READ: 14385574Smx205022 case NGE_SEE_WRITE: 14395574Smx205022 case NGE_DIAG: 14405574Smx205022 case NGE_PEEK: 14415574Smx205022 case NGE_POKE: 14425574Smx205022 case NGE_PHY_RESET: 14435574Smx205022 case NGE_SOFT_RESET: 14445574Smx205022 case NGE_HARD_RESET: 14455574Smx205022 status = nge_chip_ioctl(ngep, mp, iocp); 14465574Smx205022 break; 14475574Smx205022 14485574Smx205022 case LB_GET_INFO_SIZE: 14495574Smx205022 case LB_GET_INFO: 14505574Smx205022 case LB_GET_MODE: 14515574Smx205022 case LB_SET_MODE: 14525574Smx205022 status = nge_loop_ioctl(ngep, mp, iocp); 14535574Smx205022 break; 14545574Smx205022 14555574Smx205022 } 14565574Smx205022 14575574Smx205022 /* 14585574Smx205022 * Do we need to reprogram the PHY and/or the MAC? 14595574Smx205022 * Do it now, while we still have the mutex. 14605574Smx205022 * 14615574Smx205022 * Note: update the PHY first, 'cos it controls the 14625574Smx205022 * speed/duplex parameters that the MAC code uses. 14635574Smx205022 */ 14645574Smx205022 14655574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status)); 14665574Smx205022 14675574Smx205022 switch (status) { 14685574Smx205022 case IOC_RESTART_REPLY: 14695574Smx205022 case IOC_RESTART_ACK: 14705574Smx205022 (*ngep->physops->phys_update)(ngep); 14715574Smx205022 nge_chip_sync(ngep); 14725574Smx205022 break; 14735574Smx205022 14745574Smx205022 default: 14755574Smx205022 break; 14765574Smx205022 } 14775574Smx205022 14785574Smx205022 mutex_exit(ngep->genlock); 14795574Smx205022 14805574Smx205022 /* 14815574Smx205022 * Finally, decide how to reply 14825574Smx205022 */ 14835574Smx205022 switch (status) { 14845574Smx205022 14855574Smx205022 default: 14865574Smx205022 case IOC_INVAL: 14875574Smx205022 miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 14885574Smx205022 EINVAL : iocp->ioc_error); 14895574Smx205022 break; 14905574Smx205022 14915574Smx205022 case IOC_DONE: 14925574Smx205022 break; 14935574Smx205022 14945574Smx205022 case IOC_RESTART_ACK: 14955574Smx205022 case IOC_ACK: 14965574Smx205022 miocack(wq, mp, 0, 0); 14975574Smx205022 break; 14985574Smx205022 14995574Smx205022 case IOC_RESTART_REPLY: 15005574Smx205022 case IOC_REPLY: 15015574Smx205022 mp->b_datap->db_type = iocp->ioc_error == 0 ? 15025574Smx205022 M_IOCACK : M_IOCNAK; 15035574Smx205022 qreply(wq, mp); 15045574Smx205022 break; 15055574Smx205022 } 15065574Smx205022 } 15075574Smx205022 15086200Smx205022 static boolean_t 15096200Smx205022 nge_param_locked(mac_prop_id_t pr_num) 15106200Smx205022 { 15116200Smx205022 /* 15126200Smx205022 * All adv_* parameters are locked (read-only) while 15136200Smx205022 * the device is in any sort of loopback mode ... 15146200Smx205022 */ 15156200Smx205022 switch (pr_num) { 15166789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 15176789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 15186789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 15196789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 15206789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 15216789Sam223141 case MAC_PROP_EN_100FDX_CAP: 15226789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 15236789Sam223141 case MAC_PROP_EN_100HDX_CAP: 15246789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 15256789Sam223141 case MAC_PROP_EN_10FDX_CAP: 15266789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 15276789Sam223141 case MAC_PROP_EN_10HDX_CAP: 15286789Sam223141 case MAC_PROP_AUTONEG: 15296789Sam223141 case MAC_PROP_FLOWCTRL: 15306200Smx205022 return (B_TRUE); 15316200Smx205022 } 15326200Smx205022 return (B_FALSE); 15336200Smx205022 } 15346200Smx205022 15356200Smx205022 /* 15366200Smx205022 * callback functions for set/get of properties 15376200Smx205022 */ 15386200Smx205022 static int 15396200Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 15406200Smx205022 uint_t pr_valsize, const void *pr_val) 15416200Smx205022 { 15426200Smx205022 nge_t *ngep = barg; 15436200Smx205022 int err = 0; 15446512Ssowmini uint32_t cur_mtu, new_mtu; 15456200Smx205022 link_flowctrl_t fl; 15466200Smx205022 15476200Smx205022 mutex_enter(ngep->genlock); 15486200Smx205022 if (ngep->param_loop_mode != NGE_LOOP_NONE && 15496200Smx205022 nge_param_locked(pr_num)) { 15506200Smx205022 /* 15516200Smx205022 * All adv_* parameters are locked (read-only) 15526200Smx205022 * while the device is in any sort of loopback mode. 15536200Smx205022 */ 15546200Smx205022 mutex_exit(ngep->genlock); 15556200Smx205022 return (EBUSY); 15566200Smx205022 } 15576200Smx205022 switch (pr_num) { 15586789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 15596200Smx205022 ngep->param_en_1000fdx = *(uint8_t *)pr_val; 15606200Smx205022 ngep->param_adv_1000fdx = *(uint8_t *)pr_val; 15616200Smx205022 goto reprogram; 15626789Sam223141 case MAC_PROP_EN_100FDX_CAP: 15636200Smx205022 ngep->param_en_100fdx = *(uint8_t *)pr_val; 15646200Smx205022 ngep->param_adv_100fdx = *(uint8_t *)pr_val; 15656200Smx205022 goto reprogram; 15666789Sam223141 case MAC_PROP_EN_100HDX_CAP: 15676200Smx205022 ngep->param_en_100hdx = *(uint8_t *)pr_val; 15686200Smx205022 ngep->param_adv_100hdx = *(uint8_t *)pr_val; 15696200Smx205022 goto reprogram; 15706789Sam223141 case MAC_PROP_EN_10FDX_CAP: 15716200Smx205022 ngep->param_en_10fdx = *(uint8_t *)pr_val; 15726200Smx205022 ngep->param_adv_10fdx = *(uint8_t *)pr_val; 15736200Smx205022 goto reprogram; 15746789Sam223141 case MAC_PROP_EN_10HDX_CAP: 15756200Smx205022 ngep->param_en_10hdx = *(uint8_t *)pr_val; 15766200Smx205022 ngep->param_adv_10hdx = *(uint8_t *)pr_val; 15776200Smx205022 reprogram: 15786200Smx205022 (*ngep->physops->phys_update)(ngep); 15796200Smx205022 nge_chip_sync(ngep); 15806200Smx205022 break; 15816200Smx205022 15826789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 15836789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 15846789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 15856789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 15866789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 15876789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 15886789Sam223141 case MAC_PROP_STATUS: 15896789Sam223141 case MAC_PROP_SPEED: 15906789Sam223141 case MAC_PROP_DUPLEX: 15916789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 15926200Smx205022 err = ENOTSUP; /* read-only prop. Can't set this */ 15936200Smx205022 break; 15946789Sam223141 case MAC_PROP_AUTONEG: 15956200Smx205022 ngep->param_adv_autoneg = *(uint8_t *)pr_val; 15966200Smx205022 (*ngep->physops->phys_update)(ngep); 15976200Smx205022 nge_chip_sync(ngep); 15986200Smx205022 break; 15996789Sam223141 case MAC_PROP_MTU: 16006200Smx205022 cur_mtu = ngep->default_mtu; 16016200Smx205022 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 16026200Smx205022 if (new_mtu == cur_mtu) { 16036200Smx205022 err = 0; 16046200Smx205022 break; 16056200Smx205022 } 16066200Smx205022 if (new_mtu < ETHERMTU || 16076200Smx205022 new_mtu > NGE_MAX_MTU) { 16086200Smx205022 err = EINVAL; 16096200Smx205022 break; 16106200Smx205022 } 16116200Smx205022 if ((new_mtu > ETHERMTU) && 16126200Smx205022 (!ngep->dev_spec_param.jumbo)) { 16136200Smx205022 err = EINVAL; 16146200Smx205022 break; 16156200Smx205022 } 16166200Smx205022 if (ngep->nge_mac_state == NGE_MAC_STARTED) { 16176200Smx205022 err = EBUSY; 16186200Smx205022 break; 16196200Smx205022 } 16206200Smx205022 16216200Smx205022 ngep->default_mtu = new_mtu; 16226200Smx205022 if (ngep->default_mtu > ETHERMTU && 16236200Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 16246200Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 16256200Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 16266200Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 16276200Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 16286200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16296200Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 16306200Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 16316200Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 16326200Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 16336200Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 16346200Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 16356200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16366200Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 16376200Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 16386200Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16396200Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16406200Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16416200Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16426200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16436200Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 16446200Smx205022 ngep->default_mtu = NGE_MAX_MTU; 16456200Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16466200Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16476200Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16486200Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16496200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16506200Smx205022 } else if (ngep->lowmem_mode != 0) { 16516200Smx205022 ngep->default_mtu = ETHERMTU; 16526200Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16536200Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 16546200Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 16556200Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 16566200Smx205022 ngep->nge_split = NGE_SPLIT_32; 16576200Smx205022 } else { 16586200Smx205022 ngep->default_mtu = ETHERMTU; 16596200Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16606200Smx205022 ngep->tx_desc = 16616200Smx205022 ngep->dev_spec_param.tx_desc_num; 16626200Smx205022 ngep->rx_desc = 16636200Smx205022 ngep->dev_spec_param.rx_desc_num; 16646200Smx205022 ngep->rx_buf = 16656200Smx205022 ngep->dev_spec_param.rx_desc_num * 2; 16666200Smx205022 ngep->nge_split = 16676200Smx205022 ngep->dev_spec_param.nge_split; 16686200Smx205022 } 16696200Smx205022 16706200Smx205022 err = mac_maxsdu_update(ngep->mh, ngep->default_mtu); 16716200Smx205022 16726200Smx205022 break; 16736789Sam223141 case MAC_PROP_FLOWCTRL: 16746200Smx205022 bcopy(pr_val, &fl, sizeof (fl)); 16756200Smx205022 switch (fl) { 16766200Smx205022 default: 16776200Smx205022 err = ENOTSUP; 16786200Smx205022 break; 16796200Smx205022 case LINK_FLOWCTRL_NONE: 16806200Smx205022 ngep->param_adv_pause = 0; 16816200Smx205022 ngep->param_adv_asym_pause = 0; 16826200Smx205022 16836200Smx205022 ngep->param_link_rx_pause = B_FALSE; 16846200Smx205022 ngep->param_link_tx_pause = B_FALSE; 16856200Smx205022 break; 16866200Smx205022 case LINK_FLOWCTRL_RX: 16876200Smx205022 if (!((ngep->param_lp_pause == 0) && 16886200Smx205022 (ngep->param_lp_asym_pause == 1))) { 16896200Smx205022 err = EINVAL; 16906200Smx205022 break; 16916200Smx205022 } 16926200Smx205022 ngep->param_adv_pause = 1; 16936200Smx205022 ngep->param_adv_asym_pause = 1; 16946200Smx205022 16956200Smx205022 ngep->param_link_rx_pause = B_TRUE; 16966200Smx205022 ngep->param_link_tx_pause = B_FALSE; 16976200Smx205022 break; 16986200Smx205022 case LINK_FLOWCTRL_TX: 16996200Smx205022 if (!((ngep->param_lp_pause == 1) && 17006200Smx205022 (ngep->param_lp_asym_pause == 1))) { 17016200Smx205022 err = EINVAL; 17026200Smx205022 break; 17036200Smx205022 } 17046200Smx205022 ngep->param_adv_pause = 0; 17056200Smx205022 ngep->param_adv_asym_pause = 1; 17066200Smx205022 17076200Smx205022 ngep->param_link_rx_pause = B_FALSE; 17086200Smx205022 ngep->param_link_tx_pause = B_TRUE; 17096200Smx205022 break; 17106200Smx205022 case LINK_FLOWCTRL_BI: 17116200Smx205022 if (ngep->param_lp_pause != 1) { 17126200Smx205022 err = EINVAL; 17136200Smx205022 break; 17146200Smx205022 } 17156200Smx205022 ngep->param_adv_pause = 1; 17166200Smx205022 17176200Smx205022 ngep->param_link_rx_pause = B_TRUE; 17186200Smx205022 ngep->param_link_tx_pause = B_TRUE; 17196200Smx205022 break; 17206200Smx205022 } 17216200Smx205022 17226200Smx205022 if (err == 0) { 17236200Smx205022 (*ngep->physops->phys_update)(ngep); 17246200Smx205022 nge_chip_sync(ngep); 17256200Smx205022 } 17266200Smx205022 17276200Smx205022 break; 17286789Sam223141 case MAC_PROP_PRIVATE: 17296200Smx205022 err = nge_set_priv_prop(ngep, pr_name, pr_valsize, 17306200Smx205022 pr_val); 17316200Smx205022 if (err == 0) { 17326200Smx205022 (*ngep->physops->phys_update)(ngep); 17336200Smx205022 nge_chip_sync(ngep); 17346200Smx205022 } 17356200Smx205022 break; 17366200Smx205022 default: 17376200Smx205022 err = ENOTSUP; 17386200Smx205022 } 17396200Smx205022 mutex_exit(ngep->genlock); 17406200Smx205022 return (err); 17416200Smx205022 } 17426200Smx205022 17436200Smx205022 static int 17446200Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 17458118SVasumathi.Sundaram@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 17466200Smx205022 { 17476200Smx205022 nge_t *ngep = barg; 17486512Ssowmini int err = 0; 17496200Smx205022 link_flowctrl_t fl; 17506512Ssowmini uint64_t speed; 17516789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 17526512Ssowmini 17536512Ssowmini if (pr_valsize == 0) 17546512Ssowmini return (EINVAL); 17556200Smx205022 17568118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_RW; 17578118SVasumathi.Sundaram@Sun.COM 17586200Smx205022 bzero(pr_val, pr_valsize); 17598118SVasumathi.Sundaram@Sun.COM 17606200Smx205022 switch (pr_num) { 17616789Sam223141 case MAC_PROP_DUPLEX: 17628118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 17636512Ssowmini if (pr_valsize >= sizeof (link_duplex_t)) { 17646512Ssowmini bcopy(&ngep->param_link_duplex, pr_val, 17656512Ssowmini sizeof (link_duplex_t)); 17666512Ssowmini } else 17676512Ssowmini err = EINVAL; 17686200Smx205022 break; 17696789Sam223141 case MAC_PROP_SPEED: 17708118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 17716200Smx205022 if (pr_valsize >= sizeof (uint64_t)) { 17726512Ssowmini speed = ngep->param_link_speed * 1000000ull; 17736512Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 17746512Ssowmini } else 17756512Ssowmini err = EINVAL; 17766200Smx205022 break; 17776789Sam223141 case MAC_PROP_AUTONEG: 17786512Ssowmini if (is_default) { 17796512Ssowmini *(uint8_t *)pr_val = 1; 17806512Ssowmini } else { 17816200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_autoneg; 17826200Smx205022 } 17836200Smx205022 break; 17846789Sam223141 case MAC_PROP_FLOWCTRL: 17856200Smx205022 if (pr_valsize >= sizeof (link_flowctrl_t)) { 17866789Sam223141 if (pr_flags & MAC_PROP_DEFAULT) { 17876512Ssowmini fl = LINK_FLOWCTRL_BI; 17886512Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 17896512Ssowmini break; 17906512Ssowmini } 17916200Smx205022 if (ngep->param_link_rx_pause && 17926200Smx205022 !ngep->param_link_tx_pause) 17936200Smx205022 fl = LINK_FLOWCTRL_RX; 17946200Smx205022 17956200Smx205022 if (!ngep->param_link_rx_pause && 17966200Smx205022 !ngep->param_link_tx_pause) 17976200Smx205022 fl = LINK_FLOWCTRL_NONE; 17986200Smx205022 17996200Smx205022 if (!ngep->param_link_rx_pause && 18006200Smx205022 ngep->param_link_tx_pause) 18016200Smx205022 fl = LINK_FLOWCTRL_TX; 18026200Smx205022 18036200Smx205022 if (ngep->param_link_rx_pause && 18046200Smx205022 ngep->param_link_tx_pause) 18056200Smx205022 fl = LINK_FLOWCTRL_BI; 18066200Smx205022 bcopy(&fl, pr_val, sizeof (fl)); 18076512Ssowmini } else 18086512Ssowmini err = EINVAL; 18096200Smx205022 break; 18106789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 18118118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18126512Ssowmini if (is_default) { 18136512Ssowmini *(uint8_t *)pr_val = 1; 18146512Ssowmini } else { 18156200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_1000fdx; 18166200Smx205022 } 18176200Smx205022 break; 18186789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 18196512Ssowmini if (is_default) { 18206512Ssowmini *(uint8_t *)pr_val = 1; 18216512Ssowmini } else { 18226200Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000fdx; 18236200Smx205022 } 18246200Smx205022 break; 18256789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 18268118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18276512Ssowmini if (is_default) { 18286512Ssowmini *(uint8_t *)pr_val = 0; 18296512Ssowmini } else { 18306200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_1000hdx; 18316200Smx205022 } 18326200Smx205022 break; 18336789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 18348118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18356512Ssowmini if (is_default) { 18366512Ssowmini *(uint8_t *)pr_val = 0; 18376512Ssowmini } else { 18386200Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000hdx; 18396200Smx205022 } 18406200Smx205022 break; 18416789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 18428118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18436512Ssowmini if (is_default) { 18446512Ssowmini *(uint8_t *)pr_val = 1; 18456512Ssowmini } else { 18466200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100fdx; 18476200Smx205022 } 18486200Smx205022 break; 18496789Sam223141 case MAC_PROP_EN_100FDX_CAP: 18506512Ssowmini if (is_default) { 18516512Ssowmini *(uint8_t *)pr_val = 1; 18526512Ssowmini } else { 18536200Smx205022 *(uint8_t *)pr_val = ngep->param_en_100fdx; 18546200Smx205022 } 18556200Smx205022 break; 18566789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 18578118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18586512Ssowmini if (is_default) { 18596512Ssowmini *(uint8_t *)pr_val = 1; 18606512Ssowmini } else { 18616200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100hdx; 18626200Smx205022 } 18636200Smx205022 break; 18646789Sam223141 case MAC_PROP_EN_100HDX_CAP: 18656512Ssowmini if (is_default) { 18666512Ssowmini *(uint8_t *)pr_val = 1; 18676512Ssowmini } else { 18686200Smx205022 *(uint8_t *)pr_val = ngep->param_en_100hdx; 18696200Smx205022 } 18706200Smx205022 break; 18716789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 18728118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18736512Ssowmini if (is_default) { 18746512Ssowmini *(uint8_t *)pr_val = 1; 18756512Ssowmini } else { 18766200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10fdx; 18776200Smx205022 } 18786200Smx205022 break; 18796789Sam223141 case MAC_PROP_EN_10FDX_CAP: 18806512Ssowmini if (is_default) { 18816512Ssowmini *(uint8_t *)pr_val = 1; 18826512Ssowmini } else { 18836200Smx205022 *(uint8_t *)pr_val = ngep->param_en_10fdx; 18846200Smx205022 } 18856200Smx205022 break; 18866789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 18878118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18886512Ssowmini if (is_default) { 18896512Ssowmini *(uint8_t *)pr_val = 1; 18906512Ssowmini } else { 18916200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10hdx; 18926200Smx205022 } 18936200Smx205022 break; 18946789Sam223141 case MAC_PROP_EN_10HDX_CAP: 18956512Ssowmini if (is_default) { 18966512Ssowmini *(uint8_t *)pr_val = 1; 18976512Ssowmini } else { 18986200Smx205022 *(uint8_t *)pr_val = ngep->param_en_10hdx; 18996200Smx205022 } 19006200Smx205022 break; 19016789Sam223141 case MAC_PROP_ADV_100T4_CAP: 19026789Sam223141 case MAC_PROP_EN_100T4_CAP: 19038118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 19046512Ssowmini *(uint8_t *)pr_val = 0; 19056512Ssowmini break; 19066789Sam223141 case MAC_PROP_PRIVATE: 19076512Ssowmini err = nge_get_priv_prop(ngep, pr_name, pr_flags, 19086512Ssowmini pr_valsize, pr_val); 19096200Smx205022 break; 19109514SGirish.Moodalbail@Sun.COM case MAC_PROP_MTU: { 19119514SGirish.Moodalbail@Sun.COM mac_propval_range_t range; 19129514SGirish.Moodalbail@Sun.COM 19139514SGirish.Moodalbail@Sun.COM if (!(pr_flags & MAC_PROP_POSSIBLE)) 19149514SGirish.Moodalbail@Sun.COM return (ENOTSUP); 19159514SGirish.Moodalbail@Sun.COM if (pr_valsize < sizeof (mac_propval_range_t)) 19169514SGirish.Moodalbail@Sun.COM return (EINVAL); 19179514SGirish.Moodalbail@Sun.COM range.mpr_count = 1; 19189514SGirish.Moodalbail@Sun.COM range.mpr_type = MAC_PROPVAL_UINT32; 19199514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_min = 19209514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = ETHERMTU; 19219514SGirish.Moodalbail@Sun.COM if (ngep->dev_spec_param.jumbo) 19229514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = NGE_MAX_MTU; 19239514SGirish.Moodalbail@Sun.COM bcopy(&range, pr_val, sizeof (range)); 19249514SGirish.Moodalbail@Sun.COM break; 19259514SGirish.Moodalbail@Sun.COM } 19266200Smx205022 default: 19276200Smx205022 err = ENOTSUP; 19286200Smx205022 } 19296200Smx205022 return (err); 19306200Smx205022 } 19316200Smx205022 19326200Smx205022 /* ARGSUSED */ 19336200Smx205022 static int 19346200Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize, 19356200Smx205022 const void *pr_val) 19366200Smx205022 { 19376200Smx205022 int err = 0; 19386200Smx205022 long result; 19396200Smx205022 19406200Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 19416200Smx205022 if (pr_val == NULL) { 19426200Smx205022 err = EINVAL; 19436200Smx205022 return (err); 19446200Smx205022 } 19456200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19466200Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19476200Smx205022 err = EINVAL; 19486200Smx205022 } else { 19496200Smx205022 ngep->param_txbcopy_threshold = (uint32_t)result; 19506200Smx205022 goto reprogram; 19516200Smx205022 } 19526200Smx205022 return (err); 19536200Smx205022 } 19546200Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 19556200Smx205022 if (pr_val == NULL) { 19566200Smx205022 err = EINVAL; 19576200Smx205022 return (err); 19586200Smx205022 } 19596200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19606200Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19616200Smx205022 err = EINVAL; 19626200Smx205022 } else { 19636200Smx205022 ngep->param_rxbcopy_threshold = (uint32_t)result; 19646200Smx205022 goto reprogram; 19656200Smx205022 } 19666200Smx205022 return (err); 19676200Smx205022 } 19686200Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 19696200Smx205022 if (pr_val == NULL) { 19706200Smx205022 err = EINVAL; 19716200Smx205022 return (err); 19726200Smx205022 } 19736200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19746200Smx205022 if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 19756200Smx205022 err = EINVAL; 19766200Smx205022 } else { 19776200Smx205022 ngep->param_recv_max_packet = (uint32_t)result; 19786200Smx205022 goto reprogram; 19796200Smx205022 } 19806200Smx205022 return (err); 19816200Smx205022 } 19826200Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 19836200Smx205022 if (pr_val == NULL) { 19846200Smx205022 err = EINVAL; 19856200Smx205022 return (err); 19866200Smx205022 } 19876200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19886200Smx205022 if (result < 0 || result > 10000) { 19896200Smx205022 err = EINVAL; 19906200Smx205022 } else { 19916200Smx205022 ngep->param_poll_quiet_time = (uint32_t)result; 19926200Smx205022 goto reprogram; 19936200Smx205022 } 19946200Smx205022 return (err); 19956200Smx205022 } 19966200Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 19976200Smx205022 if (pr_val == NULL) { 19986200Smx205022 err = EINVAL; 19996200Smx205022 return (err); 20006200Smx205022 } 20016200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20026200Smx205022 if (result < 0 || result > 10000) { 20036200Smx205022 err = EINVAL; 20046200Smx205022 } else { 20056200Smx205022 ngep->param_poll_busy_time = (uint32_t)result; 20066200Smx205022 goto reprogram; 20076200Smx205022 } 20086200Smx205022 return (err); 20096200Smx205022 } 20106200Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 20116200Smx205022 if (pr_val == NULL) { 20126200Smx205022 err = EINVAL; 20136200Smx205022 return (err); 20146200Smx205022 } 20156200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20166512Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20176200Smx205022 err = EINVAL; 20186200Smx205022 } else { 20196200Smx205022 ngep->param_rx_intr_hwater = (uint32_t)result; 20206200Smx205022 goto reprogram; 20216200Smx205022 } 20226200Smx205022 return (err); 20236200Smx205022 } 20246200Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 20256200Smx205022 if (pr_val == NULL) { 20266200Smx205022 err = EINVAL; 20276200Smx205022 return (err); 20286200Smx205022 } 20296200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20306512Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20316200Smx205022 err = EINVAL; 20326200Smx205022 } else { 20336200Smx205022 ngep->param_rx_intr_lwater = (uint32_t)result; 20346200Smx205022 goto reprogram; 20356200Smx205022 } 20366200Smx205022 return (err); 20376200Smx205022 } 20386200Smx205022 if (strcmp(pr_name, "_tx_n_intr") == 0) { 20396200Smx205022 if (pr_val == NULL) { 20406200Smx205022 err = EINVAL; 20416200Smx205022 return (err); 20426200Smx205022 } 20436200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20446200Smx205022 if (result < 1 || result > 10000) { 20456200Smx205022 err = EINVAL; 20466200Smx205022 } else { 20476200Smx205022 ngep->param_tx_n_intr = (uint32_t)result; 20486200Smx205022 goto reprogram; 20496200Smx205022 } 20506200Smx205022 return (err); 20516200Smx205022 } 20526200Smx205022 20536200Smx205022 err = ENOTSUP; 20546200Smx205022 return (err); 20556200Smx205022 20566200Smx205022 reprogram: 20576200Smx205022 if (err == 0) { 20586200Smx205022 (*ngep->physops->phys_update)(ngep); 20596200Smx205022 nge_chip_sync(ngep); 20606200Smx205022 } 20616200Smx205022 20626200Smx205022 return (err); 20636200Smx205022 } 20646200Smx205022 20656200Smx205022 static int 20666512Ssowmini nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_flags, 20676512Ssowmini uint_t pr_valsize, void *pr_val) 20686200Smx205022 { 20696200Smx205022 int err = ENOTSUP; 20706789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 20716512Ssowmini int value; 20726512Ssowmini 20736512Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 20746512Ssowmini value = (is_default ? 1 : ngep->param_adv_pause); 20756512Ssowmini err = 0; 20766512Ssowmini goto done; 20776512Ssowmini } 20786512Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 20796512Ssowmini value = (is_default ? 1 : ngep->param_adv_asym_pause); 20806512Ssowmini err = 0; 20816512Ssowmini goto done; 20826512Ssowmini } 20836200Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 20846512Ssowmini value = (is_default ? NGE_TX_COPY_SIZE : 20856512Ssowmini ngep->param_txbcopy_threshold); 20866200Smx205022 err = 0; 20876200Smx205022 goto done; 20886200Smx205022 } 20896200Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 20906512Ssowmini value = (is_default ? NGE_RX_COPY_SIZE : 20916512Ssowmini ngep->param_rxbcopy_threshold); 20926200Smx205022 err = 0; 20936200Smx205022 goto done; 20946200Smx205022 } 20956200Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 20966512Ssowmini value = (is_default ? 128 : ngep->param_recv_max_packet); 20976200Smx205022 err = 0; 20986200Smx205022 goto done; 20996200Smx205022 } 21006200Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 21016512Ssowmini value = (is_default ? NGE_POLL_QUIET_TIME : 21026512Ssowmini ngep->param_poll_quiet_time); 21036200Smx205022 err = 0; 21046200Smx205022 goto done; 21056200Smx205022 } 21066200Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 21076512Ssowmini value = (is_default ? NGE_POLL_BUSY_TIME : 21086512Ssowmini ngep->param_poll_busy_time); 21096200Smx205022 err = 0; 21106200Smx205022 goto done; 21116200Smx205022 } 21126200Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 21136512Ssowmini value = (is_default ? 1 : ngep->param_rx_intr_hwater); 21146200Smx205022 err = 0; 21156200Smx205022 goto done; 21166200Smx205022 } 21176200Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 21186512Ssowmini value = (is_default ? 8 : ngep->param_rx_intr_lwater); 21196200Smx205022 err = 0; 21206200Smx205022 goto done; 21216200Smx205022 } 21226200Smx205022 if (strcmp(pr_name, "_tx_n_intr") == 0) { 21236512Ssowmini value = (is_default ? NGE_TX_N_INTR : 21246512Ssowmini ngep->param_tx_n_intr); 21256200Smx205022 err = 0; 21266200Smx205022 goto done; 21276200Smx205022 } 21286200Smx205022 21296200Smx205022 done: 21306200Smx205022 if (err == 0) { 21316512Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 21326200Smx205022 } 21336200Smx205022 return (err); 21346200Smx205022 } 21356200Smx205022 21365574Smx205022 /* ARGSUSED */ 21375574Smx205022 static boolean_t 21385574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 21395574Smx205022 { 21405574Smx205022 nge_t *ngep = arg; 21415574Smx205022 nge_dev_spec_param_t *dev_param_p; 21425574Smx205022 21435574Smx205022 dev_param_p = &ngep->dev_spec_param; 21445574Smx205022 21455574Smx205022 switch (cap) { 21465574Smx205022 case MAC_CAPAB_HCKSUM: { 21475574Smx205022 uint32_t *hcksum_txflags = cap_data; 21485574Smx205022 21495574Smx205022 if (dev_param_p->tx_hw_checksum) { 21505574Smx205022 *hcksum_txflags = dev_param_p->tx_hw_checksum; 21515574Smx205022 } else 21525574Smx205022 return (B_FALSE); 21535574Smx205022 break; 21545574Smx205022 } 21555574Smx205022 default: 21565574Smx205022 return (B_FALSE); 21575574Smx205022 } 21585574Smx205022 return (B_TRUE); 21595574Smx205022 } 21605574Smx205022 21615574Smx205022 #undef NGE_DBG 21625574Smx205022 #define NGE_DBG NGE_DBG_INIT /* debug flag for this code */ 21635574Smx205022 int 21645574Smx205022 nge_restart(nge_t *ngep) 21655574Smx205022 { 21665574Smx205022 int err = 0; 21677656SSherry.Moore@Sun.COM err = nge_reset_dev(ngep); 21687155Smx205022 /* write back the promisc setting */ 21697155Smx205022 ngep->promisc = ngep->record_promisc; 21706366Smx205022 nge_chip_sync(ngep); 21715869Smx205022 if (!err) 21725869Smx205022 err = nge_chip_start(ngep); 21735574Smx205022 21745574Smx205022 if (err) { 21755574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 21765574Smx205022 return (DDI_FAILURE); 21775574Smx205022 } else { 21785574Smx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 21795574Smx205022 return (DDI_SUCCESS); 21805574Smx205022 } 21815574Smx205022 } 21825574Smx205022 21835574Smx205022 void 21845574Smx205022 nge_wake_factotum(nge_t *ngep) 21855574Smx205022 { 21865574Smx205022 mutex_enter(ngep->softlock); 21875574Smx205022 if (ngep->factotum_flag == 0) { 21885574Smx205022 ngep->factotum_flag = 1; 21895574Smx205022 (void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL); 21905574Smx205022 } 21915574Smx205022 mutex_exit(ngep->softlock); 21925574Smx205022 } 21935574Smx205022 21945574Smx205022 /* 21955574Smx205022 * High-level cyclic handler 21965574Smx205022 * 21975574Smx205022 * This routine schedules a (low-level) softint callback to the 21985574Smx205022 * factotum. 21995574Smx205022 */ 22005574Smx205022 22015574Smx205022 static void 22025574Smx205022 nge_chip_cyclic(void *arg) 22035574Smx205022 { 22045574Smx205022 nge_t *ngep; 22055574Smx205022 22065574Smx205022 ngep = (nge_t *)arg; 22075574Smx205022 22085574Smx205022 switch (ngep->nge_chip_state) { 22095574Smx205022 default: 22105574Smx205022 return; 22115574Smx205022 22125574Smx205022 case NGE_CHIP_RUNNING: 22135574Smx205022 break; 22145574Smx205022 22155574Smx205022 case NGE_CHIP_FAULT: 22165574Smx205022 case NGE_CHIP_ERROR: 22175574Smx205022 break; 22185574Smx205022 } 22195574Smx205022 22205574Smx205022 nge_wake_factotum(ngep); 22215574Smx205022 } 22225574Smx205022 2223*9604SZhen.W@Sun.COM /* 2224*9604SZhen.W@Sun.COM * Get/Release semaphore of SMU 2225*9604SZhen.W@Sun.COM * For SMU enabled chipset 2226*9604SZhen.W@Sun.COM * When nge driver is attached, driver should acquire 2227*9604SZhen.W@Sun.COM * semaphore before PHY init and accessing MAC registers. 2228*9604SZhen.W@Sun.COM * When nge driver is unattached, driver should release 2229*9604SZhen.W@Sun.COM * semaphore. 2230*9604SZhen.W@Sun.COM */ 2231*9604SZhen.W@Sun.COM 2232*9604SZhen.W@Sun.COM static int 2233*9604SZhen.W@Sun.COM nge_smu_sema(nge_t *ngep, boolean_t acquire) 2234*9604SZhen.W@Sun.COM { 2235*9604SZhen.W@Sun.COM nge_tx_en tx_en; 2236*9604SZhen.W@Sun.COM uint32_t tries; 2237*9604SZhen.W@Sun.COM 2238*9604SZhen.W@Sun.COM if (acquire) { 2239*9604SZhen.W@Sun.COM for (tries = 0; tries < 5; tries++) { 2240*9604SZhen.W@Sun.COM tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 2241*9604SZhen.W@Sun.COM if (tx_en.bits.smu2mac == NGE_SMU_FREE) 2242*9604SZhen.W@Sun.COM break; 2243*9604SZhen.W@Sun.COM delay(drv_usectohz(1000000)); 2244*9604SZhen.W@Sun.COM } 2245*9604SZhen.W@Sun.COM if (tx_en.bits.smu2mac != NGE_SMU_FREE) 2246*9604SZhen.W@Sun.COM return (DDI_FAILURE); 2247*9604SZhen.W@Sun.COM for (tries = 0; tries < 5; tries++) { 2248*9604SZhen.W@Sun.COM tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 2249*9604SZhen.W@Sun.COM tx_en.bits.mac2smu = NGE_SMU_GET; 2250*9604SZhen.W@Sun.COM nge_reg_put32(ngep, NGE_TX_EN, tx_en.val); 2251*9604SZhen.W@Sun.COM tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 2252*9604SZhen.W@Sun.COM 2253*9604SZhen.W@Sun.COM if (tx_en.bits.mac2smu == NGE_SMU_GET && 2254*9604SZhen.W@Sun.COM tx_en.bits.smu2mac == NGE_SMU_FREE) 2255*9604SZhen.W@Sun.COM return (DDI_SUCCESS); 2256*9604SZhen.W@Sun.COM drv_usecwait(10); 2257*9604SZhen.W@Sun.COM } 2258*9604SZhen.W@Sun.COM return (DDI_FAILURE); 2259*9604SZhen.W@Sun.COM } else 2260*9604SZhen.W@Sun.COM nge_reg_put32(ngep, NGE_TX_EN, 0x0); 2261*9604SZhen.W@Sun.COM 2262*9604SZhen.W@Sun.COM return (DDI_SUCCESS); 2263*9604SZhen.W@Sun.COM 2264*9604SZhen.W@Sun.COM } 22655574Smx205022 static void 22665574Smx205022 nge_unattach(nge_t *ngep) 22675574Smx205022 { 22685574Smx205022 send_ring_t *srp; 22695574Smx205022 buff_ring_t *brp; 22705574Smx205022 22715574Smx205022 srp = ngep->send; 22725574Smx205022 brp = ngep->buff; 22735574Smx205022 NGE_TRACE(("nge_unattach($%p)", (void *)ngep)); 22745574Smx205022 22755574Smx205022 /* 22765574Smx205022 * Flag that no more activity may be initiated 22775574Smx205022 */ 22785574Smx205022 ngep->progress &= ~PROGRESS_READY; 22795574Smx205022 ngep->nge_mac_state = NGE_MAC_UNATTACH; 22805574Smx205022 22815574Smx205022 /* 22825574Smx205022 * Quiesce the PHY and MAC (leave it reset but still powered). 22835574Smx205022 * Clean up and free all NGE data structures 22845574Smx205022 */ 22855574Smx205022 if (ngep->periodic_id != NULL) { 22865574Smx205022 ddi_periodic_delete(ngep->periodic_id); 22875574Smx205022 ngep->periodic_id = NULL; 22885574Smx205022 } 22895574Smx205022 22905574Smx205022 if (ngep->progress & PROGRESS_KSTATS) 22915574Smx205022 nge_fini_kstats(ngep); 22925574Smx205022 22935574Smx205022 if (ngep->progress & PROGRESS_HWINT) { 22945574Smx205022 mutex_enter(ngep->genlock); 22955574Smx205022 nge_restore_mac_addr(ngep); 22965574Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 2297*9604SZhen.W@Sun.COM if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 2298*9604SZhen.W@Sun.COM ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 2299*9604SZhen.W@Sun.COM (void) nge_smu_sema(ngep, B_FALSE); 2300*9604SZhen.W@Sun.COM } 23015574Smx205022 mutex_exit(ngep->genlock); 23025574Smx205022 } 23035574Smx205022 23045574Smx205022 if (ngep->progress & PROGRESS_SWINT) 23055574Smx205022 nge_rem_intrs(ngep); 23065574Smx205022 23075574Smx205022 if (ngep->progress & PROGRESS_FACTOTUM) 23085574Smx205022 (void) ddi_intr_remove_softint(ngep->factotum_hdl); 23095574Smx205022 23105574Smx205022 if (ngep->progress & PROGRESS_RESCHED) 23115574Smx205022 (void) ddi_intr_remove_softint(ngep->resched_hdl); 23125574Smx205022 23135574Smx205022 if (ngep->progress & PROGRESS_INTR) { 23145574Smx205022 mutex_destroy(srp->tx_lock); 23155574Smx205022 mutex_destroy(srp->tc_lock); 23165574Smx205022 mutex_destroy(&srp->dmah_lock); 23175574Smx205022 mutex_destroy(brp->recycle_lock); 23185574Smx205022 23195574Smx205022 mutex_destroy(ngep->genlock); 23205574Smx205022 mutex_destroy(ngep->softlock); 23215574Smx205022 rw_destroy(ngep->rwlock); 23225574Smx205022 } 23235574Smx205022 23245574Smx205022 if (ngep->progress & PROGRESS_REGS) 23255574Smx205022 ddi_regs_map_free(&ngep->io_handle); 23265574Smx205022 23275574Smx205022 if (ngep->progress & PROGRESS_CFG) 23285574Smx205022 pci_config_teardown(&ngep->cfg_handle); 23295574Smx205022 23305574Smx205022 ddi_remove_minor_node(ngep->devinfo, NULL); 23315574Smx205022 23325574Smx205022 kmem_free(ngep, sizeof (*ngep)); 23335574Smx205022 } 23345574Smx205022 23355574Smx205022 static int 23365574Smx205022 nge_resume(dev_info_t *devinfo) 23375574Smx205022 { 23385574Smx205022 nge_t *ngep; 23395574Smx205022 chip_info_t *infop; 23405869Smx205022 int err; 23415574Smx205022 23425574Smx205022 ASSERT(devinfo != NULL); 23435574Smx205022 23445574Smx205022 ngep = ddi_get_driver_private(devinfo); 23455869Smx205022 err = 0; 23465869Smx205022 23475574Smx205022 /* 23485574Smx205022 * If there are state inconsistancies, this is bad. Returning 23495574Smx205022 * DDI_FAILURE here will eventually cause the machine to panic, 23505574Smx205022 * so it is best done here so that there is a possibility of 23515574Smx205022 * debugging the problem. 23525574Smx205022 */ 23535574Smx205022 if (ngep == NULL) 23545574Smx205022 cmn_err(CE_PANIC, 23555574Smx205022 "nge: ngep returned from ddi_get_driver_private was NULL"); 23565574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 23575574Smx205022 23585574Smx205022 if (ngep->devinfo != devinfo) 23595574Smx205022 cmn_err(CE_PANIC, 23605869Smx205022 "nge: passed devinfo not the same as saved devinfo"); 23615574Smx205022 23625869Smx205022 mutex_enter(ngep->genlock); 23635869Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 23645574Smx205022 23655574Smx205022 /* 23665574Smx205022 * Fetch the config space. Even though we have most of it cached, 23675574Smx205022 * some values *might* change across a suspend/resume. 23685574Smx205022 */ 23695574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 23705574Smx205022 23715574Smx205022 /* 23725869Smx205022 * Only in one case, this conditional branch can be executed: the port 23735869Smx205022 * hasn't been plumbed. 23745574Smx205022 */ 23755869Smx205022 if (ngep->suspended == B_FALSE) { 23765869Smx205022 rw_exit(ngep->rwlock); 23775869Smx205022 mutex_exit(ngep->genlock); 23785869Smx205022 return (DDI_SUCCESS); 23795869Smx205022 } 23805869Smx205022 23815869Smx205022 nge_tx_recycle_all(ngep); 23825869Smx205022 err = nge_reinit_ring(ngep); 23835869Smx205022 if (!err) { 23845869Smx205022 err = nge_chip_reset(ngep); 23855869Smx205022 if (!err) 23865869Smx205022 err = nge_chip_start(ngep); 23875869Smx205022 } 23885869Smx205022 23895869Smx205022 if (err) { 23905574Smx205022 /* 23915574Smx205022 * We note the failure, but return success, as the 23925574Smx205022 * system is still usable without this controller. 23935574Smx205022 */ 23945574Smx205022 cmn_err(CE_WARN, "nge: resume: failed to restart controller"); 23955869Smx205022 } else { 23965869Smx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 23975574Smx205022 } 23985869Smx205022 ngep->suspended = B_FALSE; 23995869Smx205022 24005869Smx205022 rw_exit(ngep->rwlock); 24015869Smx205022 mutex_exit(ngep->genlock); 24025869Smx205022 24035574Smx205022 return (DDI_SUCCESS); 24045574Smx205022 } 24055574Smx205022 24065574Smx205022 /* 24075574Smx205022 * attach(9E) -- Attach a device to the system 24085574Smx205022 * 24095574Smx205022 * Called once for each board successfully probed. 24105574Smx205022 */ 24115574Smx205022 static int 24125574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 24135574Smx205022 { 24145574Smx205022 int err; 24155574Smx205022 int i; 24165574Smx205022 int instance; 24175574Smx205022 caddr_t regs; 24185574Smx205022 nge_t *ngep; 24195574Smx205022 chip_info_t *infop; 24205574Smx205022 mac_register_t *macp; 24215574Smx205022 24225574Smx205022 switch (cmd) { 24235574Smx205022 default: 24245574Smx205022 return (DDI_FAILURE); 24255574Smx205022 24265574Smx205022 case DDI_RESUME: 24275574Smx205022 return (nge_resume(devinfo)); 24285574Smx205022 24295574Smx205022 case DDI_ATTACH: 24305574Smx205022 break; 24315574Smx205022 } 24325574Smx205022 24335574Smx205022 ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP); 24345574Smx205022 instance = ddi_get_instance(devinfo); 24355574Smx205022 ddi_set_driver_private(devinfo, ngep); 24365574Smx205022 ngep->devinfo = devinfo; 24375574Smx205022 24385574Smx205022 (void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d", 24395574Smx205022 NGE_DRIVER_NAME, instance); 24405574Smx205022 err = pci_config_setup(devinfo, &ngep->cfg_handle); 24415574Smx205022 if (err != DDI_SUCCESS) { 24425574Smx205022 nge_problem(ngep, "nge_attach: pci_config_setup() failed"); 24435574Smx205022 goto attach_fail; 24445574Smx205022 } 24456512Ssowmini /* 24466512Ssowmini * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy 24476512Ssowmini * thresholds. Bounds: min 0, max NGE_MAX_SDU 24486512Ssowmini */ 24496512Ssowmini ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE; 24506512Ssowmini ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE; 24516512Ssowmini 24526512Ssowmini /* 24536512Ssowmini * param_recv_max_packet is max packet received per interupt. 24546512Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024 24556512Ssowmini */ 24566512Ssowmini ngep->param_recv_max_packet = 128; 24576512Ssowmini 24586512Ssowmini /* 24596512Ssowmini * param_poll_quiet_time and param_poll_busy_time are quiet/busy time 24606512Ssowmini * switch from per packet interrupt to polling interrupt. 24616512Ssowmini * Bounds: min 0, max 10000 24626512Ssowmini */ 24636512Ssowmini ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME; 24646512Ssowmini ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME; 24656512Ssowmini 24666512Ssowmini /* 24676512Ssowmini * param_rx_intr_hwater/param_rx_intr_lwater: ackets received 24686512Ssowmini * to trigger the poll_quiet_time/poll_busy_time counter. 24696512Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024. 24706512Ssowmini */ 24716512Ssowmini ngep->param_rx_intr_hwater = 1; 24726512Ssowmini ngep->param_rx_intr_lwater = 8; 24736512Ssowmini 24746512Ssowmini /* 24756512Ssowmini * param_tx_n_intr: Per N tx packets to do tx recycle in poll mode. 24766512Ssowmini * Bounds: min 1, max 10000. 24776512Ssowmini */ 24786512Ssowmini ngep->param_tx_n_intr = NGE_TX_N_INTR; 24796512Ssowmini 24805574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 24815574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 24825574Smx205022 nge_init_dev_spec_param(ngep); 24835574Smx205022 nge_get_props(ngep); 24845574Smx205022 ngep->progress |= PROGRESS_CFG; 24855574Smx205022 24865574Smx205022 err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER, 24875574Smx205022 ®s, 0, 0, &nge_reg_accattr, &ngep->io_handle); 24885574Smx205022 if (err != DDI_SUCCESS) { 24895574Smx205022 nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed"); 24905574Smx205022 goto attach_fail; 24915574Smx205022 } 24925574Smx205022 ngep->io_regs = regs; 24935574Smx205022 ngep->progress |= PROGRESS_REGS; 24945574Smx205022 24955574Smx205022 err = nge_register_intrs_and_init_locks(ngep); 24965574Smx205022 if (err != DDI_SUCCESS) { 24975574Smx205022 nge_problem(ngep, "nge_attach:" 24985574Smx205022 " register intrs and init locks failed"); 24995574Smx205022 goto attach_fail; 25005574Smx205022 } 25015574Smx205022 nge_init_ring_param_lock(ngep); 25025574Smx205022 ngep->progress |= PROGRESS_INTR; 25035574Smx205022 25045574Smx205022 mutex_enter(ngep->genlock); 25055574Smx205022 2506*9604SZhen.W@Sun.COM if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 2507*9604SZhen.W@Sun.COM ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 2508*9604SZhen.W@Sun.COM err = nge_smu_sema(ngep, B_TRUE); 2509*9604SZhen.W@Sun.COM if (err != DDI_SUCCESS) { 2510*9604SZhen.W@Sun.COM nge_problem(ngep, "nge_attach: nge_smu_sema() failed"); 2511*9604SZhen.W@Sun.COM goto attach_fail; 2512*9604SZhen.W@Sun.COM } 2513*9604SZhen.W@Sun.COM } 25145574Smx205022 /* 25155574Smx205022 * Initialise link state variables 25165574Smx205022 * Stop, reset & reinitialise the chip. 25175574Smx205022 * Initialise the (internal) PHY. 25185574Smx205022 */ 25195574Smx205022 nge_phys_init(ngep); 25208218SMin.Xu@Sun.COM ngep->nge_chip_state = NGE_CHIP_INITIAL; 25215574Smx205022 err = nge_chip_reset(ngep); 25225574Smx205022 if (err != DDI_SUCCESS) { 25235574Smx205022 nge_problem(ngep, "nge_attach: nge_chip_reset() failed"); 25245574Smx205022 mutex_exit(ngep->genlock); 25255574Smx205022 goto attach_fail; 25265574Smx205022 } 25275574Smx205022 nge_chip_sync(ngep); 25285574Smx205022 25295574Smx205022 /* 25305574Smx205022 * Now that mutex locks are initialized, enable interrupts. 25315574Smx205022 */ 25325574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 25335574Smx205022 /* Call ddi_intr_block_enable() for MSI interrupts */ 25345574Smx205022 (void) ddi_intr_block_enable(ngep->htable, 25355574Smx205022 ngep->intr_actual_cnt); 25365574Smx205022 } else { 25375574Smx205022 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 25385574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 25395574Smx205022 (void) ddi_intr_enable(ngep->htable[i]); 25405574Smx205022 } 25415574Smx205022 } 25425574Smx205022 25435574Smx205022 ngep->link_state = LINK_STATE_UNKNOWN; 25445574Smx205022 ngep->progress |= PROGRESS_HWINT; 25455574Smx205022 25465574Smx205022 /* 25475574Smx205022 * Register NDD-tweakable parameters 25485574Smx205022 */ 25495574Smx205022 if (nge_nd_init(ngep)) { 25505574Smx205022 nge_problem(ngep, "nge_attach: nge_nd_init() failed"); 25515574Smx205022 mutex_exit(ngep->genlock); 25525574Smx205022 goto attach_fail; 25535574Smx205022 } 25545574Smx205022 ngep->progress |= PROGRESS_NDD; 25555574Smx205022 25565574Smx205022 /* 25575574Smx205022 * Create & initialise named kstats 25585574Smx205022 */ 25595574Smx205022 nge_init_kstats(ngep, instance); 25605574Smx205022 ngep->progress |= PROGRESS_KSTATS; 25615574Smx205022 25625574Smx205022 mutex_exit(ngep->genlock); 25635574Smx205022 25645574Smx205022 if ((macp = mac_alloc(MAC_VERSION)) == NULL) 25655574Smx205022 goto attach_fail; 25665574Smx205022 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 25675574Smx205022 macp->m_driver = ngep; 25685574Smx205022 macp->m_dip = devinfo; 25695574Smx205022 macp->m_src_addr = infop->vendor_addr.addr; 25705574Smx205022 macp->m_callbacks = &nge_m_callbacks; 25715574Smx205022 macp->m_min_sdu = 0; 25725574Smx205022 macp->m_max_sdu = ngep->default_mtu; 25735895Syz147064 macp->m_margin = VTAG_SIZE; 25746512Ssowmini macp->m_priv_props = nge_priv_props; 25756512Ssowmini macp->m_priv_prop_count = NGE_MAX_PRIV_PROPS; 25765574Smx205022 /* 25775574Smx205022 * Finally, we're ready to register ourselves with the mac 25785574Smx205022 * interface; if this succeeds, we're all ready to start() 25795574Smx205022 */ 25805574Smx205022 err = mac_register(macp, &ngep->mh); 25815574Smx205022 mac_free(macp); 25825574Smx205022 if (err != 0) 25835574Smx205022 goto attach_fail; 25845574Smx205022 25855574Smx205022 /* 25865574Smx205022 * Register a periodical handler. 25875574Smx205022 * nge_chip_cyclic() is invoked in kernel context. 25885574Smx205022 */ 25895574Smx205022 ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep, 25905574Smx205022 NGE_CYCLIC_PERIOD, DDI_IPL_0); 25915574Smx205022 25925574Smx205022 ngep->progress |= PROGRESS_READY; 25935574Smx205022 return (DDI_SUCCESS); 25945574Smx205022 25955574Smx205022 attach_fail: 25965574Smx205022 nge_unattach(ngep); 25975574Smx205022 return (DDI_FAILURE); 25985574Smx205022 } 25995574Smx205022 26005869Smx205022 static int 26015869Smx205022 nge_suspend(nge_t *ngep) 26025869Smx205022 { 26035869Smx205022 mutex_enter(ngep->genlock); 26045869Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 26055869Smx205022 26065869Smx205022 /* if the port hasn't been plumbed, just return */ 26075869Smx205022 if (ngep->nge_mac_state != NGE_MAC_STARTED) { 26085869Smx205022 rw_exit(ngep->rwlock); 26095869Smx205022 mutex_exit(ngep->genlock); 26105869Smx205022 return (DDI_SUCCESS); 26115869Smx205022 } 26125869Smx205022 ngep->suspended = B_TRUE; 26135869Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 26145869Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 26155869Smx205022 26165869Smx205022 rw_exit(ngep->rwlock); 26175869Smx205022 mutex_exit(ngep->genlock); 26185869Smx205022 return (DDI_SUCCESS); 26195869Smx205022 } 26205869Smx205022 26215574Smx205022 /* 26225574Smx205022 * detach(9E) -- Detach a device from the system 26235574Smx205022 */ 26245574Smx205022 static int 26255574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 26265574Smx205022 { 26275574Smx205022 int i; 26285574Smx205022 nge_t *ngep; 26295574Smx205022 mul_item *p, *nextp; 26305574Smx205022 buff_ring_t *brp; 26315574Smx205022 26325574Smx205022 NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd)); 26335574Smx205022 26345574Smx205022 ngep = ddi_get_driver_private(devinfo); 26355574Smx205022 brp = ngep->buff; 26365574Smx205022 26375574Smx205022 switch (cmd) { 26385574Smx205022 default: 26395574Smx205022 return (DDI_FAILURE); 26405574Smx205022 26415574Smx205022 case DDI_SUSPEND: 26425574Smx205022 /* 26435574Smx205022 * Stop the NIC 26445574Smx205022 * Note: This driver doesn't currently support WOL, but 26455574Smx205022 * should it in the future, it is important to 26465574Smx205022 * make sure the PHY remains powered so that the 26475574Smx205022 * wakeup packet can actually be recieved. 26485574Smx205022 */ 26495869Smx205022 return (nge_suspend(ngep)); 26505574Smx205022 26515574Smx205022 case DDI_DETACH: 26525574Smx205022 break; 26535574Smx205022 } 26545574Smx205022 26555574Smx205022 /* Try to wait all the buffer post to upper layer be released */ 26565574Smx205022 for (i = 0; i < 1000; i++) { 26575574Smx205022 if (brp->rx_hold == 0) 26585574Smx205022 break; 26595574Smx205022 drv_usecwait(1000); 26605574Smx205022 } 26615574Smx205022 26625574Smx205022 /* If there is any posted buffer, reject to detach */ 26635574Smx205022 if (brp->rx_hold != 0) 26645574Smx205022 return (DDI_FAILURE); 26655574Smx205022 26665574Smx205022 /* 26675574Smx205022 * Unregister from the GLD subsystem. This can fail, in 26685574Smx205022 * particular if there are DLPI style-2 streams still open - 26695574Smx205022 * in which case we just return failure without shutting 26705574Smx205022 * down chip operations. 26715574Smx205022 */ 26725574Smx205022 if (mac_unregister(ngep->mh) != DDI_SUCCESS) 26735574Smx205022 return (DDI_FAILURE); 26745574Smx205022 26755574Smx205022 /* 26766366Smx205022 * Recycle the multicast table. mac_unregister() should be called 26776366Smx205022 * before it to ensure the multicast table can be used even if 26786366Smx205022 * mac_unregister() fails. 26796366Smx205022 */ 26806366Smx205022 for (p = ngep->pcur_mulist; p != NULL; p = nextp) { 26816366Smx205022 nextp = p->next; 26826366Smx205022 kmem_free(p, sizeof (mul_item)); 26836366Smx205022 } 26846366Smx205022 ngep->pcur_mulist = NULL; 26856366Smx205022 26866366Smx205022 /* 26875574Smx205022 * All activity stopped, so we can clean up & exit 26885574Smx205022 */ 26895574Smx205022 nge_unattach(ngep); 26905574Smx205022 return (DDI_SUCCESS); 26915574Smx205022 } 26925574Smx205022 26937656SSherry.Moore@Sun.COM /* 26947656SSherry.Moore@Sun.COM * quiesce(9E) entry point. 26957656SSherry.Moore@Sun.COM * 26967656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high 26977656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 26987656SSherry.Moore@Sun.COM * blocked. 26997656SSherry.Moore@Sun.COM * 27007656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 27017656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 27027656SSherry.Moore@Sun.COM */ 27037656SSherry.Moore@Sun.COM static int 27047656SSherry.Moore@Sun.COM nge_quiesce(dev_info_t *devinfo) 27057656SSherry.Moore@Sun.COM { 27067656SSherry.Moore@Sun.COM nge_t *ngep; 27077656SSherry.Moore@Sun.COM 27087656SSherry.Moore@Sun.COM ngep = ddi_get_driver_private(devinfo); 27097656SSherry.Moore@Sun.COM 27107656SSherry.Moore@Sun.COM if (ngep == NULL) 27117656SSherry.Moore@Sun.COM return (DDI_FAILURE); 27127656SSherry.Moore@Sun.COM 27137656SSherry.Moore@Sun.COM /* 27147656SSherry.Moore@Sun.COM * Turn off debug tracing 27157656SSherry.Moore@Sun.COM */ 27167656SSherry.Moore@Sun.COM nge_debug = 0; 27177656SSherry.Moore@Sun.COM ngep->debug = 0; 27187656SSherry.Moore@Sun.COM 27197656SSherry.Moore@Sun.COM nge_restore_mac_addr(ngep); 27207656SSherry.Moore@Sun.COM (void) nge_chip_stop(ngep, B_FALSE); 27217656SSherry.Moore@Sun.COM 27227656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 27237656SSherry.Moore@Sun.COM } 27247656SSherry.Moore@Sun.COM 27257656SSherry.Moore@Sun.COM 27265574Smx205022 27275574Smx205022 /* 27285574Smx205022 * ========== Module Loading Data & Entry Points ========== 27295574Smx205022 */ 27305574Smx205022 27315574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach, 27327656SSherry.Moore@Sun.COM NULL, NULL, D_MP, NULL, nge_quiesce); 27335574Smx205022 27345574Smx205022 27355574Smx205022 static struct modldrv nge_modldrv = { 27365574Smx205022 &mod_driverops, /* Type of module. This one is a driver */ 27375574Smx205022 nge_ident, /* short description */ 27385574Smx205022 &nge_dev_ops /* driver specific ops */ 27395574Smx205022 }; 27405574Smx205022 27415574Smx205022 static struct modlinkage modlinkage = { 27425574Smx205022 MODREV_1, (void *)&nge_modldrv, NULL 27435574Smx205022 }; 27445574Smx205022 27455574Smx205022 27465574Smx205022 int 27475574Smx205022 _info(struct modinfo *modinfop) 27485574Smx205022 { 27495574Smx205022 return (mod_info(&modlinkage, modinfop)); 27505574Smx205022 } 27515574Smx205022 27525574Smx205022 int 27535574Smx205022 _init(void) 27545574Smx205022 { 27555574Smx205022 int status; 27565574Smx205022 27575574Smx205022 mac_init_ops(&nge_dev_ops, "nge"); 27585574Smx205022 status = mod_install(&modlinkage); 27595574Smx205022 if (status != DDI_SUCCESS) 27605574Smx205022 mac_fini_ops(&nge_dev_ops); 27615574Smx205022 else 27625574Smx205022 mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL); 27635574Smx205022 27645574Smx205022 return (status); 27655574Smx205022 } 27665574Smx205022 27675574Smx205022 int 27685574Smx205022 _fini(void) 27695574Smx205022 { 27705574Smx205022 int status; 27715574Smx205022 27725574Smx205022 status = mod_remove(&modlinkage); 27735574Smx205022 if (status == DDI_SUCCESS) { 27745574Smx205022 mac_fini_ops(&nge_dev_ops); 27755574Smx205022 mutex_destroy(nge_log_mutex); 27765574Smx205022 } 27775574Smx205022 27785574Smx205022 return (status); 27795574Smx205022 } 27805574Smx205022 27815574Smx205022 /* 27825574Smx205022 * ============ Init MSI/Fixed/SoftInterrupt routines ============== 27835574Smx205022 */ 27845574Smx205022 27855574Smx205022 /* 27865574Smx205022 * Register interrupts and initialize each mutex and condition variables 27875574Smx205022 */ 27885574Smx205022 27895574Smx205022 static int 27905574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep) 27915574Smx205022 { 27925574Smx205022 int err; 27935574Smx205022 int intr_types; 27945574Smx205022 uint_t soft_prip; 27955574Smx205022 nge_msi_mask msi_mask; 27965574Smx205022 nge_msi_map0_vec map0_vec; 27975574Smx205022 nge_msi_map1_vec map1_vec; 27985574Smx205022 27995574Smx205022 /* 28005574Smx205022 * Add the softint handlers: 28015574Smx205022 * 28025574Smx205022 * Both of these handlers are used to avoid restrictions on the 28035574Smx205022 * context and/or mutexes required for some operations. In 28045574Smx205022 * particular, the hardware interrupt handler and its subfunctions 28055574Smx205022 * can detect a number of conditions that we don't want to handle 28065574Smx205022 * in that context or with that set of mutexes held. So, these 28075574Smx205022 * softints are triggered instead: 28085574Smx205022 * 28095574Smx205022 * the <resched> softint is triggered if if we have previously 28105574Smx205022 * had to refuse to send a packet because of resource shortage 28115574Smx205022 * (we've run out of transmit buffers), but the send completion 28125574Smx205022 * interrupt handler has now detected that more buffers have 28135574Smx205022 * become available. Its only purpose is to call gld_sched() 28145574Smx205022 * to retry the pending transmits (we're not allowed to hold 28155574Smx205022 * driver-defined mutexes across gld_sched()). 28165574Smx205022 * 28175574Smx205022 * the <factotum> is triggered if the h/w interrupt handler 28185574Smx205022 * sees the <link state changed> or <error> bits in the status 28195574Smx205022 * block. It's also triggered periodically to poll the link 28205574Smx205022 * state, just in case we aren't getting link status change 28215574Smx205022 * interrupts ... 28225574Smx205022 */ 28235574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl, 28245574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep); 28255574Smx205022 if (err != DDI_SUCCESS) { 28265574Smx205022 nge_problem(ngep, 28275574Smx205022 "nge_attach: add nge_reschedule softintr failed"); 28285574Smx205022 28295574Smx205022 return (DDI_FAILURE); 28305574Smx205022 } 28315574Smx205022 ngep->progress |= PROGRESS_RESCHED; 28325574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl, 28335574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep); 28345574Smx205022 if (err != DDI_SUCCESS) { 28355574Smx205022 nge_problem(ngep, 28365574Smx205022 "nge_attach: add nge_chip_factotum softintr failed!"); 28375574Smx205022 28385574Smx205022 return (DDI_FAILURE); 28395574Smx205022 } 28405574Smx205022 if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip) 28415574Smx205022 != DDI_SUCCESS) { 28425574Smx205022 nge_problem(ngep, "nge_attach: get softintr priority failed\n"); 28435574Smx205022 28445574Smx205022 return (DDI_FAILURE); 28455574Smx205022 } 28465574Smx205022 ngep->soft_pri = soft_prip; 28475574Smx205022 28485574Smx205022 ngep->progress |= PROGRESS_FACTOTUM; 28495574Smx205022 /* Get supported interrupt types */ 28505574Smx205022 if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types) 28515574Smx205022 != DDI_SUCCESS) { 28525574Smx205022 nge_error(ngep, "ddi_intr_get_supported_types failed\n"); 28535574Smx205022 28545574Smx205022 return (DDI_FAILURE); 28555574Smx205022 } 28565574Smx205022 28575574Smx205022 NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x", 28585574Smx205022 intr_types)); 28595574Smx205022 28605574Smx205022 if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) { 28615574Smx205022 28625574Smx205022 /* MSI Configurations for mcp55 chipset */ 28635574Smx205022 if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 28645574Smx205022 ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 28655574Smx205022 28665574Smx205022 28675574Smx205022 /* Enable the 8 vectors */ 28685574Smx205022 msi_mask.msi_mask_val = 28695574Smx205022 nge_reg_get32(ngep, NGE_MSI_MASK); 28705574Smx205022 msi_mask.msi_msk_bits.vec0 = NGE_SET; 28715574Smx205022 msi_mask.msi_msk_bits.vec1 = NGE_SET; 28725574Smx205022 msi_mask.msi_msk_bits.vec2 = NGE_SET; 28735574Smx205022 msi_mask.msi_msk_bits.vec3 = NGE_SET; 28745574Smx205022 msi_mask.msi_msk_bits.vec4 = NGE_SET; 28755574Smx205022 msi_mask.msi_msk_bits.vec5 = NGE_SET; 28765574Smx205022 msi_mask.msi_msk_bits.vec6 = NGE_SET; 28775574Smx205022 msi_mask.msi_msk_bits.vec7 = NGE_SET; 28785574Smx205022 nge_reg_put32(ngep, NGE_MSI_MASK, 28795574Smx205022 msi_mask.msi_mask_val); 28805574Smx205022 28815574Smx205022 /* 28825574Smx205022 * Remapping the MSI MAP0 and MAP1. MCP55 28835574Smx205022 * is default mapping all the interrupt to 0 vector. 28845574Smx205022 * Software needs to remapping this. 28855574Smx205022 * This mapping is same as CK804. 28865574Smx205022 */ 28875574Smx205022 map0_vec.msi_map0_val = 28885574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP0); 28895574Smx205022 map1_vec.msi_map1_val = 28905574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP1); 28915574Smx205022 map0_vec.vecs_bits.reint_vec = 0; 28925574Smx205022 map0_vec.vecs_bits.rcint_vec = 0; 28935574Smx205022 map0_vec.vecs_bits.miss_vec = 3; 28945574Smx205022 map0_vec.vecs_bits.teint_vec = 5; 28955574Smx205022 map0_vec.vecs_bits.tcint_vec = 5; 28965574Smx205022 map0_vec.vecs_bits.stint_vec = 2; 28975574Smx205022 map0_vec.vecs_bits.mint_vec = 6; 28985574Smx205022 map0_vec.vecs_bits.rfint_vec = 0; 28995574Smx205022 map1_vec.vecs_bits.tfint_vec = 5; 29005574Smx205022 map1_vec.vecs_bits.feint_vec = 6; 29015574Smx205022 map1_vec.vecs_bits.resv8_11 = 3; 29025574Smx205022 map1_vec.vecs_bits.resv12_15 = 1; 29035574Smx205022 map1_vec.vecs_bits.resv16_19 = 0; 29045574Smx205022 map1_vec.vecs_bits.resv20_23 = 7; 29055574Smx205022 map1_vec.vecs_bits.resv24_31 = 0xff; 29065574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP0, 29075574Smx205022 map0_vec.msi_map0_val); 29085574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP1, 29095574Smx205022 map1_vec.msi_map1_val); 29105574Smx205022 } 29115574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 29125574Smx205022 NGE_DEBUG(("MSI registration failed, " 29135574Smx205022 "trying FIXED interrupt type\n")); 29145574Smx205022 } else { 29155574Smx205022 nge_log(ngep, "Using MSI interrupt type\n"); 29165574Smx205022 29175574Smx205022 ngep->intr_type = DDI_INTR_TYPE_MSI; 29185574Smx205022 ngep->progress |= PROGRESS_SWINT; 29195574Smx205022 } 29205574Smx205022 } 29215574Smx205022 29225574Smx205022 if (!(ngep->progress & PROGRESS_SWINT) && 29235574Smx205022 (intr_types & DDI_INTR_TYPE_FIXED)) { 29245574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 29255574Smx205022 nge_error(ngep, "FIXED interrupt " 29265574Smx205022 "registration failed\n"); 29275574Smx205022 29285574Smx205022 return (DDI_FAILURE); 29295574Smx205022 } 29305574Smx205022 29315574Smx205022 nge_log(ngep, "Using FIXED interrupt type\n"); 29325574Smx205022 29335574Smx205022 ngep->intr_type = DDI_INTR_TYPE_FIXED; 29345574Smx205022 ngep->progress |= PROGRESS_SWINT; 29355574Smx205022 } 29365574Smx205022 29375574Smx205022 29385574Smx205022 if (!(ngep->progress & PROGRESS_SWINT)) { 29395574Smx205022 nge_error(ngep, "No interrupts registered\n"); 29405574Smx205022 29415574Smx205022 return (DDI_FAILURE); 29425574Smx205022 } 29435574Smx205022 mutex_init(ngep->genlock, NULL, MUTEX_DRIVER, 29445574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 29455574Smx205022 mutex_init(ngep->softlock, NULL, MUTEX_DRIVER, 29465574Smx205022 DDI_INTR_PRI(ngep->soft_pri)); 29475574Smx205022 rw_init(ngep->rwlock, NULL, RW_DRIVER, 29485574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 29495574Smx205022 29505574Smx205022 return (DDI_SUCCESS); 29515574Smx205022 } 29525574Smx205022 29535574Smx205022 /* 29545574Smx205022 * nge_add_intrs: 29555574Smx205022 * 29565574Smx205022 * Register FIXED or MSI interrupts. 29575574Smx205022 */ 29585574Smx205022 static int 29595574Smx205022 nge_add_intrs(nge_t *ngep, int intr_type) 29605574Smx205022 { 29615574Smx205022 dev_info_t *dip = ngep->devinfo; 29625574Smx205022 int avail, actual, intr_size, count = 0; 29635574Smx205022 int i, flag, ret; 29645574Smx205022 29655574Smx205022 NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type)); 29665574Smx205022 29675574Smx205022 /* Get number of interrupts */ 29685574Smx205022 ret = ddi_intr_get_nintrs(dip, intr_type, &count); 29695574Smx205022 if ((ret != DDI_SUCCESS) || (count == 0)) { 29705574Smx205022 nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, " 29715574Smx205022 "count: %d", ret, count); 29725574Smx205022 29735574Smx205022 return (DDI_FAILURE); 29745574Smx205022 } 29755574Smx205022 29765574Smx205022 /* Get number of available interrupts */ 29775574Smx205022 ret = ddi_intr_get_navail(dip, intr_type, &avail); 29785574Smx205022 if ((ret != DDI_SUCCESS) || (avail == 0)) { 29795574Smx205022 nge_error(ngep, "ddi_intr_get_navail() failure, " 29805574Smx205022 "ret: %d, avail: %d\n", ret, avail); 29815574Smx205022 29825574Smx205022 return (DDI_FAILURE); 29835574Smx205022 } 29845574Smx205022 29855574Smx205022 if (avail < count) { 29865574Smx205022 NGE_DEBUG(("nitrs() returned %d, navail returned %d\n", 29875574Smx205022 count, avail)); 29885574Smx205022 } 29895574Smx205022 flag = DDI_INTR_ALLOC_NORMAL; 29905574Smx205022 29915574Smx205022 /* Allocate an array of interrupt handles */ 29925574Smx205022 intr_size = count * sizeof (ddi_intr_handle_t); 29935574Smx205022 ngep->htable = kmem_alloc(intr_size, KM_SLEEP); 29945574Smx205022 29955574Smx205022 /* Call ddi_intr_alloc() */ 29965574Smx205022 ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0, 29975574Smx205022 count, &actual, flag); 29985574Smx205022 29995574Smx205022 if ((ret != DDI_SUCCESS) || (actual == 0)) { 30005574Smx205022 nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret); 30015574Smx205022 30025574Smx205022 kmem_free(ngep->htable, intr_size); 30035574Smx205022 return (DDI_FAILURE); 30045574Smx205022 } 30055574Smx205022 30065574Smx205022 if (actual < count) { 30075574Smx205022 NGE_DEBUG(("Requested: %d, Received: %d\n", 30085574Smx205022 count, actual)); 30095574Smx205022 } 30105574Smx205022 30115574Smx205022 ngep->intr_actual_cnt = actual; 30125574Smx205022 ngep->intr_req_cnt = count; 30135574Smx205022 30145574Smx205022 /* 30155574Smx205022 * Get priority for first msi, assume remaining are all the same 30165574Smx205022 */ 30175574Smx205022 if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) != 30185574Smx205022 DDI_SUCCESS) { 30195574Smx205022 nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret); 30205574Smx205022 30215574Smx205022 /* Free already allocated intr */ 30225574Smx205022 for (i = 0; i < actual; i++) { 30235574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30245574Smx205022 } 30255574Smx205022 30265574Smx205022 kmem_free(ngep->htable, intr_size); 30275574Smx205022 30285574Smx205022 return (DDI_FAILURE); 30295574Smx205022 } 30305574Smx205022 /* Test for high level mutex */ 30315574Smx205022 if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) { 30325574Smx205022 nge_error(ngep, "nge_add_intrs:" 30335574Smx205022 "Hi level interrupt not supported"); 30345574Smx205022 30355574Smx205022 for (i = 0; i < actual; i++) 30365574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30375574Smx205022 30385574Smx205022 kmem_free(ngep->htable, intr_size); 30395574Smx205022 30405574Smx205022 return (DDI_FAILURE); 30415574Smx205022 } 30425574Smx205022 30435574Smx205022 30445574Smx205022 /* Call ddi_intr_add_handler() */ 30455574Smx205022 for (i = 0; i < actual; i++) { 30465574Smx205022 if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr, 30475574Smx205022 (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 30485574Smx205022 nge_error(ngep, "ddi_intr_add_handler() " 30495574Smx205022 "failed %d\n", ret); 30505574Smx205022 30515574Smx205022 /* Free already allocated intr */ 30525574Smx205022 for (i = 0; i < actual; i++) { 30535574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30545574Smx205022 } 30555574Smx205022 30565574Smx205022 kmem_free(ngep->htable, intr_size); 30575574Smx205022 30585574Smx205022 return (DDI_FAILURE); 30595574Smx205022 } 30605574Smx205022 } 30615574Smx205022 30625574Smx205022 if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap)) 30635574Smx205022 != DDI_SUCCESS) { 30645574Smx205022 nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret); 30655574Smx205022 30665574Smx205022 for (i = 0; i < actual; i++) { 30675574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 30685574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30695574Smx205022 } 30705574Smx205022 30715574Smx205022 kmem_free(ngep->htable, intr_size); 30725574Smx205022 30735574Smx205022 return (DDI_FAILURE); 30745574Smx205022 } 30755574Smx205022 30765574Smx205022 return (DDI_SUCCESS); 30775574Smx205022 } 30785574Smx205022 30795574Smx205022 /* 30805574Smx205022 * nge_rem_intrs: 30815574Smx205022 * 30825574Smx205022 * Unregister FIXED or MSI interrupts 30835574Smx205022 */ 30845574Smx205022 static void 30855574Smx205022 nge_rem_intrs(nge_t *ngep) 30865574Smx205022 { 30875574Smx205022 int i; 30885574Smx205022 30895574Smx205022 NGE_DEBUG(("nge_rem_intrs\n")); 30905574Smx205022 30915574Smx205022 /* Disable all interrupts */ 30925574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 30935574Smx205022 /* Call ddi_intr_block_disable() */ 30945574Smx205022 (void) ddi_intr_block_disable(ngep->htable, 30955574Smx205022 ngep->intr_actual_cnt); 30965574Smx205022 } else { 30975574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 30985574Smx205022 (void) ddi_intr_disable(ngep->htable[i]); 30995574Smx205022 } 31005574Smx205022 } 31015574Smx205022 31025574Smx205022 /* Call ddi_intr_remove_handler() */ 31035574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 31045574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 31055574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 31065574Smx205022 } 31075574Smx205022 31085574Smx205022 kmem_free(ngep->htable, 31095574Smx205022 ngep->intr_req_cnt * sizeof (ddi_intr_handle_t)); 31105574Smx205022 } 3111