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