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"; 1685574Smx205022 extern kmutex_t nge_log_mutex[1]; 1695574Smx205022 1705574Smx205022 static int nge_m_start(void *); 1715574Smx205022 static void nge_m_stop(void *); 1725574Smx205022 static int nge_m_promisc(void *, boolean_t); 1735574Smx205022 static int nge_m_multicst(void *, boolean_t, const uint8_t *); 1745574Smx205022 static int nge_m_unicst(void *, const uint8_t *); 1755574Smx205022 static void nge_m_ioctl(void *, queue_t *, mblk_t *); 1765574Smx205022 static boolean_t nge_m_getcapab(void *, mac_capab_t, void *); 1776200Smx205022 static int nge_m_setprop(void *, const char *, mac_prop_id_t, 1786200Smx205022 uint_t, const void *); 1796200Smx205022 static int nge_m_getprop(void *, const char *, mac_prop_id_t, 1808118SVasumathi.Sundaram@Sun.COM uint_t, uint_t, void *, uint_t *); 1816200Smx205022 static int nge_set_priv_prop(nge_t *, const char *, uint_t, 1826200Smx205022 const void *); 1836200Smx205022 static int nge_get_priv_prop(nge_t *, const char *, uint_t, 1846512Ssowmini uint_t, void *); 1856200Smx205022 1866200Smx205022 #define NGE_M_CALLBACK_FLAGS\ 1876200Smx205022 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 1885574Smx205022 1895574Smx205022 static mac_callbacks_t nge_m_callbacks = { 1905574Smx205022 NGE_M_CALLBACK_FLAGS, 1915574Smx205022 nge_m_stat, 1925574Smx205022 nge_m_start, 1935574Smx205022 nge_m_stop, 1945574Smx205022 nge_m_promisc, 1955574Smx205022 nge_m_multicst, 1965574Smx205022 nge_m_unicst, 1975574Smx205022 nge_m_tx, 1985574Smx205022 nge_m_ioctl, 1996200Smx205022 nge_m_getcapab, 2006200Smx205022 NULL, 2016200Smx205022 NULL, 2026200Smx205022 nge_m_setprop, 2036200Smx205022 nge_m_getprop 2045574Smx205022 }; 2055574Smx205022 2066512Ssowmini mac_priv_prop_t nge_priv_props[] = { 2076512Ssowmini {"_tx_bcopy_threshold", MAC_PROP_PERM_RW}, 2086512Ssowmini {"_rx_bcopy_threshold", MAC_PROP_PERM_RW}, 2096512Ssowmini {"_recv_max_packet", MAC_PROP_PERM_RW}, 2106512Ssowmini {"_poll_quiet_time", MAC_PROP_PERM_RW}, 2116512Ssowmini {"_poll_busy_time", MAC_PROP_PERM_RW}, 2126512Ssowmini {"_rx_intr_hwater", MAC_PROP_PERM_RW}, 2136512Ssowmini {"_rx_intr_lwater", MAC_PROP_PERM_RW}, 2146512Ssowmini }; 2156512Ssowmini 2166512Ssowmini #define NGE_MAX_PRIV_PROPS \ 2176512Ssowmini (sizeof (nge_priv_props)/sizeof (mac_priv_prop_t)) 2186512Ssowmini 2195574Smx205022 static int nge_add_intrs(nge_t *, int); 2205574Smx205022 static void nge_rem_intrs(nge_t *); 2215574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *); 2225574Smx205022 2235574Smx205022 /* 2245574Smx205022 * NGE MSI tunable: 2255574Smx205022 */ 2265574Smx205022 boolean_t nge_enable_msi = B_FALSE; 2275574Smx205022 2285574Smx205022 static enum ioc_reply 2295574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode) 2305574Smx205022 { 2315574Smx205022 /* 2325574Smx205022 * If the mode isn't being changed, there's nothing to do ... 2335574Smx205022 */ 2345574Smx205022 if (mode == ngep->param_loop_mode) 2355574Smx205022 return (IOC_ACK); 2365574Smx205022 2375574Smx205022 /* 2385574Smx205022 * Validate the requested mode and prepare a suitable message 2395574Smx205022 * to explain the link down/up cycle that the change will 2405574Smx205022 * probably induce ... 2415574Smx205022 */ 2425574Smx205022 switch (mode) { 2435574Smx205022 default: 2445574Smx205022 return (IOC_INVAL); 2455574Smx205022 2465574Smx205022 case NGE_LOOP_NONE: 2475574Smx205022 case NGE_LOOP_EXTERNAL_100: 2485574Smx205022 case NGE_LOOP_EXTERNAL_10: 2495574Smx205022 case NGE_LOOP_INTERNAL_PHY: 2505574Smx205022 break; 2515574Smx205022 } 2525574Smx205022 2535574Smx205022 /* 2545574Smx205022 * All OK; tell the caller to reprogram 2555574Smx205022 * the PHY and/or MAC for the new mode ... 2565574Smx205022 */ 2575574Smx205022 ngep->param_loop_mode = mode; 2585574Smx205022 return (IOC_RESTART_ACK); 2595574Smx205022 } 2605574Smx205022 2615574Smx205022 #undef NGE_DBG 2625574Smx205022 #define NGE_DBG NGE_DBG_INIT 2635574Smx205022 2645574Smx205022 /* 2655574Smx205022 * Utility routine to carve a slice off a chunk of allocated memory, 2665574Smx205022 * updating the chunk descriptor accordingly. The size of the slice 2675574Smx205022 * is given by the product of the <qty> and <size> parameters. 2685574Smx205022 */ 2695574Smx205022 void 2705574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 2715574Smx205022 uint32_t qty, uint32_t size) 2725574Smx205022 { 2735574Smx205022 size_t totsize; 2745574Smx205022 2755574Smx205022 totsize = qty*size; 2765574Smx205022 ASSERT(size > 0); 2775574Smx205022 ASSERT(totsize <= chunk->alength); 2785574Smx205022 2795574Smx205022 *slice = *chunk; 2805574Smx205022 slice->nslots = qty; 2815574Smx205022 slice->size = size; 2825574Smx205022 slice->alength = totsize; 2835574Smx205022 2845574Smx205022 chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 2855574Smx205022 chunk->alength -= totsize; 2865574Smx205022 chunk->offset += totsize; 2875574Smx205022 chunk->cookie.dmac_laddress += totsize; 2885574Smx205022 chunk->cookie.dmac_size -= totsize; 2895574Smx205022 } 2905574Smx205022 2915574Smx205022 /* 2925574Smx205022 * Allocate an area of memory and a DMA handle for accessing it 2935574Smx205022 */ 2945574Smx205022 int 2955574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p, 2965574Smx205022 uint_t dma_flags, dma_area_t *dma_p) 2975574Smx205022 { 2985574Smx205022 int err; 2995574Smx205022 caddr_t va; 3005574Smx205022 3015574Smx205022 NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 3025574Smx205022 (void *)ngep, memsize, attr_p, dma_flags, dma_p)); 3035574Smx205022 /* 3045574Smx205022 * Allocate handle 3055574Smx205022 */ 3065574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr, 3075574Smx205022 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 3085574Smx205022 if (err != DDI_SUCCESS) 3095574Smx205022 goto fail; 3105574Smx205022 3115574Smx205022 /* 3125574Smx205022 * Allocate memory 3135574Smx205022 */ 3145574Smx205022 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 3155574Smx205022 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 3165574Smx205022 DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl); 3175574Smx205022 if (err != DDI_SUCCESS) 3185574Smx205022 goto fail; 3195574Smx205022 3205574Smx205022 /* 3215574Smx205022 * Bind the two together 3225574Smx205022 */ 3235574Smx205022 dma_p->mem_va = va; 3245574Smx205022 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 3255574Smx205022 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 3265574Smx205022 &dma_p->cookie, &dma_p->ncookies); 3275574Smx205022 3285574Smx205022 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 3295574Smx205022 goto fail; 3305574Smx205022 3315574Smx205022 dma_p->nslots = ~0U; 3325574Smx205022 dma_p->size = ~0U; 3335574Smx205022 dma_p->offset = 0; 3345574Smx205022 3355574Smx205022 return (DDI_SUCCESS); 3365574Smx205022 3375574Smx205022 fail: 3385574Smx205022 nge_free_dma_mem(dma_p); 3395574Smx205022 NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!")); 3405574Smx205022 3415574Smx205022 return (DDI_FAILURE); 3425574Smx205022 } 3435574Smx205022 3445574Smx205022 /* 3455574Smx205022 * Free one allocated area of DMAable memory 3465574Smx205022 */ 3475574Smx205022 void 3485574Smx205022 nge_free_dma_mem(dma_area_t *dma_p) 3495574Smx205022 { 3505574Smx205022 if (dma_p->dma_hdl != NULL) { 3515574Smx205022 if (dma_p->ncookies) { 3525574Smx205022 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 3535574Smx205022 dma_p->ncookies = 0; 3545574Smx205022 } 3555574Smx205022 } 3565574Smx205022 if (dma_p->acc_hdl != NULL) { 3575574Smx205022 ddi_dma_mem_free(&dma_p->acc_hdl); 3585574Smx205022 dma_p->acc_hdl = NULL; 3595574Smx205022 } 3605574Smx205022 if (dma_p->dma_hdl != NULL) { 3615574Smx205022 ddi_dma_free_handle(&dma_p->dma_hdl); 3625574Smx205022 dma_p->dma_hdl = NULL; 3635574Smx205022 } 3645574Smx205022 } 3655574Smx205022 3665574Smx205022 #define ALLOC_TX_BUF 0x1 3675574Smx205022 #define ALLOC_TX_DESC 0x2 3685574Smx205022 #define ALLOC_RX_DESC 0x4 3695574Smx205022 3705574Smx205022 int 3715574Smx205022 nge_alloc_bufs(nge_t *ngep) 3725574Smx205022 { 3735574Smx205022 int err; 3745574Smx205022 int split; 3755574Smx205022 int progress; 3765574Smx205022 size_t txbuffsize; 3775574Smx205022 size_t rxdescsize; 3785574Smx205022 size_t txdescsize; 3795574Smx205022 3805574Smx205022 txbuffsize = ngep->tx_desc * ngep->buf_size; 3815574Smx205022 rxdescsize = ngep->rx_desc; 3825574Smx205022 txdescsize = ngep->tx_desc; 3835574Smx205022 rxdescsize *= ngep->desc_attr.rxd_size; 3845574Smx205022 txdescsize *= ngep->desc_attr.txd_size; 3855574Smx205022 progress = 0; 3865574Smx205022 3875574Smx205022 NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep)); 3885574Smx205022 /* 3895574Smx205022 * Allocate memory & handles for TX buffers 3905574Smx205022 */ 3915574Smx205022 ASSERT((txbuffsize % ngep->nge_split) == 0); 3925574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 3935574Smx205022 err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split, 3945574Smx205022 &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE, 3955574Smx205022 &ngep->send->buf[split]); 3965574Smx205022 if (err != DDI_SUCCESS) 3975574Smx205022 goto fail; 3985574Smx205022 } 3995574Smx205022 4005574Smx205022 progress |= ALLOC_TX_BUF; 4015574Smx205022 4025574Smx205022 /* 4035574Smx205022 * Allocate memory & handles for receive return rings and 4045574Smx205022 * buffer (producer) descriptor rings 4055574Smx205022 */ 4065574Smx205022 err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr, 4075574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc); 4085574Smx205022 if (err != DDI_SUCCESS) 4095574Smx205022 goto fail; 4105574Smx205022 progress |= ALLOC_RX_DESC; 4115574Smx205022 4125574Smx205022 /* 4135574Smx205022 * Allocate memory & handles for TX descriptor rings, 4145574Smx205022 */ 4155574Smx205022 err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr, 4165574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc); 4175574Smx205022 if (err != DDI_SUCCESS) 4185574Smx205022 goto fail; 4195574Smx205022 return (DDI_SUCCESS); 4205574Smx205022 4215574Smx205022 fail: 4225574Smx205022 if (progress & ALLOC_RX_DESC) 4235574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4245574Smx205022 if (progress & ALLOC_TX_BUF) { 4255574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4265574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4275574Smx205022 } 4285574Smx205022 4295574Smx205022 return (DDI_FAILURE); 4305574Smx205022 } 4315574Smx205022 4325574Smx205022 /* 4335574Smx205022 * This routine frees the transmit and receive buffers and descriptors. 4345574Smx205022 * Make sure the chip is stopped before calling it! 4355574Smx205022 */ 4365574Smx205022 void 4375574Smx205022 nge_free_bufs(nge_t *ngep) 4385574Smx205022 { 4395574Smx205022 int split; 4405574Smx205022 4415574Smx205022 NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep)); 4425574Smx205022 4435574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4445574Smx205022 nge_free_dma_mem(&ngep->send->desc); 4455574Smx205022 4465574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4475574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4485574Smx205022 } 4495574Smx205022 4505574Smx205022 /* 4515574Smx205022 * Clean up initialisation done above before the memory is freed 4525574Smx205022 */ 4535574Smx205022 static void 4545574Smx205022 nge_fini_send_ring(nge_t *ngep) 4555574Smx205022 { 4565574Smx205022 uint32_t slot; 4575574Smx205022 size_t dmah_num; 4585574Smx205022 send_ring_t *srp; 4595574Smx205022 sw_tx_sbd_t *ssbdp; 4605574Smx205022 4615574Smx205022 srp = ngep->send; 4625574Smx205022 ssbdp = srp->sw_sbds; 4635574Smx205022 4645574Smx205022 NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep)); 4655574Smx205022 4665574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 4675574Smx205022 4685574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 4695574Smx205022 if (srp->dmahndl[slot].hndl) { 4705574Smx205022 (void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl); 4715574Smx205022 ddi_dma_free_handle(&srp->dmahndl[slot].hndl); 4725574Smx205022 srp->dmahndl[slot].hndl = NULL; 4735574Smx205022 srp->dmahndl[slot].next = NULL; 4745574Smx205022 } 4755574Smx205022 } 4765574Smx205022 4775574Smx205022 srp->dmah_free.head = NULL; 4785574Smx205022 srp->dmah_free.tail = NULL; 4795574Smx205022 4805574Smx205022 kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp)); 4815574Smx205022 4825574Smx205022 } 4835574Smx205022 4845574Smx205022 /* 4855574Smx205022 * Initialise the specified Send Ring, using the information in the 4865574Smx205022 * <dma_area> descriptors that it contains to set up all the other 4875574Smx205022 * fields. This routine should be called only once for each ring. 4885574Smx205022 */ 4895574Smx205022 static int 4905574Smx205022 nge_init_send_ring(nge_t *ngep) 4915574Smx205022 { 4925574Smx205022 size_t dmah_num; 4935574Smx205022 uint32_t nslots; 4945574Smx205022 uint32_t err; 4955574Smx205022 uint32_t slot; 4965574Smx205022 uint32_t split; 4975574Smx205022 send_ring_t *srp; 4985574Smx205022 sw_tx_sbd_t *ssbdp; 4995574Smx205022 dma_area_t desc; 5005574Smx205022 dma_area_t pbuf; 5015574Smx205022 5025574Smx205022 srp = ngep->send; 5035574Smx205022 srp->desc.nslots = ngep->tx_desc; 5045574Smx205022 nslots = srp->desc.nslots; 5055574Smx205022 5065574Smx205022 NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep)); 5075574Smx205022 /* 5085574Smx205022 * Other one-off initialisation of per-ring data 5095574Smx205022 */ 5105574Smx205022 srp->ngep = ngep; 5115574Smx205022 5125574Smx205022 /* 5135574Smx205022 * Allocate the array of s/w Send Buffer Descriptors 5145574Smx205022 */ 5155574Smx205022 ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 5165574Smx205022 srp->sw_sbds = ssbdp; 5175574Smx205022 5185574Smx205022 /* 5195574Smx205022 * Now initialise each array element once and for all 5205574Smx205022 */ 5215574Smx205022 desc = srp->desc; 5225574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 5235574Smx205022 pbuf = srp->buf[split]; 5245574Smx205022 for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) { 5255574Smx205022 nge_slice_chunk(&ssbdp->desc, &desc, 1, 5265574Smx205022 ngep->desc_attr.txd_size); 5275574Smx205022 nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1, 5285574Smx205022 ngep->buf_size); 5295574Smx205022 } 5305574Smx205022 ASSERT(pbuf.alength == 0); 5315574Smx205022 } 5325574Smx205022 ASSERT(desc.alength == 0); 5335574Smx205022 5345574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5355574Smx205022 5365574Smx205022 /* preallocate dma handles for tx buffer */ 5375574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 5385574Smx205022 5395574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, 5405574Smx205022 ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT, 5415574Smx205022 NULL, &srp->dmahndl[slot].hndl); 5425574Smx205022 5435574Smx205022 if (err != DDI_SUCCESS) { 5445574Smx205022 nge_fini_send_ring(ngep); 5455574Smx205022 nge_error(ngep, 5465574Smx205022 "nge_init_send_ring: alloc dma handle fails"); 5475574Smx205022 return (DDI_FAILURE); 5485574Smx205022 } 5495574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5505574Smx205022 } 5515574Smx205022 5525574Smx205022 srp->dmah_free.head = srp->dmahndl; 5535574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5545574Smx205022 srp->dmah_free.tail->next = NULL; 5555574Smx205022 5565574Smx205022 return (DDI_SUCCESS); 5575574Smx205022 } 5585574Smx205022 5595574Smx205022 /* 5605574Smx205022 * Intialize the tx recycle pointer and tx sending pointer of tx ring 5615574Smx205022 * and set the type of tx's data descriptor by default. 5625574Smx205022 */ 5635574Smx205022 static void 5645574Smx205022 nge_reinit_send_ring(nge_t *ngep) 5655574Smx205022 { 5665574Smx205022 size_t dmah_num; 5675574Smx205022 uint32_t slot; 5685574Smx205022 send_ring_t *srp; 5695574Smx205022 sw_tx_sbd_t *ssbdp; 5705574Smx205022 5715574Smx205022 srp = ngep->send; 5725574Smx205022 5735574Smx205022 /* 5745574Smx205022 * Reinitialise control variables ... 5755574Smx205022 */ 5765574Smx205022 5775574Smx205022 srp->tx_hwmark = NGE_DESC_MIN; 5785574Smx205022 srp->tx_lwmark = NGE_DESC_MIN; 5795574Smx205022 5805574Smx205022 srp->tx_next = 0; 5815574Smx205022 srp->tx_free = srp->desc.nslots; 5825574Smx205022 srp->tc_next = 0; 5835574Smx205022 5845574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5855574Smx205022 5865574Smx205022 for (slot = 0; slot - dmah_num != 0; ++slot) 5875574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5885574Smx205022 5895574Smx205022 srp->dmah_free.head = srp->dmahndl; 5905574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5915574Smx205022 srp->dmah_free.tail->next = NULL; 5925574Smx205022 5935574Smx205022 /* 5945574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 5955574Smx205022 */ 5965574Smx205022 for (slot = 0; slot < srp->desc.nslots; ++slot) { 5975574Smx205022 ssbdp = &srp->sw_sbds[slot]; 5985574Smx205022 ssbdp->flags = HOST_OWN; 5995574Smx205022 } 6005574Smx205022 6015574Smx205022 DMA_ZERO(srp->desc); 6025574Smx205022 DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 6035574Smx205022 } 6045574Smx205022 6055574Smx205022 /* 6065574Smx205022 * Initialize the slot number of rx's ring 6075574Smx205022 */ 6085574Smx205022 static void 6095574Smx205022 nge_init_recv_ring(nge_t *ngep) 6105574Smx205022 { 6115574Smx205022 recv_ring_t *rrp; 6125574Smx205022 6135574Smx205022 rrp = ngep->recv; 6145574Smx205022 rrp->desc.nslots = ngep->rx_desc; 6155574Smx205022 rrp->ngep = ngep; 6165574Smx205022 } 6175574Smx205022 6185574Smx205022 /* 6195574Smx205022 * Intialize the rx recycle pointer and rx sending pointer of rx ring 6205574Smx205022 */ 6215574Smx205022 static void 6225574Smx205022 nge_reinit_recv_ring(nge_t *ngep) 6235574Smx205022 { 6245574Smx205022 recv_ring_t *rrp; 6255574Smx205022 6265574Smx205022 rrp = ngep->recv; 6275574Smx205022 6285574Smx205022 /* 6295574Smx205022 * Reinitialise control variables ... 6305574Smx205022 */ 6315574Smx205022 rrp->prod_index = 0; 6325574Smx205022 /* 6335574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 6345574Smx205022 */ 6355574Smx205022 DMA_ZERO(rrp->desc); 6365574Smx205022 DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV); 6375574Smx205022 } 6385574Smx205022 6395574Smx205022 /* 6405574Smx205022 * Clean up initialisation done above before the memory is freed 6415574Smx205022 */ 6425574Smx205022 static void 6435574Smx205022 nge_fini_buff_ring(nge_t *ngep) 6445574Smx205022 { 6455574Smx205022 uint32_t i; 6465574Smx205022 buff_ring_t *brp; 6475574Smx205022 dma_area_t *bufp; 6485574Smx205022 sw_rx_sbd_t *bsbdp; 6495574Smx205022 6505574Smx205022 brp = ngep->buff; 6515574Smx205022 bsbdp = brp->sw_rbds; 6525574Smx205022 6535574Smx205022 NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep)); 6545574Smx205022 6555574Smx205022 mutex_enter(brp->recycle_lock); 6565574Smx205022 brp->buf_sign++; 6575574Smx205022 mutex_exit(brp->recycle_lock); 6585574Smx205022 for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) { 6595574Smx205022 if (bsbdp->bufp) { 6605574Smx205022 if (bsbdp->bufp->mp) 6615574Smx205022 freemsg(bsbdp->bufp->mp); 6625574Smx205022 nge_free_dma_mem(bsbdp->bufp); 6635574Smx205022 kmem_free(bsbdp->bufp, sizeof (dma_area_t)); 6645574Smx205022 bsbdp->bufp = NULL; 6655574Smx205022 } 6665574Smx205022 } 6675574Smx205022 while (brp->free_list != NULL) { 6685574Smx205022 bufp = brp->free_list; 6695574Smx205022 brp->free_list = bufp->next; 6705574Smx205022 bufp->next = NULL; 6715574Smx205022 if (bufp->mp) 6725574Smx205022 freemsg(bufp->mp); 6735574Smx205022 nge_free_dma_mem(bufp); 6745574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6755574Smx205022 } 6765574Smx205022 while (brp->recycle_list != NULL) { 6775574Smx205022 bufp = brp->recycle_list; 6785574Smx205022 brp->recycle_list = bufp->next; 6795574Smx205022 bufp->next = NULL; 6805574Smx205022 if (bufp->mp) 6815574Smx205022 freemsg(bufp->mp); 6825574Smx205022 nge_free_dma_mem(bufp); 6835574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6845574Smx205022 } 6855574Smx205022 6865574Smx205022 6875574Smx205022 kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp))); 6885574Smx205022 brp->sw_rbds = NULL; 6895574Smx205022 } 6905574Smx205022 6915574Smx205022 /* 6925574Smx205022 * Intialize the Rx's data ring and free ring 6935574Smx205022 */ 6945574Smx205022 static int 6955574Smx205022 nge_init_buff_ring(nge_t *ngep) 6965574Smx205022 { 6975574Smx205022 uint32_t err; 6985574Smx205022 uint32_t slot; 6995574Smx205022 uint32_t nslots_buff; 7005574Smx205022 uint32_t nslots_recv; 7015574Smx205022 buff_ring_t *brp; 7025574Smx205022 recv_ring_t *rrp; 7035574Smx205022 dma_area_t desc; 7045574Smx205022 dma_area_t *bufp; 7055574Smx205022 sw_rx_sbd_t *bsbdp; 7065574Smx205022 7075574Smx205022 rrp = ngep->recv; 7085574Smx205022 brp = ngep->buff; 7095574Smx205022 brp->nslots = ngep->rx_buf; 7105574Smx205022 brp->rx_bcopy = B_FALSE; 7115574Smx205022 nslots_recv = rrp->desc.nslots; 7125574Smx205022 nslots_buff = brp->nslots; 7135574Smx205022 brp->ngep = ngep; 7145574Smx205022 7155574Smx205022 NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep)); 7165574Smx205022 7175574Smx205022 /* 7185574Smx205022 * Allocate the array of s/w Recv Buffer Descriptors 7195574Smx205022 */ 7205574Smx205022 bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP); 7215574Smx205022 brp->sw_rbds = bsbdp; 7225574Smx205022 brp->free_list = NULL; 7235574Smx205022 brp->recycle_list = NULL; 7245574Smx205022 for (slot = 0; slot < nslots_buff; ++slot) { 7255574Smx205022 bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP); 7265574Smx205022 err = nge_alloc_dma_mem(ngep, (ngep->buf_size 7275574Smx205022 + NGE_HEADROOM), 7285574Smx205022 &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp); 7295574Smx205022 if (err != DDI_SUCCESS) { 7305574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 7315574Smx205022 return (DDI_FAILURE); 7325574Smx205022 } 7335574Smx205022 7345574Smx205022 bufp->alength -= NGE_HEADROOM; 7355574Smx205022 bufp->offset += NGE_HEADROOM; 7365574Smx205022 bufp->private = (caddr_t)ngep; 7375574Smx205022 bufp->rx_recycle.free_func = nge_recv_recycle; 7385574Smx205022 bufp->rx_recycle.free_arg = (caddr_t)bufp; 7395574Smx205022 bufp->signature = brp->buf_sign; 7405574Smx205022 bufp->rx_delivered = B_FALSE; 7415574Smx205022 bufp->mp = desballoc(DMA_VPTR(*bufp), 7425574Smx205022 ngep->buf_size + NGE_HEADROOM, 7435574Smx205022 0, &bufp->rx_recycle); 7445574Smx205022 7455574Smx205022 if (bufp->mp == NULL) { 7465574Smx205022 return (DDI_FAILURE); 7475574Smx205022 } 7485574Smx205022 bufp->next = brp->free_list; 7495574Smx205022 brp->free_list = bufp; 7505574Smx205022 } 7515574Smx205022 7525574Smx205022 /* 7535574Smx205022 * Now initialise each array element once and for all 7545574Smx205022 */ 7555574Smx205022 desc = rrp->desc; 7565574Smx205022 for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) { 7575574Smx205022 nge_slice_chunk(&bsbdp->desc, &desc, 1, 7585574Smx205022 ngep->desc_attr.rxd_size); 7595574Smx205022 bufp = brp->free_list; 7605574Smx205022 brp->free_list = bufp->next; 7615574Smx205022 bsbdp->bufp = bufp; 7625574Smx205022 bsbdp->flags = CONTROLER_OWN; 7635574Smx205022 bufp->next = NULL; 7645574Smx205022 } 7655574Smx205022 7665574Smx205022 ASSERT(desc.alength == 0); 7675574Smx205022 return (DDI_SUCCESS); 7685574Smx205022 } 7695574Smx205022 7705574Smx205022 /* 7715574Smx205022 * Fill the host address of data in rx' descriptor 7725574Smx205022 * and initialize free pointers of rx free ring 7735574Smx205022 */ 7745574Smx205022 static int 7755574Smx205022 nge_reinit_buff_ring(nge_t *ngep) 7765574Smx205022 { 7775574Smx205022 uint32_t slot; 7785574Smx205022 uint32_t nslots_recv; 7795574Smx205022 buff_ring_t *brp; 7805574Smx205022 recv_ring_t *rrp; 7815574Smx205022 sw_rx_sbd_t *bsbdp; 7825574Smx205022 void *hw_bd_p; 7835574Smx205022 7845574Smx205022 brp = ngep->buff; 7855574Smx205022 rrp = ngep->recv; 7865574Smx205022 bsbdp = brp->sw_rbds; 7875574Smx205022 nslots_recv = rrp->desc.nslots; 7885574Smx205022 for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) { 7895574Smx205022 hw_bd_p = DMA_VPTR(bsbdp->desc); 7905574Smx205022 /* 7915574Smx205022 * There is a scenario: When the traffic of small tcp 7925574Smx205022 * packet is heavy, suspending the tcp traffic will 7935574Smx205022 * cause the preallocated buffers for rx not to be 7945574Smx205022 * released in time by tcp taffic and cause rx's buffer 7955574Smx205022 * pointers not to be refilled in time. 7965574Smx205022 * 7975574Smx205022 * At this point, if we reinitialize the driver, the bufp 7985574Smx205022 * pointer for rx's traffic will be NULL. 7995574Smx205022 * So the result of the reinitializion fails. 8005574Smx205022 */ 8015574Smx205022 if (bsbdp->bufp == NULL) 8025574Smx205022 return (DDI_FAILURE); 8035574Smx205022 8045574Smx205022 ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie, 8055574Smx205022 bsbdp->bufp->alength); 8065574Smx205022 } 8075574Smx205022 return (DDI_SUCCESS); 8085574Smx205022 } 8095574Smx205022 8105574Smx205022 static void 8115574Smx205022 nge_init_ring_param_lock(nge_t *ngep) 8125574Smx205022 { 8135574Smx205022 buff_ring_t *brp; 8145574Smx205022 send_ring_t *srp; 8155574Smx205022 8165574Smx205022 srp = ngep->send; 8175574Smx205022 brp = ngep->buff; 8185574Smx205022 8195574Smx205022 /* Init the locks for send ring */ 8205574Smx205022 mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 8215574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8225574Smx205022 mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 8235574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8245574Smx205022 mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER, 8255574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8265574Smx205022 8275574Smx205022 /* Init parameters of buffer ring */ 8285574Smx205022 brp->free_list = NULL; 8295574Smx205022 brp->recycle_list = NULL; 8305574Smx205022 brp->rx_hold = 0; 8315574Smx205022 brp->buf_sign = 0; 8325574Smx205022 8335574Smx205022 /* Init recycle list lock */ 8345574Smx205022 mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER, 8355574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8365574Smx205022 } 8375574Smx205022 8385574Smx205022 int 8395574Smx205022 nge_init_rings(nge_t *ngep) 8405574Smx205022 { 8415574Smx205022 uint32_t err; 8425574Smx205022 8435574Smx205022 err = nge_init_send_ring(ngep); 8445574Smx205022 if (err != DDI_SUCCESS) { 8455574Smx205022 return (err); 8465574Smx205022 } 8475574Smx205022 nge_init_recv_ring(ngep); 8485574Smx205022 8495574Smx205022 err = nge_init_buff_ring(ngep); 8505574Smx205022 if (err != DDI_SUCCESS) { 8515574Smx205022 nge_fini_send_ring(ngep); 8525574Smx205022 return (DDI_FAILURE); 8535574Smx205022 } 8545574Smx205022 8555574Smx205022 return (err); 8565574Smx205022 } 8575574Smx205022 8585574Smx205022 static int 8595574Smx205022 nge_reinit_ring(nge_t *ngep) 8605574Smx205022 { 8615574Smx205022 int err; 8625574Smx205022 8635574Smx205022 nge_reinit_recv_ring(ngep); 8645574Smx205022 nge_reinit_send_ring(ngep); 8655574Smx205022 err = nge_reinit_buff_ring(ngep); 8665574Smx205022 return (err); 8675574Smx205022 } 8685574Smx205022 8695574Smx205022 8705574Smx205022 void 8715574Smx205022 nge_fini_rings(nge_t *ngep) 8725574Smx205022 { 8735574Smx205022 /* 8745574Smx205022 * For receive ring, nothing need to be finished. 8755574Smx205022 * So only finish buffer ring and send ring here. 8765574Smx205022 */ 8775574Smx205022 nge_fini_buff_ring(ngep); 8785574Smx205022 nge_fini_send_ring(ngep); 8795574Smx205022 } 8805574Smx205022 8815574Smx205022 /* 8825574Smx205022 * Loopback ioctl code 8835574Smx205022 */ 8845574Smx205022 8855574Smx205022 static lb_property_t loopmodes[] = { 8865574Smx205022 { normal, "normal", NGE_LOOP_NONE }, 8875574Smx205022 { external, "100Mbps", NGE_LOOP_EXTERNAL_100 }, 8885574Smx205022 { external, "10Mbps", NGE_LOOP_EXTERNAL_10 }, 8895574Smx205022 { internal, "PHY", NGE_LOOP_INTERNAL_PHY }, 8905574Smx205022 }; 8915574Smx205022 8925574Smx205022 enum ioc_reply 8935574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp) 8945574Smx205022 { 8955574Smx205022 int cmd; 8965574Smx205022 uint32_t *lbmp; 8975574Smx205022 lb_info_sz_t *lbsp; 8985574Smx205022 lb_property_t *lbpp; 8995574Smx205022 9005574Smx205022 /* 9015574Smx205022 * Validate format of ioctl 9025574Smx205022 */ 9035574Smx205022 if (mp->b_cont == NULL) 9045574Smx205022 return (IOC_INVAL); 9055574Smx205022 9065574Smx205022 cmd = iocp->ioc_cmd; 9075574Smx205022 9085574Smx205022 switch (cmd) { 9095574Smx205022 default: 9105574Smx205022 return (IOC_INVAL); 9115574Smx205022 9125574Smx205022 case LB_GET_INFO_SIZE: 9135574Smx205022 if (iocp->ioc_count != sizeof (lb_info_sz_t)) 9145574Smx205022 return (IOC_INVAL); 9155574Smx205022 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 9165574Smx205022 *lbsp = sizeof (loopmodes); 9175574Smx205022 return (IOC_REPLY); 9185574Smx205022 9195574Smx205022 case LB_GET_INFO: 9205574Smx205022 if (iocp->ioc_count != sizeof (loopmodes)) 9215574Smx205022 return (IOC_INVAL); 9225574Smx205022 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 9235574Smx205022 bcopy(loopmodes, lbpp, sizeof (loopmodes)); 9245574Smx205022 return (IOC_REPLY); 9255574Smx205022 9265574Smx205022 case LB_GET_MODE: 9275574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9285574Smx205022 return (IOC_INVAL); 9295574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9305574Smx205022 *lbmp = ngep->param_loop_mode; 9315574Smx205022 return (IOC_REPLY); 9325574Smx205022 9335574Smx205022 case LB_SET_MODE: 9345574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9355574Smx205022 return (IOC_INVAL); 9365574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9375574Smx205022 return (nge_set_loop_mode(ngep, *lbmp)); 9385574Smx205022 } 9395574Smx205022 } 9405574Smx205022 9415574Smx205022 #undef NGE_DBG 9425574Smx205022 #define NGE_DBG NGE_DBG_NEMO 9435574Smx205022 9445574Smx205022 9455574Smx205022 static void 9465574Smx205022 nge_check_desc_prop(nge_t *ngep) 9475574Smx205022 { 9485574Smx205022 if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD) 9495574Smx205022 ngep->desc_mode = DESC_HOT; 9505574Smx205022 9515574Smx205022 if (ngep->desc_mode == DESC_OFFLOAD) { 9525574Smx205022 9535574Smx205022 ngep->desc_attr = nge_sum_desc; 9545574Smx205022 9555574Smx205022 } else if (ngep->desc_mode == DESC_HOT) { 9565574Smx205022 9575574Smx205022 ngep->desc_attr = nge_hot_desc; 9585574Smx205022 } 9595574Smx205022 } 9605574Smx205022 9615574Smx205022 /* 9625574Smx205022 * nge_get_props -- get the parameters to tune the driver 9635574Smx205022 */ 9645574Smx205022 static void 9655574Smx205022 nge_get_props(nge_t *ngep) 9665574Smx205022 { 9675574Smx205022 chip_info_t *infop; 9685574Smx205022 dev_info_t *devinfo; 9695574Smx205022 nge_dev_spec_param_t *dev_param_p; 9705574Smx205022 9715574Smx205022 devinfo = ngep->devinfo; 9725574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 9735574Smx205022 dev_param_p = &ngep->dev_spec_param; 9745574Smx205022 9755574Smx205022 infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9765574Smx205022 DDI_PROP_DONTPASS, clsize_propname, 32); 9775574Smx205022 9785574Smx205022 infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9795574Smx205022 DDI_PROP_DONTPASS, latency_propname, 64); 9805659Sjj146644 ngep->intr_moderation = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9815659Sjj146644 DDI_PROP_DONTPASS, intr_moderation, NGE_SET); 9825574Smx205022 ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9835574Smx205022 DDI_PROP_DONTPASS, rx_data_hw, 0x20); 9845574Smx205022 ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9855574Smx205022 DDI_PROP_DONTPASS, rx_prd_lw, 0x4); 9865574Smx205022 ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9875574Smx205022 DDI_PROP_DONTPASS, rx_prd_hw, 0xc); 9885574Smx205022 9895574Smx205022 ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9905574Smx205022 DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC); 9915574Smx205022 ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9925574Smx205022 DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP); 9935574Smx205022 ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9945574Smx205022 DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type); 9955574Smx205022 ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9965574Smx205022 DDI_PROP_DONTPASS, low_memory_mode, 0); 9975574Smx205022 9985574Smx205022 if (dev_param_p->jumbo) { 9995574Smx205022 ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 10005574Smx205022 DDI_PROP_DONTPASS, default_mtu, ETHERMTU); 10015574Smx205022 } else 10025574Smx205022 ngep->default_mtu = ETHERMTU; 100310496SLi-Zhen.You@Sun.COM if (dev_param_p->tx_pause_frame) 100410496SLi-Zhen.You@Sun.COM ngep->param_link_tx_pause = B_TRUE; 100510496SLi-Zhen.You@Sun.COM else 100610496SLi-Zhen.You@Sun.COM ngep->param_link_tx_pause = B_FALSE; 100710496SLi-Zhen.You@Sun.COM 100810496SLi-Zhen.You@Sun.COM if (dev_param_p->rx_pause_frame) 100910496SLi-Zhen.You@Sun.COM ngep->param_link_rx_pause = B_TRUE; 101010496SLi-Zhen.You@Sun.COM else 101110496SLi-Zhen.You@Sun.COM ngep->param_link_rx_pause = B_FALSE; 10125574Smx205022 10135574Smx205022 if (ngep->default_mtu > ETHERMTU && 10145574Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 10155574Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 10165574Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 10175574Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 10185574Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 10195574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10205574Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 10215574Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 10225574Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 10235574Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 10245574Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 10255574Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 10265574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10275574Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 10285574Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 10295574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10305574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10315574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10325574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10335574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10345574Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 10355574Smx205022 ngep->default_mtu = NGE_MAX_MTU; 10365574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10375574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10385574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10395574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10405574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10415574Smx205022 } else if (ngep->lowmem_mode != 0) { 10425574Smx205022 ngep->default_mtu = ETHERMTU; 10435574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10445574Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 10455574Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 10465574Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 10475574Smx205022 ngep->nge_split = NGE_SPLIT_32; 10485574Smx205022 } else { 10495574Smx205022 ngep->default_mtu = ETHERMTU; 10505574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10515574Smx205022 ngep->tx_desc = dev_param_p->tx_desc_num; 10525574Smx205022 ngep->rx_desc = dev_param_p->rx_desc_num; 10535574Smx205022 ngep->rx_buf = dev_param_p->rx_desc_num * 2; 10545574Smx205022 ngep->nge_split = dev_param_p->nge_split; 10555574Smx205022 } 10565574Smx205022 10575574Smx205022 nge_check_desc_prop(ngep); 10585574Smx205022 } 10595574Smx205022 10605574Smx205022 10615574Smx205022 static int 10627656SSherry.Moore@Sun.COM nge_reset_dev(nge_t *ngep) 10635574Smx205022 { 10645574Smx205022 int err; 10655869Smx205022 nge_mul_addr1 maddr1; 10665869Smx205022 nge_sw_statistics_t *sw_stp; 10675869Smx205022 sw_stp = &ngep->statistics.sw_statistics; 10685574Smx205022 send_ring_t *srp = ngep->send; 10695574Smx205022 10705574Smx205022 ASSERT(mutex_owned(ngep->genlock)); 10715574Smx205022 mutex_enter(srp->tc_lock); 10725574Smx205022 mutex_enter(srp->tx_lock); 10735574Smx205022 10745574Smx205022 nge_tx_recycle_all(ngep); 10755574Smx205022 err = nge_reinit_ring(ngep); 10765574Smx205022 if (err == DDI_FAILURE) { 10775574Smx205022 mutex_exit(srp->tx_lock); 10785574Smx205022 mutex_exit(srp->tc_lock); 10795574Smx205022 return (err); 10805574Smx205022 } 10815574Smx205022 err = nge_chip_reset(ngep); 10825869Smx205022 /* 10835869Smx205022 * Clear the Multicast mac address table 10845869Smx205022 */ 10855869Smx205022 nge_reg_put32(ngep, NGE_MUL_ADDR0, 0); 10865869Smx205022 maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1); 10875869Smx205022 maddr1.addr_bits.addr = 0; 10885869Smx205022 nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val); 10895869Smx205022 10905574Smx205022 mutex_exit(srp->tx_lock); 10915574Smx205022 mutex_exit(srp->tc_lock); 10925574Smx205022 if (err == DDI_FAILURE) 10935574Smx205022 return (err); 10945574Smx205022 ngep->watchdog = 0; 10955574Smx205022 ngep->resched_needed = B_FALSE; 10965574Smx205022 ngep->promisc = B_FALSE; 10975574Smx205022 ngep->param_loop_mode = NGE_LOOP_NONE; 10985574Smx205022 ngep->factotum_flag = 0; 10995574Smx205022 ngep->resched_needed = 0; 11005574Smx205022 ngep->nge_mac_state = NGE_MAC_RESET; 11015574Smx205022 ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL; 11025574Smx205022 ngep->max_sdu += VTAG_SIZE; 11035574Smx205022 ngep->rx_def = 0x16; 11045869Smx205022 11055869Smx205022 /* Clear the software statistics */ 11065869Smx205022 sw_stp->recv_count = 0; 11075869Smx205022 sw_stp->xmit_count = 0; 11085869Smx205022 sw_stp->rbytes = 0; 11095869Smx205022 sw_stp->obytes = 0; 11105869Smx205022 11115574Smx205022 return (DDI_SUCCESS); 11125574Smx205022 } 11135574Smx205022 11145574Smx205022 static void 11155574Smx205022 nge_m_stop(void *arg) 11165574Smx205022 { 11175574Smx205022 nge_t *ngep = arg; /* private device info */ 11189708SZhen.W@Sun.COM int err; 11195574Smx205022 11205574Smx205022 NGE_TRACE(("nge_m_stop($%p)", arg)); 11215574Smx205022 11225574Smx205022 /* 11235574Smx205022 * Just stop processing, then record new MAC state 11245574Smx205022 */ 11255574Smx205022 mutex_enter(ngep->genlock); 11265869Smx205022 /* If suspended, the adapter is already stopped, just return. */ 11275869Smx205022 if (ngep->suspended) { 11285869Smx205022 ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED); 11295869Smx205022 mutex_exit(ngep->genlock); 11305869Smx205022 return; 11315869Smx205022 } 11325574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 11335574Smx205022 11349708SZhen.W@Sun.COM err = nge_chip_stop(ngep, B_FALSE); 11359708SZhen.W@Sun.COM if (err == DDI_FAILURE) 11369708SZhen.W@Sun.COM err = nge_chip_reset(ngep); 11379708SZhen.W@Sun.COM if (err == DDI_FAILURE) 11389708SZhen.W@Sun.COM nge_problem(ngep, "nge_m_stop: stop chip failed"); 11395574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 11405574Smx205022 11415574Smx205022 /* Recycle all the TX BD */ 11425574Smx205022 nge_tx_recycle_all(ngep); 11435574Smx205022 nge_fini_rings(ngep); 11445574Smx205022 nge_free_bufs(ngep); 11455574Smx205022 11465574Smx205022 NGE_DEBUG(("nge_m_stop($%p) done", arg)); 11475574Smx205022 11485574Smx205022 rw_exit(ngep->rwlock); 11495574Smx205022 mutex_exit(ngep->genlock); 11505574Smx205022 } 11515574Smx205022 11525574Smx205022 static int 11535574Smx205022 nge_m_start(void *arg) 11545574Smx205022 { 11555574Smx205022 int err; 11565574Smx205022 nge_t *ngep = arg; 11575574Smx205022 11585574Smx205022 NGE_TRACE(("nge_m_start($%p)", arg)); 11595869Smx205022 11605869Smx205022 /* 11615869Smx205022 * Start processing and record new MAC state 11625869Smx205022 */ 11635869Smx205022 mutex_enter(ngep->genlock); 11645574Smx205022 /* 11655574Smx205022 * If suspended, don't start, as the resume processing 11665574Smx205022 * will recall this function with the suspended flag off. 11675574Smx205022 */ 11685869Smx205022 if (ngep->suspended) { 11695869Smx205022 mutex_exit(ngep->genlock); 11705988Svb160487 return (EIO); 11715869Smx205022 } 11725574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 11735574Smx205022 err = nge_alloc_bufs(ngep); 11745574Smx205022 if (err != DDI_SUCCESS) { 11755574Smx205022 nge_problem(ngep, "nge_m_start: DMA buffer allocation failed"); 11765574Smx205022 goto finish; 11775574Smx205022 } 11785574Smx205022 err = nge_init_rings(ngep); 11795574Smx205022 if (err != DDI_SUCCESS) { 11805574Smx205022 nge_free_bufs(ngep); 11815988Svb160487 nge_problem(ngep, "nge_init_rings() failed,err=%x", err); 11825574Smx205022 goto finish; 11835574Smx205022 } 11845574Smx205022 err = nge_restart(ngep); 11855574Smx205022 11865574Smx205022 NGE_DEBUG(("nge_m_start($%p) done", arg)); 11875988Svb160487 finish: 11885988Svb160487 rw_exit(ngep->rwlock); 11895988Svb160487 mutex_exit(ngep->genlock); 11905574Smx205022 11915988Svb160487 return (err == DDI_SUCCESS ? 0 : EIO); 11925574Smx205022 } 11935574Smx205022 11945574Smx205022 static int 11955574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr) 11965574Smx205022 { 11975574Smx205022 nge_t *ngep = arg; 11985574Smx205022 11995574Smx205022 NGE_TRACE(("nge_m_unicst($%p)", arg)); 12005574Smx205022 /* 12015574Smx205022 * Remember the new current address in the driver state 12025574Smx205022 * Sync the chip's idea of the address too ... 12035574Smx205022 */ 12045574Smx205022 mutex_enter(ngep->genlock); 12055574Smx205022 12065574Smx205022 ethaddr_copy(macaddr, ngep->cur_uni_addr.addr); 12075574Smx205022 ngep->cur_uni_addr.set = 1; 12085574Smx205022 12095574Smx205022 /* 12105574Smx205022 * If we are suspended, we want to quit now, and not update 12115574Smx205022 * the chip. Doing so might put it in a bad state, but the 12125574Smx205022 * resume will get the unicast address installed. 12135574Smx205022 */ 12145869Smx205022 if (ngep->suspended) { 12155869Smx205022 mutex_exit(ngep->genlock); 12165574Smx205022 return (DDI_SUCCESS); 12175869Smx205022 } 12185574Smx205022 nge_chip_sync(ngep); 12195574Smx205022 12205574Smx205022 NGE_DEBUG(("nge_m_unicst($%p) done", arg)); 12215574Smx205022 mutex_exit(ngep->genlock); 12225574Smx205022 12235574Smx205022 return (0); 12245574Smx205022 } 12255574Smx205022 12265574Smx205022 static int 12275574Smx205022 nge_m_promisc(void *arg, boolean_t on) 12285574Smx205022 { 12295574Smx205022 nge_t *ngep = arg; 12305574Smx205022 12315574Smx205022 NGE_TRACE(("nge_m_promisc($%p)", arg)); 12325574Smx205022 12335574Smx205022 /* 12345574Smx205022 * Store specified mode and pass to chip layer to update h/w 12355574Smx205022 */ 12365574Smx205022 mutex_enter(ngep->genlock); 12375869Smx205022 /* 12385869Smx205022 * If suspended, there is no need to do anything, even 12395869Smx205022 * recording the promiscuious mode is not neccessary, as 12405869Smx205022 * it won't be properly set on resume. Just return failing. 12415869Smx205022 */ 12425869Smx205022 if (ngep->suspended) { 12435869Smx205022 mutex_exit(ngep->genlock); 12445869Smx205022 return (DDI_FAILURE); 12455869Smx205022 } 12465574Smx205022 if (ngep->promisc == on) { 12475574Smx205022 mutex_exit(ngep->genlock); 12485574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12495574Smx205022 return (0); 12505574Smx205022 } 12515574Smx205022 ngep->promisc = on; 12527155Smx205022 ngep->record_promisc = ngep->promisc; 12535574Smx205022 nge_chip_sync(ngep); 12545574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 12555574Smx205022 mutex_exit(ngep->genlock); 12565574Smx205022 12575574Smx205022 return (0); 12585574Smx205022 } 12595574Smx205022 12605574Smx205022 static void nge_mulparam(nge_t *ngep) 12615574Smx205022 { 12625574Smx205022 uint8_t number; 12635574Smx205022 ether_addr_t pand; 12645574Smx205022 ether_addr_t por; 12655574Smx205022 mul_item *plist; 12665574Smx205022 12675574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12685574Smx205022 pand[number] = 0x00; 12695574Smx205022 por[number] = 0x00; 12705574Smx205022 } 12715574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) { 12725574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12735574Smx205022 pand[number] &= plist->mul_addr[number]; 12745574Smx205022 por[number] |= plist->mul_addr[number]; 12755574Smx205022 } 12765574Smx205022 } 12775574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12785574Smx205022 ngep->cur_mul_addr.addr[number] 12795574Smx205022 = pand[number] & por[number]; 12805574Smx205022 ngep->cur_mul_mask.addr[number] 12815574Smx205022 = pand [number] | (~por[number]); 12825574Smx205022 } 12835574Smx205022 } 12845574Smx205022 static int 12855574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12865574Smx205022 { 12875574Smx205022 boolean_t update; 12885574Smx205022 boolean_t b_eq; 12895574Smx205022 nge_t *ngep = arg; 12905574Smx205022 mul_item *plist; 12915574Smx205022 mul_item *plist_prev; 12925574Smx205022 mul_item *pitem; 12935574Smx205022 12945574Smx205022 NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg, 12955574Smx205022 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 12965574Smx205022 12975574Smx205022 update = B_FALSE; 12985574Smx205022 plist = plist_prev = NULL; 12995574Smx205022 mutex_enter(ngep->genlock); 13005574Smx205022 if (add) { 13015574Smx205022 if (ngep->pcur_mulist != NULL) { 13025574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 13035574Smx205022 plist = plist->next) { 13045574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 13055574Smx205022 if (b_eq) { 13065574Smx205022 plist->ref_cnt++; 13075574Smx205022 break; 13085574Smx205022 } 13095574Smx205022 plist_prev = plist; 13105574Smx205022 } 13115574Smx205022 } 13125574Smx205022 13135574Smx205022 if (plist == NULL) { 13145574Smx205022 pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP); 13155574Smx205022 ether_copy(mca, pitem->mul_addr); 13165574Smx205022 pitem ->ref_cnt++; 13175574Smx205022 pitem ->next = NULL; 13185574Smx205022 if (plist_prev == NULL) 13195574Smx205022 ngep->pcur_mulist = pitem; 13205574Smx205022 else 13215574Smx205022 plist_prev->next = pitem; 13225574Smx205022 update = B_TRUE; 13235574Smx205022 } 13245574Smx205022 } else { 13255574Smx205022 if (ngep->pcur_mulist != NULL) { 13265574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 13275574Smx205022 plist = plist->next) { 13285574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 13295574Smx205022 if (b_eq) { 13305574Smx205022 update = B_TRUE; 13315574Smx205022 break; 13325574Smx205022 } 13335574Smx205022 plist_prev = plist; 13345574Smx205022 } 13355574Smx205022 13365574Smx205022 if (update) { 13375574Smx205022 if ((plist_prev == NULL) && 13385574Smx205022 (plist->next == NULL)) 13395574Smx205022 ngep->pcur_mulist = NULL; 13405574Smx205022 else if ((plist_prev == NULL) && 13415574Smx205022 (plist->next != NULL)) 13425574Smx205022 ngep->pcur_mulist = plist->next; 13435574Smx205022 else 13445574Smx205022 plist_prev->next = plist->next; 13455574Smx205022 kmem_free(plist, sizeof (mul_item)); 13465574Smx205022 } 13475574Smx205022 } 13485574Smx205022 } 13495574Smx205022 13505869Smx205022 if (update && !ngep->suspended) { 13515574Smx205022 nge_mulparam(ngep); 13525574Smx205022 nge_chip_sync(ngep); 13535574Smx205022 } 13545574Smx205022 NGE_DEBUG(("nge_m_multicst($%p) done", arg)); 13555574Smx205022 mutex_exit(ngep->genlock); 13565574Smx205022 13575574Smx205022 return (0); 13585574Smx205022 } 13595574Smx205022 13605574Smx205022 static void 13615574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 13625574Smx205022 { 13635574Smx205022 int err; 13645574Smx205022 int cmd; 13655574Smx205022 nge_t *ngep = arg; 13665574Smx205022 struct iocblk *iocp; 13675574Smx205022 enum ioc_reply status; 13685574Smx205022 boolean_t need_privilege; 13695574Smx205022 13705574Smx205022 /* 13715574Smx205022 * If suspended, we might actually be able to do some of 13725574Smx205022 * these ioctls, but it is harder to make sure they occur 13735574Smx205022 * without actually putting the hardware in an undesireable 13745574Smx205022 * state. So just NAK it. 13755574Smx205022 */ 13765869Smx205022 mutex_enter(ngep->genlock); 13775574Smx205022 if (ngep->suspended) { 13785574Smx205022 miocnak(wq, mp, 0, EINVAL); 13795869Smx205022 mutex_exit(ngep->genlock); 13805574Smx205022 return; 13815574Smx205022 } 13825869Smx205022 mutex_exit(ngep->genlock); 13835574Smx205022 13845574Smx205022 /* 13855574Smx205022 * Validate the command before bothering with the mutex ... 13865574Smx205022 */ 13875574Smx205022 iocp = (struct iocblk *)mp->b_rptr; 13885574Smx205022 iocp->ioc_error = 0; 13895574Smx205022 need_privilege = B_TRUE; 13905574Smx205022 cmd = iocp->ioc_cmd; 13915574Smx205022 13925574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x", cmd)); 13935574Smx205022 switch (cmd) { 13945574Smx205022 default: 13955574Smx205022 NGE_LDB(NGE_DBG_BADIOC, 13965574Smx205022 ("nge_m_ioctl: unknown cmd 0x%x", cmd)); 13975574Smx205022 13985574Smx205022 miocnak(wq, mp, 0, EINVAL); 13995574Smx205022 return; 14005574Smx205022 14015574Smx205022 case NGE_MII_READ: 14025574Smx205022 case NGE_MII_WRITE: 14035574Smx205022 case NGE_SEE_READ: 14045574Smx205022 case NGE_SEE_WRITE: 14055574Smx205022 case NGE_DIAG: 14065574Smx205022 case NGE_PEEK: 14075574Smx205022 case NGE_POKE: 14085574Smx205022 case NGE_PHY_RESET: 14095574Smx205022 case NGE_SOFT_RESET: 14105574Smx205022 case NGE_HARD_RESET: 14115574Smx205022 break; 14125574Smx205022 14135574Smx205022 case LB_GET_INFO_SIZE: 14145574Smx205022 case LB_GET_INFO: 14155574Smx205022 case LB_GET_MODE: 14165574Smx205022 need_privilege = B_FALSE; 14175574Smx205022 break; 14185574Smx205022 case LB_SET_MODE: 14195574Smx205022 break; 14205574Smx205022 } 14215574Smx205022 14225574Smx205022 if (need_privilege) { 14235574Smx205022 /* 14245574Smx205022 * Check for specific net_config privilege. 14255574Smx205022 */ 14265574Smx205022 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 14275574Smx205022 if (err != 0) { 14285574Smx205022 NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d", 14295574Smx205022 cmd, err)); 14305574Smx205022 miocnak(wq, mp, 0, err); 14315574Smx205022 return; 14325574Smx205022 } 14335574Smx205022 } 14345574Smx205022 14355574Smx205022 mutex_enter(ngep->genlock); 14365574Smx205022 14375574Smx205022 switch (cmd) { 14385574Smx205022 default: 14395574Smx205022 _NOTE(NOTREACHED) 14405574Smx205022 status = IOC_INVAL; 14415574Smx205022 break; 14425574Smx205022 14435574Smx205022 case NGE_MII_READ: 14445574Smx205022 case NGE_MII_WRITE: 14455574Smx205022 case NGE_SEE_READ: 14465574Smx205022 case NGE_SEE_WRITE: 14475574Smx205022 case NGE_DIAG: 14485574Smx205022 case NGE_PEEK: 14495574Smx205022 case NGE_POKE: 14505574Smx205022 case NGE_PHY_RESET: 14515574Smx205022 case NGE_SOFT_RESET: 14525574Smx205022 case NGE_HARD_RESET: 14535574Smx205022 status = nge_chip_ioctl(ngep, mp, iocp); 14545574Smx205022 break; 14555574Smx205022 14565574Smx205022 case LB_GET_INFO_SIZE: 14575574Smx205022 case LB_GET_INFO: 14585574Smx205022 case LB_GET_MODE: 14595574Smx205022 case LB_SET_MODE: 14605574Smx205022 status = nge_loop_ioctl(ngep, mp, iocp); 14615574Smx205022 break; 14625574Smx205022 14635574Smx205022 } 14645574Smx205022 14655574Smx205022 /* 14665574Smx205022 * Do we need to reprogram the PHY and/or the MAC? 14675574Smx205022 * Do it now, while we still have the mutex. 14685574Smx205022 * 14695574Smx205022 * Note: update the PHY first, 'cos it controls the 14705574Smx205022 * speed/duplex parameters that the MAC code uses. 14715574Smx205022 */ 14725574Smx205022 14735574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status)); 14745574Smx205022 14755574Smx205022 switch (status) { 14765574Smx205022 case IOC_RESTART_REPLY: 14775574Smx205022 case IOC_RESTART_ACK: 14785574Smx205022 (*ngep->physops->phys_update)(ngep); 14795574Smx205022 nge_chip_sync(ngep); 14805574Smx205022 break; 14815574Smx205022 14825574Smx205022 default: 14835574Smx205022 break; 14845574Smx205022 } 14855574Smx205022 14865574Smx205022 mutex_exit(ngep->genlock); 14875574Smx205022 14885574Smx205022 /* 14895574Smx205022 * Finally, decide how to reply 14905574Smx205022 */ 14915574Smx205022 switch (status) { 14925574Smx205022 14935574Smx205022 default: 14945574Smx205022 case IOC_INVAL: 14955574Smx205022 miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 14965574Smx205022 EINVAL : iocp->ioc_error); 14975574Smx205022 break; 14985574Smx205022 14995574Smx205022 case IOC_DONE: 15005574Smx205022 break; 15015574Smx205022 15025574Smx205022 case IOC_RESTART_ACK: 15035574Smx205022 case IOC_ACK: 15045574Smx205022 miocack(wq, mp, 0, 0); 15055574Smx205022 break; 15065574Smx205022 15075574Smx205022 case IOC_RESTART_REPLY: 15085574Smx205022 case IOC_REPLY: 15095574Smx205022 mp->b_datap->db_type = iocp->ioc_error == 0 ? 15105574Smx205022 M_IOCACK : M_IOCNAK; 15115574Smx205022 qreply(wq, mp); 15125574Smx205022 break; 15135574Smx205022 } 15145574Smx205022 } 15155574Smx205022 15166200Smx205022 static boolean_t 15176200Smx205022 nge_param_locked(mac_prop_id_t pr_num) 15186200Smx205022 { 15196200Smx205022 /* 15206200Smx205022 * All adv_* parameters are locked (read-only) while 15216200Smx205022 * the device is in any sort of loopback mode ... 15226200Smx205022 */ 15236200Smx205022 switch (pr_num) { 15246789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 15256789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 15266789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 15276789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 15286789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 15296789Sam223141 case MAC_PROP_EN_100FDX_CAP: 15306789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 15316789Sam223141 case MAC_PROP_EN_100HDX_CAP: 15326789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 15336789Sam223141 case MAC_PROP_EN_10FDX_CAP: 15346789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 15356789Sam223141 case MAC_PROP_EN_10HDX_CAP: 15366789Sam223141 case MAC_PROP_AUTONEG: 15376789Sam223141 case MAC_PROP_FLOWCTRL: 15386200Smx205022 return (B_TRUE); 15396200Smx205022 } 15406200Smx205022 return (B_FALSE); 15416200Smx205022 } 15426200Smx205022 15436200Smx205022 /* 15446200Smx205022 * callback functions for set/get of properties 15456200Smx205022 */ 15466200Smx205022 static int 15476200Smx205022 nge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 15486200Smx205022 uint_t pr_valsize, const void *pr_val) 15496200Smx205022 { 15506200Smx205022 nge_t *ngep = barg; 15516200Smx205022 int err = 0; 15526512Ssowmini uint32_t cur_mtu, new_mtu; 15536200Smx205022 link_flowctrl_t fl; 15546200Smx205022 15556200Smx205022 mutex_enter(ngep->genlock); 15566200Smx205022 if (ngep->param_loop_mode != NGE_LOOP_NONE && 15576200Smx205022 nge_param_locked(pr_num)) { 15586200Smx205022 /* 15596200Smx205022 * All adv_* parameters are locked (read-only) 15606200Smx205022 * while the device is in any sort of loopback mode. 15616200Smx205022 */ 15626200Smx205022 mutex_exit(ngep->genlock); 15636200Smx205022 return (EBUSY); 15646200Smx205022 } 15656200Smx205022 switch (pr_num) { 15666789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 15676200Smx205022 ngep->param_en_1000fdx = *(uint8_t *)pr_val; 15686200Smx205022 ngep->param_adv_1000fdx = *(uint8_t *)pr_val; 15696200Smx205022 goto reprogram; 15706789Sam223141 case MAC_PROP_EN_100FDX_CAP: 15716200Smx205022 ngep->param_en_100fdx = *(uint8_t *)pr_val; 15726200Smx205022 ngep->param_adv_100fdx = *(uint8_t *)pr_val; 15736200Smx205022 goto reprogram; 15746789Sam223141 case MAC_PROP_EN_100HDX_CAP: 15756200Smx205022 ngep->param_en_100hdx = *(uint8_t *)pr_val; 15766200Smx205022 ngep->param_adv_100hdx = *(uint8_t *)pr_val; 15776200Smx205022 goto reprogram; 15786789Sam223141 case MAC_PROP_EN_10FDX_CAP: 15796200Smx205022 ngep->param_en_10fdx = *(uint8_t *)pr_val; 15806200Smx205022 ngep->param_adv_10fdx = *(uint8_t *)pr_val; 15816200Smx205022 goto reprogram; 15826789Sam223141 case MAC_PROP_EN_10HDX_CAP: 15836200Smx205022 ngep->param_en_10hdx = *(uint8_t *)pr_val; 15846200Smx205022 ngep->param_adv_10hdx = *(uint8_t *)pr_val; 15856200Smx205022 reprogram: 15866200Smx205022 (*ngep->physops->phys_update)(ngep); 15876200Smx205022 nge_chip_sync(ngep); 15886200Smx205022 break; 15896200Smx205022 15906789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 15916789Sam223141 case MAC_PROP_ADV_1000HDX_CAP: 15926789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 15936789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 15946789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 15956789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 15966789Sam223141 case MAC_PROP_STATUS: 15976789Sam223141 case MAC_PROP_SPEED: 15986789Sam223141 case MAC_PROP_DUPLEX: 15996789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 16006200Smx205022 err = ENOTSUP; /* read-only prop. Can't set this */ 16016200Smx205022 break; 16026789Sam223141 case MAC_PROP_AUTONEG: 16036200Smx205022 ngep->param_adv_autoneg = *(uint8_t *)pr_val; 16046200Smx205022 (*ngep->physops->phys_update)(ngep); 16056200Smx205022 nge_chip_sync(ngep); 16066200Smx205022 break; 16076789Sam223141 case MAC_PROP_MTU: 16086200Smx205022 cur_mtu = ngep->default_mtu; 16096200Smx205022 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 16106200Smx205022 if (new_mtu == cur_mtu) { 16116200Smx205022 err = 0; 16126200Smx205022 break; 16136200Smx205022 } 16146200Smx205022 if (new_mtu < ETHERMTU || 16156200Smx205022 new_mtu > NGE_MAX_MTU) { 16166200Smx205022 err = EINVAL; 16176200Smx205022 break; 16186200Smx205022 } 16196200Smx205022 if ((new_mtu > ETHERMTU) && 16206200Smx205022 (!ngep->dev_spec_param.jumbo)) { 16216200Smx205022 err = EINVAL; 16226200Smx205022 break; 16236200Smx205022 } 16246200Smx205022 if (ngep->nge_mac_state == NGE_MAC_STARTED) { 16256200Smx205022 err = EBUSY; 16266200Smx205022 break; 16276200Smx205022 } 16286200Smx205022 16296200Smx205022 ngep->default_mtu = new_mtu; 16306200Smx205022 if (ngep->default_mtu > ETHERMTU && 16316200Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 16326200Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 16336200Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 16346200Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 16356200Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 16366200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16376200Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 16386200Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 16396200Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 16406200Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 16416200Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 16426200Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 16436200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16446200Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 16456200Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 16466200Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16476200Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16486200Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16496200Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16506200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16516200Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 16526200Smx205022 ngep->default_mtu = NGE_MAX_MTU; 16536200Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 16546200Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 16556200Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 16566200Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 16576200Smx205022 ngep->nge_split = NGE_SPLIT_256; 16586200Smx205022 } else if (ngep->lowmem_mode != 0) { 16596200Smx205022 ngep->default_mtu = ETHERMTU; 16606200Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16616200Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 16626200Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 16636200Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 16646200Smx205022 ngep->nge_split = NGE_SPLIT_32; 16656200Smx205022 } else { 16666200Smx205022 ngep->default_mtu = ETHERMTU; 16676200Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 16686200Smx205022 ngep->tx_desc = 16696200Smx205022 ngep->dev_spec_param.tx_desc_num; 16706200Smx205022 ngep->rx_desc = 16716200Smx205022 ngep->dev_spec_param.rx_desc_num; 16726200Smx205022 ngep->rx_buf = 16736200Smx205022 ngep->dev_spec_param.rx_desc_num * 2; 16746200Smx205022 ngep->nge_split = 16756200Smx205022 ngep->dev_spec_param.nge_split; 16766200Smx205022 } 16776200Smx205022 16786200Smx205022 err = mac_maxsdu_update(ngep->mh, ngep->default_mtu); 16796200Smx205022 16806200Smx205022 break; 16816789Sam223141 case MAC_PROP_FLOWCTRL: 16826200Smx205022 bcopy(pr_val, &fl, sizeof (fl)); 16836200Smx205022 switch (fl) { 16846200Smx205022 default: 16856200Smx205022 err = ENOTSUP; 16866200Smx205022 break; 16876200Smx205022 case LINK_FLOWCTRL_NONE: 16886200Smx205022 ngep->param_adv_pause = 0; 16896200Smx205022 ngep->param_adv_asym_pause = 0; 16906200Smx205022 16916200Smx205022 ngep->param_link_rx_pause = B_FALSE; 16926200Smx205022 ngep->param_link_tx_pause = B_FALSE; 16936200Smx205022 break; 16946200Smx205022 case LINK_FLOWCTRL_RX: 16956200Smx205022 if (!((ngep->param_lp_pause == 0) && 16966200Smx205022 (ngep->param_lp_asym_pause == 1))) { 16976200Smx205022 err = EINVAL; 16986200Smx205022 break; 16996200Smx205022 } 17006200Smx205022 ngep->param_adv_pause = 1; 17016200Smx205022 ngep->param_adv_asym_pause = 1; 17026200Smx205022 17036200Smx205022 ngep->param_link_rx_pause = B_TRUE; 17046200Smx205022 ngep->param_link_tx_pause = B_FALSE; 17056200Smx205022 break; 17066200Smx205022 case LINK_FLOWCTRL_TX: 17076200Smx205022 if (!((ngep->param_lp_pause == 1) && 17086200Smx205022 (ngep->param_lp_asym_pause == 1))) { 17096200Smx205022 err = EINVAL; 17106200Smx205022 break; 17116200Smx205022 } 17126200Smx205022 ngep->param_adv_pause = 0; 17136200Smx205022 ngep->param_adv_asym_pause = 1; 17146200Smx205022 17156200Smx205022 ngep->param_link_rx_pause = B_FALSE; 17166200Smx205022 ngep->param_link_tx_pause = B_TRUE; 17176200Smx205022 break; 17186200Smx205022 case LINK_FLOWCTRL_BI: 17196200Smx205022 if (ngep->param_lp_pause != 1) { 17206200Smx205022 err = EINVAL; 17216200Smx205022 break; 17226200Smx205022 } 17236200Smx205022 ngep->param_adv_pause = 1; 17246200Smx205022 17256200Smx205022 ngep->param_link_rx_pause = B_TRUE; 17266200Smx205022 ngep->param_link_tx_pause = B_TRUE; 17276200Smx205022 break; 17286200Smx205022 } 17296200Smx205022 17306200Smx205022 if (err == 0) { 17316200Smx205022 (*ngep->physops->phys_update)(ngep); 17326200Smx205022 nge_chip_sync(ngep); 17336200Smx205022 } 17346200Smx205022 17356200Smx205022 break; 17366789Sam223141 case MAC_PROP_PRIVATE: 17376200Smx205022 err = nge_set_priv_prop(ngep, pr_name, pr_valsize, 17386200Smx205022 pr_val); 17396200Smx205022 if (err == 0) { 17406200Smx205022 (*ngep->physops->phys_update)(ngep); 17416200Smx205022 nge_chip_sync(ngep); 17426200Smx205022 } 17436200Smx205022 break; 17446200Smx205022 default: 17456200Smx205022 err = ENOTSUP; 17466200Smx205022 } 17476200Smx205022 mutex_exit(ngep->genlock); 17486200Smx205022 return (err); 17496200Smx205022 } 17506200Smx205022 17516200Smx205022 static int 17526200Smx205022 nge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, 17538118SVasumathi.Sundaram@Sun.COM uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm) 17546200Smx205022 { 17556200Smx205022 nge_t *ngep = barg; 17566512Ssowmini int err = 0; 17576200Smx205022 link_flowctrl_t fl; 17586512Ssowmini uint64_t speed; 17596789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 17606512Ssowmini 17616512Ssowmini if (pr_valsize == 0) 17626512Ssowmini return (EINVAL); 17636200Smx205022 17648118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_RW; 17658118SVasumathi.Sundaram@Sun.COM 17666200Smx205022 bzero(pr_val, pr_valsize); 17678118SVasumathi.Sundaram@Sun.COM 17686200Smx205022 switch (pr_num) { 17696789Sam223141 case MAC_PROP_DUPLEX: 17708118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 17716512Ssowmini if (pr_valsize >= sizeof (link_duplex_t)) { 17726512Ssowmini bcopy(&ngep->param_link_duplex, pr_val, 17736512Ssowmini sizeof (link_duplex_t)); 17746512Ssowmini } else 17756512Ssowmini err = EINVAL; 17766200Smx205022 break; 17776789Sam223141 case MAC_PROP_SPEED: 17788118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 17796200Smx205022 if (pr_valsize >= sizeof (uint64_t)) { 17806512Ssowmini speed = ngep->param_link_speed * 1000000ull; 17816512Ssowmini bcopy(&speed, pr_val, sizeof (speed)); 17826512Ssowmini } else 17836512Ssowmini err = EINVAL; 17846200Smx205022 break; 17856789Sam223141 case MAC_PROP_AUTONEG: 17866512Ssowmini if (is_default) { 17876512Ssowmini *(uint8_t *)pr_val = 1; 17886512Ssowmini } else { 17896200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_autoneg; 17906200Smx205022 } 17916200Smx205022 break; 17926789Sam223141 case MAC_PROP_FLOWCTRL: 17936200Smx205022 if (pr_valsize >= sizeof (link_flowctrl_t)) { 17946789Sam223141 if (pr_flags & MAC_PROP_DEFAULT) { 17956512Ssowmini fl = LINK_FLOWCTRL_BI; 17966512Ssowmini bcopy(&fl, pr_val, sizeof (fl)); 17976512Ssowmini break; 17986512Ssowmini } 17996200Smx205022 if (ngep->param_link_rx_pause && 18006200Smx205022 !ngep->param_link_tx_pause) 18016200Smx205022 fl = LINK_FLOWCTRL_RX; 18026200Smx205022 18036200Smx205022 if (!ngep->param_link_rx_pause && 18046200Smx205022 !ngep->param_link_tx_pause) 18056200Smx205022 fl = LINK_FLOWCTRL_NONE; 18066200Smx205022 18076200Smx205022 if (!ngep->param_link_rx_pause && 18086200Smx205022 ngep->param_link_tx_pause) 18096200Smx205022 fl = LINK_FLOWCTRL_TX; 18106200Smx205022 18116200Smx205022 if (ngep->param_link_rx_pause && 18126200Smx205022 ngep->param_link_tx_pause) 18136200Smx205022 fl = LINK_FLOWCTRL_BI; 18146200Smx205022 bcopy(&fl, pr_val, sizeof (fl)); 18156512Ssowmini } else 18166512Ssowmini err = EINVAL; 18176200Smx205022 break; 18186789Sam223141 case MAC_PROP_ADV_1000FDX_CAP: 18198118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18206512Ssowmini if (is_default) { 18216512Ssowmini *(uint8_t *)pr_val = 1; 18226512Ssowmini } else { 18236200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_1000fdx; 18246200Smx205022 } 18256200Smx205022 break; 18266789Sam223141 case MAC_PROP_EN_1000FDX_CAP: 18276512Ssowmini if (is_default) { 18286512Ssowmini *(uint8_t *)pr_val = 1; 18296512Ssowmini } else { 18306200Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000fdx; 18316200Smx205022 } 18326200Smx205022 break; 18336789Sam223141 case MAC_PROP_ADV_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_adv_1000hdx; 18396200Smx205022 } 18406200Smx205022 break; 18416789Sam223141 case MAC_PROP_EN_1000HDX_CAP: 18428118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18436512Ssowmini if (is_default) { 18446512Ssowmini *(uint8_t *)pr_val = 0; 18456512Ssowmini } else { 18466200Smx205022 *(uint8_t *)pr_val = ngep->param_en_1000hdx; 18476200Smx205022 } 18486200Smx205022 break; 18496789Sam223141 case MAC_PROP_ADV_100FDX_CAP: 18508118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18516512Ssowmini if (is_default) { 18526512Ssowmini *(uint8_t *)pr_val = 1; 18536512Ssowmini } else { 18546200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100fdx; 18556200Smx205022 } 18566200Smx205022 break; 18576789Sam223141 case MAC_PROP_EN_100FDX_CAP: 18586512Ssowmini if (is_default) { 18596512Ssowmini *(uint8_t *)pr_val = 1; 18606512Ssowmini } else { 18616200Smx205022 *(uint8_t *)pr_val = ngep->param_en_100fdx; 18626200Smx205022 } 18636200Smx205022 break; 18646789Sam223141 case MAC_PROP_ADV_100HDX_CAP: 18658118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18666512Ssowmini if (is_default) { 18676512Ssowmini *(uint8_t *)pr_val = 1; 18686512Ssowmini } else { 18696200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_100hdx; 18706200Smx205022 } 18716200Smx205022 break; 18726789Sam223141 case MAC_PROP_EN_100HDX_CAP: 18736512Ssowmini if (is_default) { 18746512Ssowmini *(uint8_t *)pr_val = 1; 18756512Ssowmini } else { 18766200Smx205022 *(uint8_t *)pr_val = ngep->param_en_100hdx; 18776200Smx205022 } 18786200Smx205022 break; 18796789Sam223141 case MAC_PROP_ADV_10FDX_CAP: 18808118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18816512Ssowmini if (is_default) { 18826512Ssowmini *(uint8_t *)pr_val = 1; 18836512Ssowmini } else { 18846200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10fdx; 18856200Smx205022 } 18866200Smx205022 break; 18876789Sam223141 case MAC_PROP_EN_10FDX_CAP: 18886512Ssowmini if (is_default) { 18896512Ssowmini *(uint8_t *)pr_val = 1; 18906512Ssowmini } else { 18916200Smx205022 *(uint8_t *)pr_val = ngep->param_en_10fdx; 18926200Smx205022 } 18936200Smx205022 break; 18946789Sam223141 case MAC_PROP_ADV_10HDX_CAP: 18958118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 18966512Ssowmini if (is_default) { 18976512Ssowmini *(uint8_t *)pr_val = 1; 18986512Ssowmini } else { 18996200Smx205022 *(uint8_t *)pr_val = ngep->param_adv_10hdx; 19006200Smx205022 } 19016200Smx205022 break; 19026789Sam223141 case MAC_PROP_EN_10HDX_CAP: 19036512Ssowmini if (is_default) { 19046512Ssowmini *(uint8_t *)pr_val = 1; 19056512Ssowmini } else { 19066200Smx205022 *(uint8_t *)pr_val = ngep->param_en_10hdx; 19076200Smx205022 } 19086200Smx205022 break; 19096789Sam223141 case MAC_PROP_ADV_100T4_CAP: 19106789Sam223141 case MAC_PROP_EN_100T4_CAP: 19118118SVasumathi.Sundaram@Sun.COM *perm = MAC_PROP_PERM_READ; 19126512Ssowmini *(uint8_t *)pr_val = 0; 19136512Ssowmini break; 19146789Sam223141 case MAC_PROP_PRIVATE: 19156512Ssowmini err = nge_get_priv_prop(ngep, pr_name, pr_flags, 19166512Ssowmini pr_valsize, pr_val); 19176200Smx205022 break; 19189514SGirish.Moodalbail@Sun.COM case MAC_PROP_MTU: { 19199514SGirish.Moodalbail@Sun.COM mac_propval_range_t range; 19209514SGirish.Moodalbail@Sun.COM 19219514SGirish.Moodalbail@Sun.COM if (!(pr_flags & MAC_PROP_POSSIBLE)) 19229514SGirish.Moodalbail@Sun.COM return (ENOTSUP); 19239514SGirish.Moodalbail@Sun.COM if (pr_valsize < sizeof (mac_propval_range_t)) 19249514SGirish.Moodalbail@Sun.COM return (EINVAL); 19259514SGirish.Moodalbail@Sun.COM range.mpr_count = 1; 19269514SGirish.Moodalbail@Sun.COM range.mpr_type = MAC_PROPVAL_UINT32; 19279514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_min = 19289514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = ETHERMTU; 19299514SGirish.Moodalbail@Sun.COM if (ngep->dev_spec_param.jumbo) 19309514SGirish.Moodalbail@Sun.COM range.range_uint32[0].mpur_max = NGE_MAX_MTU; 19319514SGirish.Moodalbail@Sun.COM bcopy(&range, pr_val, sizeof (range)); 19329514SGirish.Moodalbail@Sun.COM break; 19339514SGirish.Moodalbail@Sun.COM } 19346200Smx205022 default: 19356200Smx205022 err = ENOTSUP; 19366200Smx205022 } 19376200Smx205022 return (err); 19386200Smx205022 } 19396200Smx205022 19406200Smx205022 /* ARGSUSED */ 19416200Smx205022 static int 19426200Smx205022 nge_set_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_valsize, 19436200Smx205022 const void *pr_val) 19446200Smx205022 { 19456200Smx205022 int err = 0; 19466200Smx205022 long result; 19476200Smx205022 19486200Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 19496200Smx205022 if (pr_val == NULL) { 19506200Smx205022 err = EINVAL; 19516200Smx205022 return (err); 19526200Smx205022 } 19536200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19546200Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19556200Smx205022 err = EINVAL; 19566200Smx205022 } else { 19576200Smx205022 ngep->param_txbcopy_threshold = (uint32_t)result; 19586200Smx205022 goto reprogram; 19596200Smx205022 } 19606200Smx205022 return (err); 19616200Smx205022 } 19626200Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 19636200Smx205022 if (pr_val == NULL) { 19646200Smx205022 err = EINVAL; 19656200Smx205022 return (err); 19666200Smx205022 } 19676200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19686200Smx205022 if (result < 0 || result > NGE_MAX_SDU) { 19696200Smx205022 err = EINVAL; 19706200Smx205022 } else { 19716200Smx205022 ngep->param_rxbcopy_threshold = (uint32_t)result; 19726200Smx205022 goto reprogram; 19736200Smx205022 } 19746200Smx205022 return (err); 19756200Smx205022 } 19766200Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 19776200Smx205022 if (pr_val == NULL) { 19786200Smx205022 err = EINVAL; 19796200Smx205022 return (err); 19806200Smx205022 } 19816200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19826200Smx205022 if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 19836200Smx205022 err = EINVAL; 19846200Smx205022 } else { 19856200Smx205022 ngep->param_recv_max_packet = (uint32_t)result; 19866200Smx205022 goto reprogram; 19876200Smx205022 } 19886200Smx205022 return (err); 19896200Smx205022 } 19906200Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 19916200Smx205022 if (pr_val == NULL) { 19926200Smx205022 err = EINVAL; 19936200Smx205022 return (err); 19946200Smx205022 } 19956200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 19966200Smx205022 if (result < 0 || result > 10000) { 19976200Smx205022 err = EINVAL; 19986200Smx205022 } else { 19996200Smx205022 ngep->param_poll_quiet_time = (uint32_t)result; 20006200Smx205022 goto reprogram; 20016200Smx205022 } 20026200Smx205022 return (err); 20036200Smx205022 } 20046200Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 20056200Smx205022 if (pr_val == NULL) { 20066200Smx205022 err = EINVAL; 20076200Smx205022 return (err); 20086200Smx205022 } 20096200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20106200Smx205022 if (result < 0 || result > 10000) { 20116200Smx205022 err = EINVAL; 20126200Smx205022 } else { 20136200Smx205022 ngep->param_poll_busy_time = (uint32_t)result; 20146200Smx205022 goto reprogram; 20156200Smx205022 } 20166200Smx205022 return (err); 20176200Smx205022 } 20186200Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 20196200Smx205022 if (pr_val == NULL) { 20206200Smx205022 err = EINVAL; 20216200Smx205022 return (err); 20226200Smx205022 } 20236200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20246512Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20256200Smx205022 err = EINVAL; 20266200Smx205022 } else { 20276200Smx205022 ngep->param_rx_intr_hwater = (uint32_t)result; 20286200Smx205022 goto reprogram; 20296200Smx205022 } 20306200Smx205022 return (err); 20316200Smx205022 } 20326200Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 20336200Smx205022 if (pr_val == NULL) { 20346200Smx205022 err = EINVAL; 20356200Smx205022 return (err); 20366200Smx205022 } 20376200Smx205022 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 20386512Ssowmini if (result < 0 || result > NGE_RECV_SLOTS_DESC_1024) { 20396200Smx205022 err = EINVAL; 20406200Smx205022 } else { 20416200Smx205022 ngep->param_rx_intr_lwater = (uint32_t)result; 20426200Smx205022 goto reprogram; 20436200Smx205022 } 20446200Smx205022 return (err); 20456200Smx205022 } 20466200Smx205022 err = ENOTSUP; 20476200Smx205022 return (err); 20486200Smx205022 20496200Smx205022 reprogram: 20506200Smx205022 if (err == 0) { 20516200Smx205022 (*ngep->physops->phys_update)(ngep); 20526200Smx205022 nge_chip_sync(ngep); 20536200Smx205022 } 20546200Smx205022 20556200Smx205022 return (err); 20566200Smx205022 } 20576200Smx205022 20586200Smx205022 static int 20596512Ssowmini nge_get_priv_prop(nge_t *ngep, const char *pr_name, uint_t pr_flags, 20606512Ssowmini uint_t pr_valsize, void *pr_val) 20616200Smx205022 { 20626200Smx205022 int err = ENOTSUP; 20636789Sam223141 boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT); 20646512Ssowmini int value; 20656512Ssowmini 20666200Smx205022 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 20676512Ssowmini value = (is_default ? NGE_TX_COPY_SIZE : 20686512Ssowmini ngep->param_txbcopy_threshold); 20696200Smx205022 err = 0; 20706200Smx205022 goto done; 20716200Smx205022 } 20726200Smx205022 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 20736512Ssowmini value = (is_default ? NGE_RX_COPY_SIZE : 20746512Ssowmini ngep->param_rxbcopy_threshold); 20756200Smx205022 err = 0; 20766200Smx205022 goto done; 20776200Smx205022 } 20786200Smx205022 if (strcmp(pr_name, "_recv_max_packet") == 0) { 20796512Ssowmini value = (is_default ? 128 : ngep->param_recv_max_packet); 20806200Smx205022 err = 0; 20816200Smx205022 goto done; 20826200Smx205022 } 20836200Smx205022 if (strcmp(pr_name, "_poll_quiet_time") == 0) { 20846512Ssowmini value = (is_default ? NGE_POLL_QUIET_TIME : 20856512Ssowmini ngep->param_poll_quiet_time); 20866200Smx205022 err = 0; 20876200Smx205022 goto done; 20886200Smx205022 } 20896200Smx205022 if (strcmp(pr_name, "_poll_busy_time") == 0) { 20906512Ssowmini value = (is_default ? NGE_POLL_BUSY_TIME : 20916512Ssowmini ngep->param_poll_busy_time); 20926200Smx205022 err = 0; 20936200Smx205022 goto done; 20946200Smx205022 } 20956200Smx205022 if (strcmp(pr_name, "_rx_intr_hwater") == 0) { 20966512Ssowmini value = (is_default ? 1 : ngep->param_rx_intr_hwater); 20976200Smx205022 err = 0; 20986200Smx205022 goto done; 20996200Smx205022 } 21006200Smx205022 if (strcmp(pr_name, "_rx_intr_lwater") == 0) { 21016512Ssowmini value = (is_default ? 8 : ngep->param_rx_intr_lwater); 21026200Smx205022 err = 0; 21036200Smx205022 goto done; 21046200Smx205022 } 21056200Smx205022 21066200Smx205022 done: 21076200Smx205022 if (err == 0) { 21086512Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 21096200Smx205022 } 21106200Smx205022 return (err); 21116200Smx205022 } 21126200Smx205022 21135574Smx205022 /* ARGSUSED */ 21145574Smx205022 static boolean_t 21155574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 21165574Smx205022 { 21175574Smx205022 nge_t *ngep = arg; 21185574Smx205022 nge_dev_spec_param_t *dev_param_p; 21195574Smx205022 21205574Smx205022 dev_param_p = &ngep->dev_spec_param; 21215574Smx205022 21225574Smx205022 switch (cap) { 21235574Smx205022 case MAC_CAPAB_HCKSUM: { 21245574Smx205022 uint32_t *hcksum_txflags = cap_data; 21255574Smx205022 21265574Smx205022 if (dev_param_p->tx_hw_checksum) { 21275574Smx205022 *hcksum_txflags = dev_param_p->tx_hw_checksum; 21285574Smx205022 } else 21295574Smx205022 return (B_FALSE); 21305574Smx205022 break; 21315574Smx205022 } 21325574Smx205022 default: 21335574Smx205022 return (B_FALSE); 21345574Smx205022 } 21355574Smx205022 return (B_TRUE); 21365574Smx205022 } 21375574Smx205022 21385574Smx205022 #undef NGE_DBG 21395574Smx205022 #define NGE_DBG NGE_DBG_INIT /* debug flag for this code */ 21405574Smx205022 int 21415574Smx205022 nge_restart(nge_t *ngep) 21425574Smx205022 { 21435574Smx205022 int err = 0; 21447656SSherry.Moore@Sun.COM err = nge_reset_dev(ngep); 21457155Smx205022 /* write back the promisc setting */ 21467155Smx205022 ngep->promisc = ngep->record_promisc; 21476366Smx205022 nge_chip_sync(ngep); 21485869Smx205022 if (!err) 21495869Smx205022 err = nge_chip_start(ngep); 21505574Smx205022 21515574Smx205022 if (err) { 21525574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 21535574Smx205022 return (DDI_FAILURE); 21545574Smx205022 } else { 21555574Smx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 21565574Smx205022 return (DDI_SUCCESS); 21575574Smx205022 } 21585574Smx205022 } 21595574Smx205022 21605574Smx205022 void 21615574Smx205022 nge_wake_factotum(nge_t *ngep) 21625574Smx205022 { 21635574Smx205022 mutex_enter(ngep->softlock); 21645574Smx205022 if (ngep->factotum_flag == 0) { 21655574Smx205022 ngep->factotum_flag = 1; 21665574Smx205022 (void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL); 21675574Smx205022 } 21685574Smx205022 mutex_exit(ngep->softlock); 21695574Smx205022 } 21705574Smx205022 2171*10615SZhen.W@Sun.COM void 2172*10615SZhen.W@Sun.COM nge_interrupt_optimize(nge_t *ngep) 2173*10615SZhen.W@Sun.COM { 2174*10615SZhen.W@Sun.COM uint32_t tx_pkts; 2175*10615SZhen.W@Sun.COM tx_pkts = ngep->statistics.sw_statistics.xmit_count - ngep->tpkts_last; 2176*10615SZhen.W@Sun.COM ngep->tpkts_last = ngep->statistics.sw_statistics.xmit_count; 2177*10615SZhen.W@Sun.COM if ((tx_pkts > NGE_POLL_TUNE) && 2178*10615SZhen.W@Sun.COM (tx_pkts <= NGE_POLL_MAX)) 2179*10615SZhen.W@Sun.COM ngep->tfint_threshold = (tx_pkts / NGE_POLL_ENTER); 2180*10615SZhen.W@Sun.COM else 2181*10615SZhen.W@Sun.COM ngep->tfint_threshold = NGE_TFINT_DEFAULT; 2182*10615SZhen.W@Sun.COM } 2183*10615SZhen.W@Sun.COM 21845574Smx205022 /* 21855574Smx205022 * High-level cyclic handler 21865574Smx205022 * 21875574Smx205022 * This routine schedules a (low-level) softint callback to the 21885574Smx205022 * factotum. 21895574Smx205022 */ 21905574Smx205022 21915574Smx205022 static void 21925574Smx205022 nge_chip_cyclic(void *arg) 21935574Smx205022 { 21945574Smx205022 nge_t *ngep; 21955574Smx205022 21965574Smx205022 ngep = (nge_t *)arg; 21975574Smx205022 21985574Smx205022 switch (ngep->nge_chip_state) { 21995574Smx205022 default: 22005574Smx205022 return; 22015574Smx205022 22025574Smx205022 case NGE_CHIP_RUNNING: 2203*10615SZhen.W@Sun.COM nge_interrupt_optimize(ngep); 22045574Smx205022 break; 22055574Smx205022 22065574Smx205022 case NGE_CHIP_FAULT: 22075574Smx205022 case NGE_CHIP_ERROR: 22085574Smx205022 break; 22095574Smx205022 } 22105574Smx205022 22115574Smx205022 nge_wake_factotum(ngep); 22125574Smx205022 } 22135574Smx205022 22149604SZhen.W@Sun.COM /* 22159604SZhen.W@Sun.COM * Get/Release semaphore of SMU 22169604SZhen.W@Sun.COM * For SMU enabled chipset 22179604SZhen.W@Sun.COM * When nge driver is attached, driver should acquire 22189604SZhen.W@Sun.COM * semaphore before PHY init and accessing MAC registers. 22199604SZhen.W@Sun.COM * When nge driver is unattached, driver should release 22209604SZhen.W@Sun.COM * semaphore. 22219604SZhen.W@Sun.COM */ 22229604SZhen.W@Sun.COM 22239604SZhen.W@Sun.COM static int 22249604SZhen.W@Sun.COM nge_smu_sema(nge_t *ngep, boolean_t acquire) 22259604SZhen.W@Sun.COM { 22269604SZhen.W@Sun.COM nge_tx_en tx_en; 22279604SZhen.W@Sun.COM uint32_t tries; 22289604SZhen.W@Sun.COM 22299604SZhen.W@Sun.COM if (acquire) { 22309604SZhen.W@Sun.COM for (tries = 0; tries < 5; tries++) { 22319604SZhen.W@Sun.COM tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 22329604SZhen.W@Sun.COM if (tx_en.bits.smu2mac == NGE_SMU_FREE) 22339604SZhen.W@Sun.COM break; 22349604SZhen.W@Sun.COM delay(drv_usectohz(1000000)); 22359604SZhen.W@Sun.COM } 22369604SZhen.W@Sun.COM if (tx_en.bits.smu2mac != NGE_SMU_FREE) 22379604SZhen.W@Sun.COM return (DDI_FAILURE); 22389604SZhen.W@Sun.COM for (tries = 0; tries < 5; tries++) { 22399604SZhen.W@Sun.COM tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 22409604SZhen.W@Sun.COM tx_en.bits.mac2smu = NGE_SMU_GET; 22419604SZhen.W@Sun.COM nge_reg_put32(ngep, NGE_TX_EN, tx_en.val); 22429604SZhen.W@Sun.COM tx_en.val = nge_reg_get32(ngep, NGE_TX_EN); 22439604SZhen.W@Sun.COM 22449604SZhen.W@Sun.COM if (tx_en.bits.mac2smu == NGE_SMU_GET && 22459604SZhen.W@Sun.COM tx_en.bits.smu2mac == NGE_SMU_FREE) 22469604SZhen.W@Sun.COM return (DDI_SUCCESS); 22479604SZhen.W@Sun.COM drv_usecwait(10); 22489604SZhen.W@Sun.COM } 22499604SZhen.W@Sun.COM return (DDI_FAILURE); 22509604SZhen.W@Sun.COM } else 22519604SZhen.W@Sun.COM nge_reg_put32(ngep, NGE_TX_EN, 0x0); 22529604SZhen.W@Sun.COM 22539604SZhen.W@Sun.COM return (DDI_SUCCESS); 22549604SZhen.W@Sun.COM 22559604SZhen.W@Sun.COM } 22565574Smx205022 static void 22575574Smx205022 nge_unattach(nge_t *ngep) 22585574Smx205022 { 22595574Smx205022 send_ring_t *srp; 22605574Smx205022 buff_ring_t *brp; 22615574Smx205022 22625574Smx205022 srp = ngep->send; 22635574Smx205022 brp = ngep->buff; 22645574Smx205022 NGE_TRACE(("nge_unattach($%p)", (void *)ngep)); 22655574Smx205022 22665574Smx205022 /* 22675574Smx205022 * Flag that no more activity may be initiated 22685574Smx205022 */ 22695574Smx205022 ngep->progress &= ~PROGRESS_READY; 22705574Smx205022 ngep->nge_mac_state = NGE_MAC_UNATTACH; 22715574Smx205022 22725574Smx205022 /* 22735574Smx205022 * Quiesce the PHY and MAC (leave it reset but still powered). 22745574Smx205022 * Clean up and free all NGE data structures 22755574Smx205022 */ 22765574Smx205022 if (ngep->periodic_id != NULL) { 22775574Smx205022 ddi_periodic_delete(ngep->periodic_id); 22785574Smx205022 ngep->periodic_id = NULL; 22795574Smx205022 } 22805574Smx205022 22815574Smx205022 if (ngep->progress & PROGRESS_KSTATS) 22825574Smx205022 nge_fini_kstats(ngep); 22835574Smx205022 22845574Smx205022 if (ngep->progress & PROGRESS_HWINT) { 22855574Smx205022 mutex_enter(ngep->genlock); 22865574Smx205022 nge_restore_mac_addr(ngep); 22875574Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 22889604SZhen.W@Sun.COM if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 22899604SZhen.W@Sun.COM ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 22909604SZhen.W@Sun.COM (void) nge_smu_sema(ngep, B_FALSE); 22919604SZhen.W@Sun.COM } 22925574Smx205022 mutex_exit(ngep->genlock); 22935574Smx205022 } 22945574Smx205022 22955574Smx205022 if (ngep->progress & PROGRESS_SWINT) 22965574Smx205022 nge_rem_intrs(ngep); 22975574Smx205022 22985574Smx205022 if (ngep->progress & PROGRESS_FACTOTUM) 22995574Smx205022 (void) ddi_intr_remove_softint(ngep->factotum_hdl); 23005574Smx205022 23015574Smx205022 if (ngep->progress & PROGRESS_RESCHED) 23025574Smx205022 (void) ddi_intr_remove_softint(ngep->resched_hdl); 23035574Smx205022 23045574Smx205022 if (ngep->progress & PROGRESS_INTR) { 23055574Smx205022 mutex_destroy(srp->tx_lock); 23065574Smx205022 mutex_destroy(srp->tc_lock); 23075574Smx205022 mutex_destroy(&srp->dmah_lock); 23085574Smx205022 mutex_destroy(brp->recycle_lock); 23095574Smx205022 23105574Smx205022 mutex_destroy(ngep->genlock); 23115574Smx205022 mutex_destroy(ngep->softlock); 23125574Smx205022 rw_destroy(ngep->rwlock); 23135574Smx205022 } 23145574Smx205022 23155574Smx205022 if (ngep->progress & PROGRESS_REGS) 23165574Smx205022 ddi_regs_map_free(&ngep->io_handle); 23175574Smx205022 23185574Smx205022 if (ngep->progress & PROGRESS_CFG) 23195574Smx205022 pci_config_teardown(&ngep->cfg_handle); 23205574Smx205022 23215574Smx205022 ddi_remove_minor_node(ngep->devinfo, NULL); 23225574Smx205022 23235574Smx205022 kmem_free(ngep, sizeof (*ngep)); 23245574Smx205022 } 23255574Smx205022 23265574Smx205022 static int 23275574Smx205022 nge_resume(dev_info_t *devinfo) 23285574Smx205022 { 23295574Smx205022 nge_t *ngep; 23305574Smx205022 chip_info_t *infop; 23315869Smx205022 int err; 23325574Smx205022 23335574Smx205022 ASSERT(devinfo != NULL); 23345574Smx205022 23355574Smx205022 ngep = ddi_get_driver_private(devinfo); 23365869Smx205022 err = 0; 23375869Smx205022 23385574Smx205022 /* 23395574Smx205022 * If there are state inconsistancies, this is bad. Returning 23405574Smx205022 * DDI_FAILURE here will eventually cause the machine to panic, 23415574Smx205022 * so it is best done here so that there is a possibility of 23425574Smx205022 * debugging the problem. 23435574Smx205022 */ 23445574Smx205022 if (ngep == NULL) 23455574Smx205022 cmn_err(CE_PANIC, 23465574Smx205022 "nge: ngep returned from ddi_get_driver_private was NULL"); 23475574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 23485574Smx205022 23495574Smx205022 if (ngep->devinfo != devinfo) 23505574Smx205022 cmn_err(CE_PANIC, 23515869Smx205022 "nge: passed devinfo not the same as saved devinfo"); 23525574Smx205022 23535869Smx205022 mutex_enter(ngep->genlock); 23545869Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 23555574Smx205022 23565574Smx205022 /* 23575574Smx205022 * Fetch the config space. Even though we have most of it cached, 23585574Smx205022 * some values *might* change across a suspend/resume. 23595574Smx205022 */ 23605574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 23615574Smx205022 23625574Smx205022 /* 23635869Smx205022 * Only in one case, this conditional branch can be executed: the port 23645869Smx205022 * hasn't been plumbed. 23655574Smx205022 */ 23665869Smx205022 if (ngep->suspended == B_FALSE) { 23675869Smx205022 rw_exit(ngep->rwlock); 23685869Smx205022 mutex_exit(ngep->genlock); 23695869Smx205022 return (DDI_SUCCESS); 23705869Smx205022 } 23715869Smx205022 23725869Smx205022 nge_tx_recycle_all(ngep); 23735869Smx205022 err = nge_reinit_ring(ngep); 23745869Smx205022 if (!err) { 23755869Smx205022 err = nge_chip_reset(ngep); 23765869Smx205022 if (!err) 23775869Smx205022 err = nge_chip_start(ngep); 23785869Smx205022 } 23795869Smx205022 23805869Smx205022 if (err) { 23815574Smx205022 /* 23825574Smx205022 * We note the failure, but return success, as the 23835574Smx205022 * system is still usable without this controller. 23845574Smx205022 */ 23855574Smx205022 cmn_err(CE_WARN, "nge: resume: failed to restart controller"); 23865869Smx205022 } else { 23875869Smx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 23885574Smx205022 } 23895869Smx205022 ngep->suspended = B_FALSE; 23905869Smx205022 23915869Smx205022 rw_exit(ngep->rwlock); 23925869Smx205022 mutex_exit(ngep->genlock); 23935869Smx205022 23945574Smx205022 return (DDI_SUCCESS); 23955574Smx205022 } 23965574Smx205022 23975574Smx205022 /* 23985574Smx205022 * attach(9E) -- Attach a device to the system 23995574Smx205022 * 24005574Smx205022 * Called once for each board successfully probed. 24015574Smx205022 */ 24025574Smx205022 static int 24035574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 24045574Smx205022 { 24055574Smx205022 int err; 24065574Smx205022 int i; 24075574Smx205022 int instance; 24085574Smx205022 caddr_t regs; 24095574Smx205022 nge_t *ngep; 24105574Smx205022 chip_info_t *infop; 24115574Smx205022 mac_register_t *macp; 24125574Smx205022 24135574Smx205022 switch (cmd) { 24145574Smx205022 default: 24155574Smx205022 return (DDI_FAILURE); 24165574Smx205022 24175574Smx205022 case DDI_RESUME: 24185574Smx205022 return (nge_resume(devinfo)); 24195574Smx205022 24205574Smx205022 case DDI_ATTACH: 24215574Smx205022 break; 24225574Smx205022 } 24235574Smx205022 24245574Smx205022 ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP); 24255574Smx205022 instance = ddi_get_instance(devinfo); 24265574Smx205022 ddi_set_driver_private(devinfo, ngep); 24275574Smx205022 ngep->devinfo = devinfo; 24285574Smx205022 24295574Smx205022 (void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d", 24305574Smx205022 NGE_DRIVER_NAME, instance); 24315574Smx205022 err = pci_config_setup(devinfo, &ngep->cfg_handle); 24325574Smx205022 if (err != DDI_SUCCESS) { 24335574Smx205022 nge_problem(ngep, "nge_attach: pci_config_setup() failed"); 24345574Smx205022 goto attach_fail; 24355574Smx205022 } 24366512Ssowmini /* 24376512Ssowmini * param_txbcopy_threshold and param_rxbcopy_threshold are tx/rx bcopy 24386512Ssowmini * thresholds. Bounds: min 0, max NGE_MAX_SDU 24396512Ssowmini */ 24406512Ssowmini ngep->param_txbcopy_threshold = NGE_TX_COPY_SIZE; 24416512Ssowmini ngep->param_rxbcopy_threshold = NGE_RX_COPY_SIZE; 24426512Ssowmini 24436512Ssowmini /* 24446512Ssowmini * param_recv_max_packet is max packet received per interupt. 24456512Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024 24466512Ssowmini */ 24476512Ssowmini ngep->param_recv_max_packet = 128; 24486512Ssowmini 24496512Ssowmini /* 24506512Ssowmini * param_poll_quiet_time and param_poll_busy_time are quiet/busy time 24516512Ssowmini * switch from per packet interrupt to polling interrupt. 24526512Ssowmini * Bounds: min 0, max 10000 24536512Ssowmini */ 24546512Ssowmini ngep->param_poll_quiet_time = NGE_POLL_QUIET_TIME; 24556512Ssowmini ngep->param_poll_busy_time = NGE_POLL_BUSY_TIME; 2456*10615SZhen.W@Sun.COM ngep->tfint_threshold = NGE_TFINT_DEFAULT; 2457*10615SZhen.W@Sun.COM ngep->poll = B_FALSE; 2458*10615SZhen.W@Sun.COM ngep->ch_intr_mode = B_FALSE; 24596512Ssowmini 24606512Ssowmini /* 24616512Ssowmini * param_rx_intr_hwater/param_rx_intr_lwater: ackets received 24626512Ssowmini * to trigger the poll_quiet_time/poll_busy_time counter. 24636512Ssowmini * Bounds: min 0, max NGE_RECV_SLOTS_DESC_1024. 24646512Ssowmini */ 24656512Ssowmini ngep->param_rx_intr_hwater = 1; 24666512Ssowmini ngep->param_rx_intr_lwater = 8; 24676512Ssowmini 24686512Ssowmini 24695574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 24705574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 24715574Smx205022 nge_init_dev_spec_param(ngep); 24725574Smx205022 nge_get_props(ngep); 24735574Smx205022 ngep->progress |= PROGRESS_CFG; 24745574Smx205022 24755574Smx205022 err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER, 24765574Smx205022 ®s, 0, 0, &nge_reg_accattr, &ngep->io_handle); 24775574Smx205022 if (err != DDI_SUCCESS) { 24785574Smx205022 nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed"); 24795574Smx205022 goto attach_fail; 24805574Smx205022 } 24815574Smx205022 ngep->io_regs = regs; 24825574Smx205022 ngep->progress |= PROGRESS_REGS; 24835574Smx205022 24845574Smx205022 err = nge_register_intrs_and_init_locks(ngep); 24855574Smx205022 if (err != DDI_SUCCESS) { 24865574Smx205022 nge_problem(ngep, "nge_attach:" 24875574Smx205022 " register intrs and init locks failed"); 24885574Smx205022 goto attach_fail; 24895574Smx205022 } 24905574Smx205022 nge_init_ring_param_lock(ngep); 24915574Smx205022 ngep->progress |= PROGRESS_INTR; 24925574Smx205022 24935574Smx205022 mutex_enter(ngep->genlock); 24945574Smx205022 24959604SZhen.W@Sun.COM if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 24969604SZhen.W@Sun.COM ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 24979604SZhen.W@Sun.COM err = nge_smu_sema(ngep, B_TRUE); 24989604SZhen.W@Sun.COM if (err != DDI_SUCCESS) { 24999604SZhen.W@Sun.COM nge_problem(ngep, "nge_attach: nge_smu_sema() failed"); 25009604SZhen.W@Sun.COM goto attach_fail; 25019604SZhen.W@Sun.COM } 25029604SZhen.W@Sun.COM } 25035574Smx205022 /* 25045574Smx205022 * Initialise link state variables 25055574Smx205022 * Stop, reset & reinitialise the chip. 25065574Smx205022 * Initialise the (internal) PHY. 25075574Smx205022 */ 25085574Smx205022 nge_phys_init(ngep); 25098218SMin.Xu@Sun.COM ngep->nge_chip_state = NGE_CHIP_INITIAL; 25105574Smx205022 err = nge_chip_reset(ngep); 25115574Smx205022 if (err != DDI_SUCCESS) { 25125574Smx205022 nge_problem(ngep, "nge_attach: nge_chip_reset() failed"); 25135574Smx205022 mutex_exit(ngep->genlock); 25145574Smx205022 goto attach_fail; 25155574Smx205022 } 25165574Smx205022 nge_chip_sync(ngep); 25175574Smx205022 25185574Smx205022 /* 25195574Smx205022 * Now that mutex locks are initialized, enable interrupts. 25205574Smx205022 */ 25215574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 25225574Smx205022 /* Call ddi_intr_block_enable() for MSI interrupts */ 25235574Smx205022 (void) ddi_intr_block_enable(ngep->htable, 25245574Smx205022 ngep->intr_actual_cnt); 25255574Smx205022 } else { 25265574Smx205022 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 25275574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 25285574Smx205022 (void) ddi_intr_enable(ngep->htable[i]); 25295574Smx205022 } 25305574Smx205022 } 25315574Smx205022 25325574Smx205022 ngep->link_state = LINK_STATE_UNKNOWN; 25335574Smx205022 ngep->progress |= PROGRESS_HWINT; 25345574Smx205022 25355574Smx205022 /* 25365574Smx205022 * Register NDD-tweakable parameters 25375574Smx205022 */ 25385574Smx205022 if (nge_nd_init(ngep)) { 25395574Smx205022 nge_problem(ngep, "nge_attach: nge_nd_init() failed"); 25405574Smx205022 mutex_exit(ngep->genlock); 25415574Smx205022 goto attach_fail; 25425574Smx205022 } 25435574Smx205022 ngep->progress |= PROGRESS_NDD; 25445574Smx205022 25455574Smx205022 /* 25465574Smx205022 * Create & initialise named kstats 25475574Smx205022 */ 25485574Smx205022 nge_init_kstats(ngep, instance); 25495574Smx205022 ngep->progress |= PROGRESS_KSTATS; 25505574Smx205022 25515574Smx205022 mutex_exit(ngep->genlock); 25525574Smx205022 25535574Smx205022 if ((macp = mac_alloc(MAC_VERSION)) == NULL) 25545574Smx205022 goto attach_fail; 25555574Smx205022 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 25565574Smx205022 macp->m_driver = ngep; 25575574Smx205022 macp->m_dip = devinfo; 25585574Smx205022 macp->m_src_addr = infop->vendor_addr.addr; 25595574Smx205022 macp->m_callbacks = &nge_m_callbacks; 25605574Smx205022 macp->m_min_sdu = 0; 25615574Smx205022 macp->m_max_sdu = ngep->default_mtu; 25625895Syz147064 macp->m_margin = VTAG_SIZE; 25636512Ssowmini macp->m_priv_props = nge_priv_props; 25646512Ssowmini macp->m_priv_prop_count = NGE_MAX_PRIV_PROPS; 25655574Smx205022 /* 25665574Smx205022 * Finally, we're ready to register ourselves with the mac 25675574Smx205022 * interface; if this succeeds, we're all ready to start() 25685574Smx205022 */ 25695574Smx205022 err = mac_register(macp, &ngep->mh); 25705574Smx205022 mac_free(macp); 25715574Smx205022 if (err != 0) 25725574Smx205022 goto attach_fail; 25735574Smx205022 25745574Smx205022 /* 25755574Smx205022 * Register a periodical handler. 25765574Smx205022 * nge_chip_cyclic() is invoked in kernel context. 25775574Smx205022 */ 25785574Smx205022 ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep, 25795574Smx205022 NGE_CYCLIC_PERIOD, DDI_IPL_0); 25805574Smx205022 25815574Smx205022 ngep->progress |= PROGRESS_READY; 25825574Smx205022 return (DDI_SUCCESS); 25835574Smx205022 25845574Smx205022 attach_fail: 25855574Smx205022 nge_unattach(ngep); 25865574Smx205022 return (DDI_FAILURE); 25875574Smx205022 } 25885574Smx205022 25895869Smx205022 static int 25905869Smx205022 nge_suspend(nge_t *ngep) 25915869Smx205022 { 25925869Smx205022 mutex_enter(ngep->genlock); 25935869Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 25945869Smx205022 25955869Smx205022 /* if the port hasn't been plumbed, just return */ 25965869Smx205022 if (ngep->nge_mac_state != NGE_MAC_STARTED) { 25975869Smx205022 rw_exit(ngep->rwlock); 25985869Smx205022 mutex_exit(ngep->genlock); 25995869Smx205022 return (DDI_SUCCESS); 26005869Smx205022 } 26015869Smx205022 ngep->suspended = B_TRUE; 26025869Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 26035869Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 26045869Smx205022 26055869Smx205022 rw_exit(ngep->rwlock); 26065869Smx205022 mutex_exit(ngep->genlock); 26075869Smx205022 return (DDI_SUCCESS); 26085869Smx205022 } 26095869Smx205022 26105574Smx205022 /* 26115574Smx205022 * detach(9E) -- Detach a device from the system 26125574Smx205022 */ 26135574Smx205022 static int 26145574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 26155574Smx205022 { 26165574Smx205022 int i; 26175574Smx205022 nge_t *ngep; 26185574Smx205022 mul_item *p, *nextp; 26195574Smx205022 buff_ring_t *brp; 26205574Smx205022 26215574Smx205022 NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd)); 26225574Smx205022 26235574Smx205022 ngep = ddi_get_driver_private(devinfo); 26245574Smx205022 brp = ngep->buff; 26255574Smx205022 26265574Smx205022 switch (cmd) { 26275574Smx205022 default: 26285574Smx205022 return (DDI_FAILURE); 26295574Smx205022 26305574Smx205022 case DDI_SUSPEND: 26315574Smx205022 /* 26325574Smx205022 * Stop the NIC 26335574Smx205022 * Note: This driver doesn't currently support WOL, but 26345574Smx205022 * should it in the future, it is important to 26355574Smx205022 * make sure the PHY remains powered so that the 26365574Smx205022 * wakeup packet can actually be recieved. 26375574Smx205022 */ 26385869Smx205022 return (nge_suspend(ngep)); 26395574Smx205022 26405574Smx205022 case DDI_DETACH: 26415574Smx205022 break; 26425574Smx205022 } 26435574Smx205022 26445574Smx205022 /* Try to wait all the buffer post to upper layer be released */ 26455574Smx205022 for (i = 0; i < 1000; i++) { 26465574Smx205022 if (brp->rx_hold == 0) 26475574Smx205022 break; 26485574Smx205022 drv_usecwait(1000); 26495574Smx205022 } 26505574Smx205022 26515574Smx205022 /* If there is any posted buffer, reject to detach */ 26525574Smx205022 if (brp->rx_hold != 0) 26535574Smx205022 return (DDI_FAILURE); 26545574Smx205022 26555574Smx205022 /* 26565574Smx205022 * Unregister from the GLD subsystem. This can fail, in 26575574Smx205022 * particular if there are DLPI style-2 streams still open - 26585574Smx205022 * in which case we just return failure without shutting 26595574Smx205022 * down chip operations. 26605574Smx205022 */ 26615574Smx205022 if (mac_unregister(ngep->mh) != DDI_SUCCESS) 26625574Smx205022 return (DDI_FAILURE); 26635574Smx205022 26645574Smx205022 /* 26656366Smx205022 * Recycle the multicast table. mac_unregister() should be called 26666366Smx205022 * before it to ensure the multicast table can be used even if 26676366Smx205022 * mac_unregister() fails. 26686366Smx205022 */ 26696366Smx205022 for (p = ngep->pcur_mulist; p != NULL; p = nextp) { 26706366Smx205022 nextp = p->next; 26716366Smx205022 kmem_free(p, sizeof (mul_item)); 26726366Smx205022 } 26736366Smx205022 ngep->pcur_mulist = NULL; 26746366Smx205022 26756366Smx205022 /* 26765574Smx205022 * All activity stopped, so we can clean up & exit 26775574Smx205022 */ 26785574Smx205022 nge_unattach(ngep); 26795574Smx205022 return (DDI_SUCCESS); 26805574Smx205022 } 26815574Smx205022 26827656SSherry.Moore@Sun.COM /* 26837656SSherry.Moore@Sun.COM * quiesce(9E) entry point. 26847656SSherry.Moore@Sun.COM * 26857656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high 26867656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 26877656SSherry.Moore@Sun.COM * blocked. 26887656SSherry.Moore@Sun.COM * 26897656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 26907656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 26917656SSherry.Moore@Sun.COM */ 26927656SSherry.Moore@Sun.COM static int 26937656SSherry.Moore@Sun.COM nge_quiesce(dev_info_t *devinfo) 26947656SSherry.Moore@Sun.COM { 26957656SSherry.Moore@Sun.COM nge_t *ngep; 26967656SSherry.Moore@Sun.COM 26977656SSherry.Moore@Sun.COM ngep = ddi_get_driver_private(devinfo); 26987656SSherry.Moore@Sun.COM 26997656SSherry.Moore@Sun.COM if (ngep == NULL) 27007656SSherry.Moore@Sun.COM return (DDI_FAILURE); 27017656SSherry.Moore@Sun.COM 27027656SSherry.Moore@Sun.COM /* 27037656SSherry.Moore@Sun.COM * Turn off debug tracing 27047656SSherry.Moore@Sun.COM */ 27057656SSherry.Moore@Sun.COM nge_debug = 0; 27067656SSherry.Moore@Sun.COM ngep->debug = 0; 27077656SSherry.Moore@Sun.COM 27087656SSherry.Moore@Sun.COM nge_restore_mac_addr(ngep); 27097656SSherry.Moore@Sun.COM (void) nge_chip_stop(ngep, B_FALSE); 27107656SSherry.Moore@Sun.COM 27117656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 27127656SSherry.Moore@Sun.COM } 27137656SSherry.Moore@Sun.COM 27147656SSherry.Moore@Sun.COM 27155574Smx205022 27165574Smx205022 /* 27175574Smx205022 * ========== Module Loading Data & Entry Points ========== 27185574Smx205022 */ 27195574Smx205022 27205574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach, 27217656SSherry.Moore@Sun.COM NULL, NULL, D_MP, NULL, nge_quiesce); 27225574Smx205022 27235574Smx205022 27245574Smx205022 static struct modldrv nge_modldrv = { 27255574Smx205022 &mod_driverops, /* Type of module. This one is a driver */ 27265574Smx205022 nge_ident, /* short description */ 27275574Smx205022 &nge_dev_ops /* driver specific ops */ 27285574Smx205022 }; 27295574Smx205022 27305574Smx205022 static struct modlinkage modlinkage = { 27315574Smx205022 MODREV_1, (void *)&nge_modldrv, NULL 27325574Smx205022 }; 27335574Smx205022 27345574Smx205022 27355574Smx205022 int 27365574Smx205022 _info(struct modinfo *modinfop) 27375574Smx205022 { 27385574Smx205022 return (mod_info(&modlinkage, modinfop)); 27395574Smx205022 } 27405574Smx205022 27415574Smx205022 int 27425574Smx205022 _init(void) 27435574Smx205022 { 27445574Smx205022 int status; 27455574Smx205022 27465574Smx205022 mac_init_ops(&nge_dev_ops, "nge"); 27475574Smx205022 status = mod_install(&modlinkage); 27485574Smx205022 if (status != DDI_SUCCESS) 27495574Smx205022 mac_fini_ops(&nge_dev_ops); 27505574Smx205022 else 27515574Smx205022 mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL); 27525574Smx205022 27535574Smx205022 return (status); 27545574Smx205022 } 27555574Smx205022 27565574Smx205022 int 27575574Smx205022 _fini(void) 27585574Smx205022 { 27595574Smx205022 int status; 27605574Smx205022 27615574Smx205022 status = mod_remove(&modlinkage); 27625574Smx205022 if (status == DDI_SUCCESS) { 27635574Smx205022 mac_fini_ops(&nge_dev_ops); 27645574Smx205022 mutex_destroy(nge_log_mutex); 27655574Smx205022 } 27665574Smx205022 27675574Smx205022 return (status); 27685574Smx205022 } 27695574Smx205022 27705574Smx205022 /* 27715574Smx205022 * ============ Init MSI/Fixed/SoftInterrupt routines ============== 27725574Smx205022 */ 27735574Smx205022 27745574Smx205022 /* 27755574Smx205022 * Register interrupts and initialize each mutex and condition variables 27765574Smx205022 */ 27775574Smx205022 27785574Smx205022 static int 27795574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep) 27805574Smx205022 { 27815574Smx205022 int err; 27825574Smx205022 int intr_types; 27835574Smx205022 uint_t soft_prip; 27845574Smx205022 nge_msi_mask msi_mask; 27855574Smx205022 nge_msi_map0_vec map0_vec; 27865574Smx205022 nge_msi_map1_vec map1_vec; 27875574Smx205022 27885574Smx205022 /* 27895574Smx205022 * Add the softint handlers: 27905574Smx205022 * 27915574Smx205022 * Both of these handlers are used to avoid restrictions on the 27925574Smx205022 * context and/or mutexes required for some operations. In 27935574Smx205022 * particular, the hardware interrupt handler and its subfunctions 27945574Smx205022 * can detect a number of conditions that we don't want to handle 27955574Smx205022 * in that context or with that set of mutexes held. So, these 27965574Smx205022 * softints are triggered instead: 27975574Smx205022 * 27985574Smx205022 * the <resched> softint is triggered if if we have previously 27995574Smx205022 * had to refuse to send a packet because of resource shortage 28005574Smx205022 * (we've run out of transmit buffers), but the send completion 28015574Smx205022 * interrupt handler has now detected that more buffers have 28025574Smx205022 * become available. Its only purpose is to call gld_sched() 28035574Smx205022 * to retry the pending transmits (we're not allowed to hold 28045574Smx205022 * driver-defined mutexes across gld_sched()). 28055574Smx205022 * 28065574Smx205022 * the <factotum> is triggered if the h/w interrupt handler 28075574Smx205022 * sees the <link state changed> or <error> bits in the status 28085574Smx205022 * block. It's also triggered periodically to poll the link 28095574Smx205022 * state, just in case we aren't getting link status change 28105574Smx205022 * interrupts ... 28115574Smx205022 */ 28125574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl, 28135574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep); 28145574Smx205022 if (err != DDI_SUCCESS) { 28155574Smx205022 nge_problem(ngep, 28165574Smx205022 "nge_attach: add nge_reschedule softintr failed"); 28175574Smx205022 28185574Smx205022 return (DDI_FAILURE); 28195574Smx205022 } 28205574Smx205022 ngep->progress |= PROGRESS_RESCHED; 28215574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl, 28225574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep); 28235574Smx205022 if (err != DDI_SUCCESS) { 28245574Smx205022 nge_problem(ngep, 28255574Smx205022 "nge_attach: add nge_chip_factotum softintr failed!"); 28265574Smx205022 28275574Smx205022 return (DDI_FAILURE); 28285574Smx205022 } 28295574Smx205022 if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip) 28305574Smx205022 != DDI_SUCCESS) { 28315574Smx205022 nge_problem(ngep, "nge_attach: get softintr priority failed\n"); 28325574Smx205022 28335574Smx205022 return (DDI_FAILURE); 28345574Smx205022 } 28355574Smx205022 ngep->soft_pri = soft_prip; 28365574Smx205022 28375574Smx205022 ngep->progress |= PROGRESS_FACTOTUM; 28385574Smx205022 /* Get supported interrupt types */ 28395574Smx205022 if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types) 28405574Smx205022 != DDI_SUCCESS) { 28415574Smx205022 nge_error(ngep, "ddi_intr_get_supported_types failed\n"); 28425574Smx205022 28435574Smx205022 return (DDI_FAILURE); 28445574Smx205022 } 28455574Smx205022 28465574Smx205022 NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x", 28475574Smx205022 intr_types)); 28485574Smx205022 28495574Smx205022 if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) { 28505574Smx205022 28515574Smx205022 /* MSI Configurations for mcp55 chipset */ 28525574Smx205022 if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 28535574Smx205022 ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 28545574Smx205022 28555574Smx205022 28565574Smx205022 /* Enable the 8 vectors */ 28575574Smx205022 msi_mask.msi_mask_val = 28585574Smx205022 nge_reg_get32(ngep, NGE_MSI_MASK); 28595574Smx205022 msi_mask.msi_msk_bits.vec0 = NGE_SET; 28605574Smx205022 msi_mask.msi_msk_bits.vec1 = NGE_SET; 28615574Smx205022 msi_mask.msi_msk_bits.vec2 = NGE_SET; 28625574Smx205022 msi_mask.msi_msk_bits.vec3 = NGE_SET; 28635574Smx205022 msi_mask.msi_msk_bits.vec4 = NGE_SET; 28645574Smx205022 msi_mask.msi_msk_bits.vec5 = NGE_SET; 28655574Smx205022 msi_mask.msi_msk_bits.vec6 = NGE_SET; 28665574Smx205022 msi_mask.msi_msk_bits.vec7 = NGE_SET; 28675574Smx205022 nge_reg_put32(ngep, NGE_MSI_MASK, 28685574Smx205022 msi_mask.msi_mask_val); 28695574Smx205022 28705574Smx205022 /* 28715574Smx205022 * Remapping the MSI MAP0 and MAP1. MCP55 28725574Smx205022 * is default mapping all the interrupt to 0 vector. 28735574Smx205022 * Software needs to remapping this. 28745574Smx205022 * This mapping is same as CK804. 28755574Smx205022 */ 28765574Smx205022 map0_vec.msi_map0_val = 28775574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP0); 28785574Smx205022 map1_vec.msi_map1_val = 28795574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP1); 28805574Smx205022 map0_vec.vecs_bits.reint_vec = 0; 28815574Smx205022 map0_vec.vecs_bits.rcint_vec = 0; 28825574Smx205022 map0_vec.vecs_bits.miss_vec = 3; 28835574Smx205022 map0_vec.vecs_bits.teint_vec = 5; 28845574Smx205022 map0_vec.vecs_bits.tcint_vec = 5; 28855574Smx205022 map0_vec.vecs_bits.stint_vec = 2; 28865574Smx205022 map0_vec.vecs_bits.mint_vec = 6; 28875574Smx205022 map0_vec.vecs_bits.rfint_vec = 0; 28885574Smx205022 map1_vec.vecs_bits.tfint_vec = 5; 28895574Smx205022 map1_vec.vecs_bits.feint_vec = 6; 28905574Smx205022 map1_vec.vecs_bits.resv8_11 = 3; 28915574Smx205022 map1_vec.vecs_bits.resv12_15 = 1; 28925574Smx205022 map1_vec.vecs_bits.resv16_19 = 0; 28935574Smx205022 map1_vec.vecs_bits.resv20_23 = 7; 28945574Smx205022 map1_vec.vecs_bits.resv24_31 = 0xff; 28955574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP0, 28965574Smx205022 map0_vec.msi_map0_val); 28975574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP1, 28985574Smx205022 map1_vec.msi_map1_val); 28995574Smx205022 } 29005574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 29015574Smx205022 NGE_DEBUG(("MSI registration failed, " 29025574Smx205022 "trying FIXED interrupt type\n")); 29035574Smx205022 } else { 29045574Smx205022 nge_log(ngep, "Using MSI interrupt type\n"); 29055574Smx205022 29065574Smx205022 ngep->intr_type = DDI_INTR_TYPE_MSI; 29075574Smx205022 ngep->progress |= PROGRESS_SWINT; 29085574Smx205022 } 29095574Smx205022 } 29105574Smx205022 29115574Smx205022 if (!(ngep->progress & PROGRESS_SWINT) && 29125574Smx205022 (intr_types & DDI_INTR_TYPE_FIXED)) { 29135574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 29145574Smx205022 nge_error(ngep, "FIXED interrupt " 29155574Smx205022 "registration failed\n"); 29165574Smx205022 29175574Smx205022 return (DDI_FAILURE); 29185574Smx205022 } 29195574Smx205022 29205574Smx205022 nge_log(ngep, "Using FIXED interrupt type\n"); 29215574Smx205022 29225574Smx205022 ngep->intr_type = DDI_INTR_TYPE_FIXED; 29235574Smx205022 ngep->progress |= PROGRESS_SWINT; 29245574Smx205022 } 29255574Smx205022 29265574Smx205022 29275574Smx205022 if (!(ngep->progress & PROGRESS_SWINT)) { 29285574Smx205022 nge_error(ngep, "No interrupts registered\n"); 29295574Smx205022 29305574Smx205022 return (DDI_FAILURE); 29315574Smx205022 } 29325574Smx205022 mutex_init(ngep->genlock, NULL, MUTEX_DRIVER, 29335574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 29345574Smx205022 mutex_init(ngep->softlock, NULL, MUTEX_DRIVER, 29355574Smx205022 DDI_INTR_PRI(ngep->soft_pri)); 29365574Smx205022 rw_init(ngep->rwlock, NULL, RW_DRIVER, 29375574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 29385574Smx205022 29395574Smx205022 return (DDI_SUCCESS); 29405574Smx205022 } 29415574Smx205022 29425574Smx205022 /* 29435574Smx205022 * nge_add_intrs: 29445574Smx205022 * 29455574Smx205022 * Register FIXED or MSI interrupts. 29465574Smx205022 */ 29475574Smx205022 static int 29485574Smx205022 nge_add_intrs(nge_t *ngep, int intr_type) 29495574Smx205022 { 29505574Smx205022 dev_info_t *dip = ngep->devinfo; 29515574Smx205022 int avail, actual, intr_size, count = 0; 29525574Smx205022 int i, flag, ret; 29535574Smx205022 29545574Smx205022 NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type)); 29555574Smx205022 29565574Smx205022 /* Get number of interrupts */ 29575574Smx205022 ret = ddi_intr_get_nintrs(dip, intr_type, &count); 29585574Smx205022 if ((ret != DDI_SUCCESS) || (count == 0)) { 29595574Smx205022 nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, " 29605574Smx205022 "count: %d", ret, count); 29615574Smx205022 29625574Smx205022 return (DDI_FAILURE); 29635574Smx205022 } 29645574Smx205022 29655574Smx205022 /* Get number of available interrupts */ 29665574Smx205022 ret = ddi_intr_get_navail(dip, intr_type, &avail); 29675574Smx205022 if ((ret != DDI_SUCCESS) || (avail == 0)) { 29685574Smx205022 nge_error(ngep, "ddi_intr_get_navail() failure, " 29695574Smx205022 "ret: %d, avail: %d\n", ret, avail); 29705574Smx205022 29715574Smx205022 return (DDI_FAILURE); 29725574Smx205022 } 29735574Smx205022 29745574Smx205022 if (avail < count) { 29755574Smx205022 NGE_DEBUG(("nitrs() returned %d, navail returned %d\n", 29765574Smx205022 count, avail)); 29775574Smx205022 } 29785574Smx205022 flag = DDI_INTR_ALLOC_NORMAL; 29795574Smx205022 29805574Smx205022 /* Allocate an array of interrupt handles */ 29815574Smx205022 intr_size = count * sizeof (ddi_intr_handle_t); 29825574Smx205022 ngep->htable = kmem_alloc(intr_size, KM_SLEEP); 29835574Smx205022 29845574Smx205022 /* Call ddi_intr_alloc() */ 29855574Smx205022 ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0, 29865574Smx205022 count, &actual, flag); 29875574Smx205022 29885574Smx205022 if ((ret != DDI_SUCCESS) || (actual == 0)) { 29895574Smx205022 nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret); 29905574Smx205022 29915574Smx205022 kmem_free(ngep->htable, intr_size); 29925574Smx205022 return (DDI_FAILURE); 29935574Smx205022 } 29945574Smx205022 29955574Smx205022 if (actual < count) { 29965574Smx205022 NGE_DEBUG(("Requested: %d, Received: %d\n", 29975574Smx205022 count, actual)); 29985574Smx205022 } 29995574Smx205022 30005574Smx205022 ngep->intr_actual_cnt = actual; 30015574Smx205022 ngep->intr_req_cnt = count; 30025574Smx205022 30035574Smx205022 /* 30045574Smx205022 * Get priority for first msi, assume remaining are all the same 30055574Smx205022 */ 30065574Smx205022 if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) != 30075574Smx205022 DDI_SUCCESS) { 30085574Smx205022 nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret); 30095574Smx205022 30105574Smx205022 /* Free already allocated intr */ 30115574Smx205022 for (i = 0; i < actual; i++) { 30125574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30135574Smx205022 } 30145574Smx205022 30155574Smx205022 kmem_free(ngep->htable, intr_size); 30165574Smx205022 30175574Smx205022 return (DDI_FAILURE); 30185574Smx205022 } 30195574Smx205022 /* Test for high level mutex */ 30205574Smx205022 if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) { 30215574Smx205022 nge_error(ngep, "nge_add_intrs:" 30225574Smx205022 "Hi level interrupt not supported"); 30235574Smx205022 30245574Smx205022 for (i = 0; i < actual; i++) 30255574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30265574Smx205022 30275574Smx205022 kmem_free(ngep->htable, intr_size); 30285574Smx205022 30295574Smx205022 return (DDI_FAILURE); 30305574Smx205022 } 30315574Smx205022 30325574Smx205022 30335574Smx205022 /* Call ddi_intr_add_handler() */ 30345574Smx205022 for (i = 0; i < actual; i++) { 30355574Smx205022 if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr, 30365574Smx205022 (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 30375574Smx205022 nge_error(ngep, "ddi_intr_add_handler() " 30385574Smx205022 "failed %d\n", ret); 30395574Smx205022 30405574Smx205022 /* Free already allocated intr */ 30415574Smx205022 for (i = 0; i < actual; i++) { 30425574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30435574Smx205022 } 30445574Smx205022 30455574Smx205022 kmem_free(ngep->htable, intr_size); 30465574Smx205022 30475574Smx205022 return (DDI_FAILURE); 30485574Smx205022 } 30495574Smx205022 } 30505574Smx205022 30515574Smx205022 if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap)) 30525574Smx205022 != DDI_SUCCESS) { 30535574Smx205022 nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret); 30545574Smx205022 30555574Smx205022 for (i = 0; i < actual; i++) { 30565574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 30575574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30585574Smx205022 } 30595574Smx205022 30605574Smx205022 kmem_free(ngep->htable, intr_size); 30615574Smx205022 30625574Smx205022 return (DDI_FAILURE); 30635574Smx205022 } 30645574Smx205022 30655574Smx205022 return (DDI_SUCCESS); 30665574Smx205022 } 30675574Smx205022 30685574Smx205022 /* 30695574Smx205022 * nge_rem_intrs: 30705574Smx205022 * 30715574Smx205022 * Unregister FIXED or MSI interrupts 30725574Smx205022 */ 30735574Smx205022 static void 30745574Smx205022 nge_rem_intrs(nge_t *ngep) 30755574Smx205022 { 30765574Smx205022 int i; 30775574Smx205022 30785574Smx205022 NGE_DEBUG(("nge_rem_intrs\n")); 30795574Smx205022 30805574Smx205022 /* Disable all interrupts */ 30815574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 30825574Smx205022 /* Call ddi_intr_block_disable() */ 30835574Smx205022 (void) ddi_intr_block_disable(ngep->htable, 30845574Smx205022 ngep->intr_actual_cnt); 30855574Smx205022 } else { 30865574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 30875574Smx205022 (void) ddi_intr_disable(ngep->htable[i]); 30885574Smx205022 } 30895574Smx205022 } 30905574Smx205022 30915574Smx205022 /* Call ddi_intr_remove_handler() */ 30925574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 30935574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 30945574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 30955574Smx205022 } 30965574Smx205022 30975574Smx205022 kmem_free(ngep->htable, 30985574Smx205022 ngep->intr_req_cnt * sizeof (ddi_intr_handle_t)); 30995574Smx205022 } 3100