1*5578Smx205022 /* 2*5578Smx205022 * CDDL HEADER START 3*5578Smx205022 * 4*5578Smx205022 * The contents of this file are subject to the terms of the 5*5578Smx205022 * Common Development and Distribution License (the "License"). 6*5578Smx205022 * You may not use this file except in compliance with the License. 7*5578Smx205022 * 8*5578Smx205022 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5578Smx205022 * or http://www.opensolaris.org/os/licensing. 10*5578Smx205022 * See the License for the specific language governing permissions 11*5578Smx205022 * and limitations under the License. 12*5578Smx205022 * 13*5578Smx205022 * When distributing Covered Code, include this CDDL HEADER in each 14*5578Smx205022 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5578Smx205022 * If applicable, add the following below this CDDL HEADER, with the 16*5578Smx205022 * fields enclosed by brackets "[]" replaced with your own identifying 17*5578Smx205022 * information: Portions Copyright [yyyy] [name of copyright owner] 18*5578Smx205022 * 19*5578Smx205022 * CDDL HEADER END 20*5578Smx205022 */ 21*5578Smx205022 225574Smx205022 /* 235574Smx205022 * Copyright 2007 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 1575574Smx205022 static char nge_ident[] = "nVidia 1Gb Ethernet %I%"; 1585574Smx205022 static char clsize_propname[] = "cache-line-size"; 1595574Smx205022 static char latency_propname[] = "latency-timer"; 1605574Smx205022 static char debug_propname[] = "nge-debug-flags"; 1615574Smx205022 static char rx_data_hw[] = "rx-data-hw"; 1625574Smx205022 static char rx_prd_lw[] = "rx-prd-lw"; 1635574Smx205022 static char rx_prd_hw[] = "rx-prd-hw"; 1645574Smx205022 static char sw_intr_intv[] = "sw-intr-intvl"; 1655574Smx205022 static char nge_desc_mode[] = "desc-mode"; 1665574Smx205022 static char default_mtu[] = "default_mtu"; 1675574Smx205022 static char low_memory_mode[] = "minimal-memory-usage"; 1685574Smx205022 extern kmutex_t nge_log_mutex[1]; 1695574Smx205022 1705574Smx205022 static int nge_m_start(void *); 1715574Smx205022 static void nge_m_stop(void *); 1725574Smx205022 static int nge_m_promisc(void *, boolean_t); 1735574Smx205022 static int nge_m_multicst(void *, boolean_t, const uint8_t *); 1745574Smx205022 static int nge_m_unicst(void *, const uint8_t *); 1755574Smx205022 static void nge_m_resources(void *); 1765574Smx205022 static void nge_m_ioctl(void *, queue_t *, mblk_t *); 1775574Smx205022 static boolean_t nge_m_getcapab(void *, mac_capab_t, void *); 1785574Smx205022 1795574Smx205022 #define NGE_M_CALLBACK_FLAGS (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB) 1805574Smx205022 1815574Smx205022 static mac_callbacks_t nge_m_callbacks = { 1825574Smx205022 NGE_M_CALLBACK_FLAGS, 1835574Smx205022 nge_m_stat, 1845574Smx205022 nge_m_start, 1855574Smx205022 nge_m_stop, 1865574Smx205022 nge_m_promisc, 1875574Smx205022 nge_m_multicst, 1885574Smx205022 nge_m_unicst, 1895574Smx205022 nge_m_tx, 1905574Smx205022 nge_m_resources, 1915574Smx205022 nge_m_ioctl, 1925574Smx205022 nge_m_getcapab 1935574Smx205022 }; 1945574Smx205022 1955574Smx205022 static int nge_add_intrs(nge_t *, int); 1965574Smx205022 static void nge_rem_intrs(nge_t *); 1975574Smx205022 static int nge_register_intrs_and_init_locks(nge_t *); 1985574Smx205022 1995574Smx205022 /* 2005574Smx205022 * NGE MSI tunable: 2015574Smx205022 */ 2025574Smx205022 boolean_t nge_enable_msi = B_FALSE; 2035574Smx205022 2045574Smx205022 static enum ioc_reply 2055574Smx205022 nge_set_loop_mode(nge_t *ngep, uint32_t mode) 2065574Smx205022 { 2075574Smx205022 /* 2085574Smx205022 * If the mode isn't being changed, there's nothing to do ... 2095574Smx205022 */ 2105574Smx205022 if (mode == ngep->param_loop_mode) 2115574Smx205022 return (IOC_ACK); 2125574Smx205022 2135574Smx205022 /* 2145574Smx205022 * Validate the requested mode and prepare a suitable message 2155574Smx205022 * to explain the link down/up cycle that the change will 2165574Smx205022 * probably induce ... 2175574Smx205022 */ 2185574Smx205022 switch (mode) { 2195574Smx205022 default: 2205574Smx205022 return (IOC_INVAL); 2215574Smx205022 2225574Smx205022 case NGE_LOOP_NONE: 2235574Smx205022 case NGE_LOOP_EXTERNAL_100: 2245574Smx205022 case NGE_LOOP_EXTERNAL_10: 2255574Smx205022 case NGE_LOOP_INTERNAL_PHY: 2265574Smx205022 break; 2275574Smx205022 } 2285574Smx205022 2295574Smx205022 /* 2305574Smx205022 * All OK; tell the caller to reprogram 2315574Smx205022 * the PHY and/or MAC for the new mode ... 2325574Smx205022 */ 2335574Smx205022 ngep->param_loop_mode = mode; 2345574Smx205022 return (IOC_RESTART_ACK); 2355574Smx205022 } 2365574Smx205022 2375574Smx205022 #undef NGE_DBG 2385574Smx205022 #define NGE_DBG NGE_DBG_INIT 2395574Smx205022 2405574Smx205022 /* 2415574Smx205022 * Utility routine to carve a slice off a chunk of allocated memory, 2425574Smx205022 * updating the chunk descriptor accordingly. The size of the slice 2435574Smx205022 * is given by the product of the <qty> and <size> parameters. 2445574Smx205022 */ 2455574Smx205022 void 2465574Smx205022 nge_slice_chunk(dma_area_t *slice, dma_area_t *chunk, 2475574Smx205022 uint32_t qty, uint32_t size) 2485574Smx205022 { 2495574Smx205022 size_t totsize; 2505574Smx205022 2515574Smx205022 totsize = qty*size; 2525574Smx205022 ASSERT(size > 0); 2535574Smx205022 ASSERT(totsize <= chunk->alength); 2545574Smx205022 2555574Smx205022 *slice = *chunk; 2565574Smx205022 slice->nslots = qty; 2575574Smx205022 slice->size = size; 2585574Smx205022 slice->alength = totsize; 2595574Smx205022 2605574Smx205022 chunk->mem_va = (caddr_t)chunk->mem_va + totsize; 2615574Smx205022 chunk->alength -= totsize; 2625574Smx205022 chunk->offset += totsize; 2635574Smx205022 chunk->cookie.dmac_laddress += totsize; 2645574Smx205022 chunk->cookie.dmac_size -= totsize; 2655574Smx205022 } 2665574Smx205022 2675574Smx205022 /* 2685574Smx205022 * Allocate an area of memory and a DMA handle for accessing it 2695574Smx205022 */ 2705574Smx205022 int 2715574Smx205022 nge_alloc_dma_mem(nge_t *ngep, size_t memsize, ddi_device_acc_attr_t *attr_p, 2725574Smx205022 uint_t dma_flags, dma_area_t *dma_p) 2735574Smx205022 { 2745574Smx205022 int err; 2755574Smx205022 caddr_t va; 2765574Smx205022 2775574Smx205022 NGE_TRACE(("nge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)", 2785574Smx205022 (void *)ngep, memsize, attr_p, dma_flags, dma_p)); 2795574Smx205022 /* 2805574Smx205022 * Allocate handle 2815574Smx205022 */ 2825574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, ngep->desc_attr.dma_attr, 2835574Smx205022 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); 2845574Smx205022 if (err != DDI_SUCCESS) 2855574Smx205022 goto fail; 2865574Smx205022 2875574Smx205022 /* 2885574Smx205022 * Allocate memory 2895574Smx205022 */ 2905574Smx205022 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 2915574Smx205022 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 2925574Smx205022 DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength, &dma_p->acc_hdl); 2935574Smx205022 if (err != DDI_SUCCESS) 2945574Smx205022 goto fail; 2955574Smx205022 2965574Smx205022 /* 2975574Smx205022 * Bind the two together 2985574Smx205022 */ 2995574Smx205022 dma_p->mem_va = va; 3005574Smx205022 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 3015574Smx205022 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL, 3025574Smx205022 &dma_p->cookie, &dma_p->ncookies); 3035574Smx205022 3045574Smx205022 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) 3055574Smx205022 goto fail; 3065574Smx205022 3075574Smx205022 dma_p->nslots = ~0U; 3085574Smx205022 dma_p->size = ~0U; 3095574Smx205022 dma_p->offset = 0; 3105574Smx205022 3115574Smx205022 return (DDI_SUCCESS); 3125574Smx205022 3135574Smx205022 fail: 3145574Smx205022 nge_free_dma_mem(dma_p); 3155574Smx205022 NGE_DEBUG(("nge_alloc_dma_mem: fail to alloc dma memory!")); 3165574Smx205022 3175574Smx205022 return (DDI_FAILURE); 3185574Smx205022 } 3195574Smx205022 3205574Smx205022 /* 3215574Smx205022 * Free one allocated area of DMAable memory 3225574Smx205022 */ 3235574Smx205022 void 3245574Smx205022 nge_free_dma_mem(dma_area_t *dma_p) 3255574Smx205022 { 3265574Smx205022 if (dma_p->dma_hdl != NULL) { 3275574Smx205022 if (dma_p->ncookies) { 3285574Smx205022 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 3295574Smx205022 dma_p->ncookies = 0; 3305574Smx205022 } 3315574Smx205022 } 3325574Smx205022 if (dma_p->acc_hdl != NULL) { 3335574Smx205022 ddi_dma_mem_free(&dma_p->acc_hdl); 3345574Smx205022 dma_p->acc_hdl = NULL; 3355574Smx205022 } 3365574Smx205022 if (dma_p->dma_hdl != NULL) { 3375574Smx205022 ddi_dma_free_handle(&dma_p->dma_hdl); 3385574Smx205022 dma_p->dma_hdl = NULL; 3395574Smx205022 } 3405574Smx205022 } 3415574Smx205022 3425574Smx205022 #define ALLOC_TX_BUF 0x1 3435574Smx205022 #define ALLOC_TX_DESC 0x2 3445574Smx205022 #define ALLOC_RX_DESC 0x4 3455574Smx205022 3465574Smx205022 int 3475574Smx205022 nge_alloc_bufs(nge_t *ngep) 3485574Smx205022 { 3495574Smx205022 int err; 3505574Smx205022 int split; 3515574Smx205022 int progress; 3525574Smx205022 size_t txbuffsize; 3535574Smx205022 size_t rxdescsize; 3545574Smx205022 size_t txdescsize; 3555574Smx205022 3565574Smx205022 txbuffsize = ngep->tx_desc * ngep->buf_size; 3575574Smx205022 rxdescsize = ngep->rx_desc; 3585574Smx205022 txdescsize = ngep->tx_desc; 3595574Smx205022 rxdescsize *= ngep->desc_attr.rxd_size; 3605574Smx205022 txdescsize *= ngep->desc_attr.txd_size; 3615574Smx205022 progress = 0; 3625574Smx205022 3635574Smx205022 NGE_TRACE(("nge_alloc_bufs($%p)", (void *)ngep)); 3645574Smx205022 /* 3655574Smx205022 * Allocate memory & handles for TX buffers 3665574Smx205022 */ 3675574Smx205022 ASSERT((txbuffsize % ngep->nge_split) == 0); 3685574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 3695574Smx205022 err = nge_alloc_dma_mem(ngep, txbuffsize/ngep->nge_split, 3705574Smx205022 &nge_data_accattr, DDI_DMA_WRITE | NGE_DMA_MODE, 3715574Smx205022 &ngep->send->buf[split]); 3725574Smx205022 if (err != DDI_SUCCESS) 3735574Smx205022 goto fail; 3745574Smx205022 } 3755574Smx205022 3765574Smx205022 progress |= ALLOC_TX_BUF; 3775574Smx205022 3785574Smx205022 /* 3795574Smx205022 * Allocate memory & handles for receive return rings and 3805574Smx205022 * buffer (producer) descriptor rings 3815574Smx205022 */ 3825574Smx205022 err = nge_alloc_dma_mem(ngep, rxdescsize, &nge_desc_accattr, 3835574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->recv->desc); 3845574Smx205022 if (err != DDI_SUCCESS) 3855574Smx205022 goto fail; 3865574Smx205022 progress |= ALLOC_RX_DESC; 3875574Smx205022 3885574Smx205022 /* 3895574Smx205022 * Allocate memory & handles for TX descriptor rings, 3905574Smx205022 */ 3915574Smx205022 err = nge_alloc_dma_mem(ngep, txdescsize, &nge_desc_accattr, 3925574Smx205022 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &ngep->send->desc); 3935574Smx205022 if (err != DDI_SUCCESS) 3945574Smx205022 goto fail; 3955574Smx205022 return (DDI_SUCCESS); 3965574Smx205022 3975574Smx205022 fail: 3985574Smx205022 if (progress & ALLOC_RX_DESC) 3995574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4005574Smx205022 if (progress & ALLOC_TX_BUF) { 4015574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4025574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4035574Smx205022 } 4045574Smx205022 4055574Smx205022 return (DDI_FAILURE); 4065574Smx205022 } 4075574Smx205022 4085574Smx205022 /* 4095574Smx205022 * This routine frees the transmit and receive buffers and descriptors. 4105574Smx205022 * Make sure the chip is stopped before calling it! 4115574Smx205022 */ 4125574Smx205022 void 4135574Smx205022 nge_free_bufs(nge_t *ngep) 4145574Smx205022 { 4155574Smx205022 int split; 4165574Smx205022 4175574Smx205022 NGE_TRACE(("nge_free_bufs($%p)", (void *)ngep)); 4185574Smx205022 4195574Smx205022 nge_free_dma_mem(&ngep->recv->desc); 4205574Smx205022 nge_free_dma_mem(&ngep->send->desc); 4215574Smx205022 4225574Smx205022 for (split = 0; split < ngep->nge_split; ++split) 4235574Smx205022 nge_free_dma_mem(&ngep->send->buf[split]); 4245574Smx205022 } 4255574Smx205022 4265574Smx205022 /* 4275574Smx205022 * Clean up initialisation done above before the memory is freed 4285574Smx205022 */ 4295574Smx205022 static void 4305574Smx205022 nge_fini_send_ring(nge_t *ngep) 4315574Smx205022 { 4325574Smx205022 uint32_t slot; 4335574Smx205022 size_t dmah_num; 4345574Smx205022 send_ring_t *srp; 4355574Smx205022 sw_tx_sbd_t *ssbdp; 4365574Smx205022 4375574Smx205022 srp = ngep->send; 4385574Smx205022 ssbdp = srp->sw_sbds; 4395574Smx205022 4405574Smx205022 NGE_TRACE(("nge_fini_send_ring($%p)", (void *)ngep)); 4415574Smx205022 4425574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 4435574Smx205022 4445574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 4455574Smx205022 if (srp->dmahndl[slot].hndl) { 4465574Smx205022 (void) ddi_dma_unbind_handle(srp->dmahndl[slot].hndl); 4475574Smx205022 ddi_dma_free_handle(&srp->dmahndl[slot].hndl); 4485574Smx205022 srp->dmahndl[slot].hndl = NULL; 4495574Smx205022 srp->dmahndl[slot].next = NULL; 4505574Smx205022 } 4515574Smx205022 } 4525574Smx205022 4535574Smx205022 srp->dmah_free.head = NULL; 4545574Smx205022 srp->dmah_free.tail = NULL; 4555574Smx205022 4565574Smx205022 kmem_free(ssbdp, srp->desc.nslots*sizeof (*ssbdp)); 4575574Smx205022 4585574Smx205022 } 4595574Smx205022 4605574Smx205022 /* 4615574Smx205022 * Initialise the specified Send Ring, using the information in the 4625574Smx205022 * <dma_area> descriptors that it contains to set up all the other 4635574Smx205022 * fields. This routine should be called only once for each ring. 4645574Smx205022 */ 4655574Smx205022 static int 4665574Smx205022 nge_init_send_ring(nge_t *ngep) 4675574Smx205022 { 4685574Smx205022 size_t dmah_num; 4695574Smx205022 uint32_t nslots; 4705574Smx205022 uint32_t err; 4715574Smx205022 uint32_t slot; 4725574Smx205022 uint32_t split; 4735574Smx205022 send_ring_t *srp; 4745574Smx205022 sw_tx_sbd_t *ssbdp; 4755574Smx205022 dma_area_t desc; 4765574Smx205022 dma_area_t pbuf; 4775574Smx205022 4785574Smx205022 srp = ngep->send; 4795574Smx205022 srp->desc.nslots = ngep->tx_desc; 4805574Smx205022 nslots = srp->desc.nslots; 4815574Smx205022 4825574Smx205022 NGE_TRACE(("nge_init_send_ring($%p)", (void *)ngep)); 4835574Smx205022 /* 4845574Smx205022 * Other one-off initialisation of per-ring data 4855574Smx205022 */ 4865574Smx205022 srp->ngep = ngep; 4875574Smx205022 4885574Smx205022 /* 4895574Smx205022 * Allocate the array of s/w Send Buffer Descriptors 4905574Smx205022 */ 4915574Smx205022 ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP); 4925574Smx205022 srp->sw_sbds = ssbdp; 4935574Smx205022 4945574Smx205022 /* 4955574Smx205022 * Now initialise each array element once and for all 4965574Smx205022 */ 4975574Smx205022 desc = srp->desc; 4985574Smx205022 for (split = 0; split < ngep->nge_split; ++split) { 4995574Smx205022 pbuf = srp->buf[split]; 5005574Smx205022 for (slot = 0; slot < nslots/ngep->nge_split; ++ssbdp, ++slot) { 5015574Smx205022 nge_slice_chunk(&ssbdp->desc, &desc, 1, 5025574Smx205022 ngep->desc_attr.txd_size); 5035574Smx205022 nge_slice_chunk(&ssbdp->pbuf, &pbuf, 1, 5045574Smx205022 ngep->buf_size); 5055574Smx205022 } 5065574Smx205022 ASSERT(pbuf.alength == 0); 5075574Smx205022 } 5085574Smx205022 ASSERT(desc.alength == 0); 5095574Smx205022 5105574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5115574Smx205022 5125574Smx205022 /* preallocate dma handles for tx buffer */ 5135574Smx205022 for (slot = 0; slot < dmah_num; ++slot) { 5145574Smx205022 5155574Smx205022 err = ddi_dma_alloc_handle(ngep->devinfo, 5165574Smx205022 ngep->desc_attr.tx_dma_attr, DDI_DMA_DONTWAIT, 5175574Smx205022 NULL, &srp->dmahndl[slot].hndl); 5185574Smx205022 5195574Smx205022 if (err != DDI_SUCCESS) { 5205574Smx205022 nge_fini_send_ring(ngep); 5215574Smx205022 nge_error(ngep, 5225574Smx205022 "nge_init_send_ring: alloc dma handle fails"); 5235574Smx205022 return (DDI_FAILURE); 5245574Smx205022 } 5255574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5265574Smx205022 } 5275574Smx205022 5285574Smx205022 srp->dmah_free.head = srp->dmahndl; 5295574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5305574Smx205022 srp->dmah_free.tail->next = NULL; 5315574Smx205022 5325574Smx205022 return (DDI_SUCCESS); 5335574Smx205022 } 5345574Smx205022 5355574Smx205022 /* 5365574Smx205022 * Intialize the tx recycle pointer and tx sending pointer of tx ring 5375574Smx205022 * and set the type of tx's data descriptor by default. 5385574Smx205022 */ 5395574Smx205022 static void 5405574Smx205022 nge_reinit_send_ring(nge_t *ngep) 5415574Smx205022 { 5425574Smx205022 size_t dmah_num; 5435574Smx205022 uint32_t slot; 5445574Smx205022 send_ring_t *srp; 5455574Smx205022 sw_tx_sbd_t *ssbdp; 5465574Smx205022 5475574Smx205022 srp = ngep->send; 5485574Smx205022 5495574Smx205022 /* 5505574Smx205022 * Reinitialise control variables ... 5515574Smx205022 */ 5525574Smx205022 5535574Smx205022 srp->tx_hwmark = NGE_DESC_MIN; 5545574Smx205022 srp->tx_lwmark = NGE_DESC_MIN; 5555574Smx205022 5565574Smx205022 srp->tx_next = 0; 5575574Smx205022 srp->tx_free = srp->desc.nslots; 5585574Smx205022 srp->tc_next = 0; 5595574Smx205022 5605574Smx205022 dmah_num = sizeof (srp->dmahndl) / sizeof (srp->dmahndl[0]); 5615574Smx205022 5625574Smx205022 for (slot = 0; slot - dmah_num != 0; ++slot) 5635574Smx205022 srp->dmahndl[slot].next = srp->dmahndl + slot + 1; 5645574Smx205022 5655574Smx205022 srp->dmah_free.head = srp->dmahndl; 5665574Smx205022 srp->dmah_free.tail = srp->dmahndl + dmah_num - 1; 5675574Smx205022 srp->dmah_free.tail->next = NULL; 5685574Smx205022 5695574Smx205022 /* 5705574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 5715574Smx205022 */ 5725574Smx205022 for (slot = 0; slot < srp->desc.nslots; ++slot) { 5735574Smx205022 ssbdp = &srp->sw_sbds[slot]; 5745574Smx205022 ssbdp->flags = HOST_OWN; 5755574Smx205022 } 5765574Smx205022 5775574Smx205022 DMA_ZERO(srp->desc); 5785574Smx205022 DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV); 5795574Smx205022 } 5805574Smx205022 5815574Smx205022 /* 5825574Smx205022 * Initialize the slot number of rx's ring 5835574Smx205022 */ 5845574Smx205022 static void 5855574Smx205022 nge_init_recv_ring(nge_t *ngep) 5865574Smx205022 { 5875574Smx205022 recv_ring_t *rrp; 5885574Smx205022 5895574Smx205022 rrp = ngep->recv; 5905574Smx205022 rrp->desc.nslots = ngep->rx_desc; 5915574Smx205022 rrp->ngep = ngep; 5925574Smx205022 } 5935574Smx205022 5945574Smx205022 /* 5955574Smx205022 * Intialize the rx recycle pointer and rx sending pointer of rx ring 5965574Smx205022 */ 5975574Smx205022 static void 5985574Smx205022 nge_reinit_recv_ring(nge_t *ngep) 5995574Smx205022 { 6005574Smx205022 recv_ring_t *rrp; 6015574Smx205022 6025574Smx205022 rrp = ngep->recv; 6035574Smx205022 6045574Smx205022 /* 6055574Smx205022 * Reinitialise control variables ... 6065574Smx205022 */ 6075574Smx205022 rrp->prod_index = 0; 6085574Smx205022 /* 6095574Smx205022 * Zero and sync all the h/w Send Buffer Descriptors 6105574Smx205022 */ 6115574Smx205022 DMA_ZERO(rrp->desc); 6125574Smx205022 DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORDEV); 6135574Smx205022 } 6145574Smx205022 6155574Smx205022 /* 6165574Smx205022 * Clean up initialisation done above before the memory is freed 6175574Smx205022 */ 6185574Smx205022 static void 6195574Smx205022 nge_fini_buff_ring(nge_t *ngep) 6205574Smx205022 { 6215574Smx205022 uint32_t i; 6225574Smx205022 buff_ring_t *brp; 6235574Smx205022 dma_area_t *bufp; 6245574Smx205022 sw_rx_sbd_t *bsbdp; 6255574Smx205022 6265574Smx205022 brp = ngep->buff; 6275574Smx205022 bsbdp = brp->sw_rbds; 6285574Smx205022 6295574Smx205022 NGE_DEBUG(("nge_fini_buff_ring($%p)", (void *)ngep)); 6305574Smx205022 6315574Smx205022 mutex_enter(brp->recycle_lock); 6325574Smx205022 brp->buf_sign++; 6335574Smx205022 mutex_exit(brp->recycle_lock); 6345574Smx205022 for (i = 0; i < ngep->rx_desc; i++, ++bsbdp) { 6355574Smx205022 if (bsbdp->bufp) { 6365574Smx205022 if (bsbdp->bufp->mp) 6375574Smx205022 freemsg(bsbdp->bufp->mp); 6385574Smx205022 nge_free_dma_mem(bsbdp->bufp); 6395574Smx205022 kmem_free(bsbdp->bufp, sizeof (dma_area_t)); 6405574Smx205022 bsbdp->bufp = NULL; 6415574Smx205022 } 6425574Smx205022 } 6435574Smx205022 while (brp->free_list != NULL) { 6445574Smx205022 bufp = brp->free_list; 6455574Smx205022 brp->free_list = bufp->next; 6465574Smx205022 bufp->next = NULL; 6475574Smx205022 if (bufp->mp) 6485574Smx205022 freemsg(bufp->mp); 6495574Smx205022 nge_free_dma_mem(bufp); 6505574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6515574Smx205022 } 6525574Smx205022 while (brp->recycle_list != NULL) { 6535574Smx205022 bufp = brp->recycle_list; 6545574Smx205022 brp->recycle_list = bufp->next; 6555574Smx205022 bufp->next = NULL; 6565574Smx205022 if (bufp->mp) 6575574Smx205022 freemsg(bufp->mp); 6585574Smx205022 nge_free_dma_mem(bufp); 6595574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 6605574Smx205022 } 6615574Smx205022 6625574Smx205022 6635574Smx205022 kmem_free(brp->sw_rbds, (ngep->rx_desc * sizeof (*bsbdp))); 6645574Smx205022 brp->sw_rbds = NULL; 6655574Smx205022 } 6665574Smx205022 6675574Smx205022 /* 6685574Smx205022 * Intialize the Rx's data ring and free ring 6695574Smx205022 */ 6705574Smx205022 static int 6715574Smx205022 nge_init_buff_ring(nge_t *ngep) 6725574Smx205022 { 6735574Smx205022 uint32_t err; 6745574Smx205022 uint32_t slot; 6755574Smx205022 uint32_t nslots_buff; 6765574Smx205022 uint32_t nslots_recv; 6775574Smx205022 buff_ring_t *brp; 6785574Smx205022 recv_ring_t *rrp; 6795574Smx205022 dma_area_t desc; 6805574Smx205022 dma_area_t *bufp; 6815574Smx205022 sw_rx_sbd_t *bsbdp; 6825574Smx205022 6835574Smx205022 rrp = ngep->recv; 6845574Smx205022 brp = ngep->buff; 6855574Smx205022 brp->nslots = ngep->rx_buf; 6865574Smx205022 brp->rx_bcopy = B_FALSE; 6875574Smx205022 nslots_recv = rrp->desc.nslots; 6885574Smx205022 nslots_buff = brp->nslots; 6895574Smx205022 brp->ngep = ngep; 6905574Smx205022 6915574Smx205022 NGE_TRACE(("nge_init_buff_ring($%p)", (void *)ngep)); 6925574Smx205022 6935574Smx205022 /* 6945574Smx205022 * Allocate the array of s/w Recv Buffer Descriptors 6955574Smx205022 */ 6965574Smx205022 bsbdp = kmem_zalloc(nslots_recv *sizeof (*bsbdp), KM_SLEEP); 6975574Smx205022 brp->sw_rbds = bsbdp; 6985574Smx205022 brp->free_list = NULL; 6995574Smx205022 brp->recycle_list = NULL; 7005574Smx205022 for (slot = 0; slot < nslots_buff; ++slot) { 7015574Smx205022 bufp = kmem_zalloc(sizeof (dma_area_t), KM_SLEEP); 7025574Smx205022 err = nge_alloc_dma_mem(ngep, (ngep->buf_size 7035574Smx205022 + NGE_HEADROOM), 7045574Smx205022 &nge_data_accattr, DDI_DMA_READ | NGE_DMA_MODE, bufp); 7055574Smx205022 if (err != DDI_SUCCESS) { 7065574Smx205022 kmem_free(bufp, sizeof (dma_area_t)); 7075574Smx205022 return (DDI_FAILURE); 7085574Smx205022 } 7095574Smx205022 7105574Smx205022 bufp->alength -= NGE_HEADROOM; 7115574Smx205022 bufp->offset += NGE_HEADROOM; 7125574Smx205022 bufp->private = (caddr_t)ngep; 7135574Smx205022 bufp->rx_recycle.free_func = nge_recv_recycle; 7145574Smx205022 bufp->rx_recycle.free_arg = (caddr_t)bufp; 7155574Smx205022 bufp->signature = brp->buf_sign; 7165574Smx205022 bufp->rx_delivered = B_FALSE; 7175574Smx205022 bufp->mp = desballoc(DMA_VPTR(*bufp), 7185574Smx205022 ngep->buf_size + NGE_HEADROOM, 7195574Smx205022 0, &bufp->rx_recycle); 7205574Smx205022 7215574Smx205022 if (bufp->mp == NULL) { 7225574Smx205022 return (DDI_FAILURE); 7235574Smx205022 } 7245574Smx205022 bufp->next = brp->free_list; 7255574Smx205022 brp->free_list = bufp; 7265574Smx205022 } 7275574Smx205022 7285574Smx205022 /* 7295574Smx205022 * Now initialise each array element once and for all 7305574Smx205022 */ 7315574Smx205022 desc = rrp->desc; 7325574Smx205022 for (slot = 0; slot < nslots_recv; ++slot, ++bsbdp) { 7335574Smx205022 nge_slice_chunk(&bsbdp->desc, &desc, 1, 7345574Smx205022 ngep->desc_attr.rxd_size); 7355574Smx205022 bufp = brp->free_list; 7365574Smx205022 brp->free_list = bufp->next; 7375574Smx205022 bsbdp->bufp = bufp; 7385574Smx205022 bsbdp->flags = CONTROLER_OWN; 7395574Smx205022 bufp->next = NULL; 7405574Smx205022 } 7415574Smx205022 7425574Smx205022 ASSERT(desc.alength == 0); 7435574Smx205022 return (DDI_SUCCESS); 7445574Smx205022 } 7455574Smx205022 7465574Smx205022 /* 7475574Smx205022 * Fill the host address of data in rx' descriptor 7485574Smx205022 * and initialize free pointers of rx free ring 7495574Smx205022 */ 7505574Smx205022 static int 7515574Smx205022 nge_reinit_buff_ring(nge_t *ngep) 7525574Smx205022 { 7535574Smx205022 uint32_t slot; 7545574Smx205022 uint32_t nslots_recv; 7555574Smx205022 buff_ring_t *brp; 7565574Smx205022 recv_ring_t *rrp; 7575574Smx205022 sw_rx_sbd_t *bsbdp; 7585574Smx205022 void *hw_bd_p; 7595574Smx205022 7605574Smx205022 brp = ngep->buff; 7615574Smx205022 rrp = ngep->recv; 7625574Smx205022 bsbdp = brp->sw_rbds; 7635574Smx205022 nslots_recv = rrp->desc.nslots; 7645574Smx205022 for (slot = 0; slot < nslots_recv; ++bsbdp, ++slot) { 7655574Smx205022 hw_bd_p = DMA_VPTR(bsbdp->desc); 7665574Smx205022 /* 7675574Smx205022 * There is a scenario: When the traffic of small tcp 7685574Smx205022 * packet is heavy, suspending the tcp traffic will 7695574Smx205022 * cause the preallocated buffers for rx not to be 7705574Smx205022 * released in time by tcp taffic and cause rx's buffer 7715574Smx205022 * pointers not to be refilled in time. 7725574Smx205022 * 7735574Smx205022 * At this point, if we reinitialize the driver, the bufp 7745574Smx205022 * pointer for rx's traffic will be NULL. 7755574Smx205022 * So the result of the reinitializion fails. 7765574Smx205022 */ 7775574Smx205022 if (bsbdp->bufp == NULL) 7785574Smx205022 return (DDI_FAILURE); 7795574Smx205022 7805574Smx205022 ngep->desc_attr.rxd_fill(hw_bd_p, &bsbdp->bufp->cookie, 7815574Smx205022 bsbdp->bufp->alength); 7825574Smx205022 } 7835574Smx205022 return (DDI_SUCCESS); 7845574Smx205022 } 7855574Smx205022 7865574Smx205022 static void 7875574Smx205022 nge_init_ring_param_lock(nge_t *ngep) 7885574Smx205022 { 7895574Smx205022 buff_ring_t *brp; 7905574Smx205022 send_ring_t *srp; 7915574Smx205022 7925574Smx205022 srp = ngep->send; 7935574Smx205022 brp = ngep->buff; 7945574Smx205022 7955574Smx205022 /* Init the locks for send ring */ 7965574Smx205022 mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER, 7975574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 7985574Smx205022 mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER, 7995574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8005574Smx205022 mutex_init(&srp->dmah_lock, NULL, MUTEX_DRIVER, 8015574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8025574Smx205022 8035574Smx205022 /* Init parameters of buffer ring */ 8045574Smx205022 brp->free_list = NULL; 8055574Smx205022 brp->recycle_list = NULL; 8065574Smx205022 brp->rx_hold = 0; 8075574Smx205022 brp->buf_sign = 0; 8085574Smx205022 8095574Smx205022 /* Init recycle list lock */ 8105574Smx205022 mutex_init(brp->recycle_lock, NULL, MUTEX_DRIVER, 8115574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 8125574Smx205022 } 8135574Smx205022 8145574Smx205022 int 8155574Smx205022 nge_init_rings(nge_t *ngep) 8165574Smx205022 { 8175574Smx205022 uint32_t err; 8185574Smx205022 8195574Smx205022 err = nge_init_send_ring(ngep); 8205574Smx205022 if (err != DDI_SUCCESS) { 8215574Smx205022 return (err); 8225574Smx205022 } 8235574Smx205022 nge_init_recv_ring(ngep); 8245574Smx205022 8255574Smx205022 err = nge_init_buff_ring(ngep); 8265574Smx205022 if (err != DDI_SUCCESS) { 8275574Smx205022 nge_fini_send_ring(ngep); 8285574Smx205022 return (DDI_FAILURE); 8295574Smx205022 } 8305574Smx205022 8315574Smx205022 return (err); 8325574Smx205022 } 8335574Smx205022 8345574Smx205022 static int 8355574Smx205022 nge_reinit_ring(nge_t *ngep) 8365574Smx205022 { 8375574Smx205022 int err; 8385574Smx205022 8395574Smx205022 nge_reinit_recv_ring(ngep); 8405574Smx205022 nge_reinit_send_ring(ngep); 8415574Smx205022 err = nge_reinit_buff_ring(ngep); 8425574Smx205022 return (err); 8435574Smx205022 } 8445574Smx205022 8455574Smx205022 8465574Smx205022 void 8475574Smx205022 nge_fini_rings(nge_t *ngep) 8485574Smx205022 { 8495574Smx205022 /* 8505574Smx205022 * For receive ring, nothing need to be finished. 8515574Smx205022 * So only finish buffer ring and send ring here. 8525574Smx205022 */ 8535574Smx205022 nge_fini_buff_ring(ngep); 8545574Smx205022 nge_fini_send_ring(ngep); 8555574Smx205022 } 8565574Smx205022 8575574Smx205022 /* 8585574Smx205022 * Loopback ioctl code 8595574Smx205022 */ 8605574Smx205022 8615574Smx205022 static lb_property_t loopmodes[] = { 8625574Smx205022 { normal, "normal", NGE_LOOP_NONE }, 8635574Smx205022 { external, "100Mbps", NGE_LOOP_EXTERNAL_100 }, 8645574Smx205022 { external, "10Mbps", NGE_LOOP_EXTERNAL_10 }, 8655574Smx205022 { internal, "PHY", NGE_LOOP_INTERNAL_PHY }, 8665574Smx205022 }; 8675574Smx205022 8685574Smx205022 enum ioc_reply 8695574Smx205022 nge_loop_ioctl(nge_t *ngep, mblk_t *mp, struct iocblk *iocp) 8705574Smx205022 { 8715574Smx205022 int cmd; 8725574Smx205022 uint32_t *lbmp; 8735574Smx205022 lb_info_sz_t *lbsp; 8745574Smx205022 lb_property_t *lbpp; 8755574Smx205022 8765574Smx205022 /* 8775574Smx205022 * Validate format of ioctl 8785574Smx205022 */ 8795574Smx205022 if (mp->b_cont == NULL) 8805574Smx205022 return (IOC_INVAL); 8815574Smx205022 8825574Smx205022 cmd = iocp->ioc_cmd; 8835574Smx205022 8845574Smx205022 switch (cmd) { 8855574Smx205022 default: 8865574Smx205022 return (IOC_INVAL); 8875574Smx205022 8885574Smx205022 case LB_GET_INFO_SIZE: 8895574Smx205022 if (iocp->ioc_count != sizeof (lb_info_sz_t)) 8905574Smx205022 return (IOC_INVAL); 8915574Smx205022 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 8925574Smx205022 *lbsp = sizeof (loopmodes); 8935574Smx205022 return (IOC_REPLY); 8945574Smx205022 8955574Smx205022 case LB_GET_INFO: 8965574Smx205022 if (iocp->ioc_count != sizeof (loopmodes)) 8975574Smx205022 return (IOC_INVAL); 8985574Smx205022 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 8995574Smx205022 bcopy(loopmodes, lbpp, sizeof (loopmodes)); 9005574Smx205022 return (IOC_REPLY); 9015574Smx205022 9025574Smx205022 case LB_GET_MODE: 9035574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9045574Smx205022 return (IOC_INVAL); 9055574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9065574Smx205022 *lbmp = ngep->param_loop_mode; 9075574Smx205022 return (IOC_REPLY); 9085574Smx205022 9095574Smx205022 case LB_SET_MODE: 9105574Smx205022 if (iocp->ioc_count != sizeof (uint32_t)) 9115574Smx205022 return (IOC_INVAL); 9125574Smx205022 lbmp = (uint32_t *)mp->b_cont->b_rptr; 9135574Smx205022 return (nge_set_loop_mode(ngep, *lbmp)); 9145574Smx205022 } 9155574Smx205022 } 9165574Smx205022 9175574Smx205022 #undef NGE_DBG 9185574Smx205022 #define NGE_DBG NGE_DBG_NEMO 9195574Smx205022 9205574Smx205022 9215574Smx205022 static void 9225574Smx205022 nge_check_desc_prop(nge_t *ngep) 9235574Smx205022 { 9245574Smx205022 if (ngep->desc_mode != DESC_HOT && ngep->desc_mode != DESC_OFFLOAD) 9255574Smx205022 ngep->desc_mode = DESC_HOT; 9265574Smx205022 9275574Smx205022 if (ngep->desc_mode == DESC_OFFLOAD) { 9285574Smx205022 9295574Smx205022 ngep->desc_attr = nge_sum_desc; 9305574Smx205022 9315574Smx205022 } else if (ngep->desc_mode == DESC_HOT) { 9325574Smx205022 9335574Smx205022 ngep->desc_attr = nge_hot_desc; 9345574Smx205022 } 9355574Smx205022 } 9365574Smx205022 9375574Smx205022 /* 9385574Smx205022 * nge_get_props -- get the parameters to tune the driver 9395574Smx205022 */ 9405574Smx205022 static void 9415574Smx205022 nge_get_props(nge_t *ngep) 9425574Smx205022 { 9435574Smx205022 chip_info_t *infop; 9445574Smx205022 dev_info_t *devinfo; 9455574Smx205022 nge_dev_spec_param_t *dev_param_p; 9465574Smx205022 9475574Smx205022 devinfo = ngep->devinfo; 9485574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 9495574Smx205022 dev_param_p = &ngep->dev_spec_param; 9505574Smx205022 9515574Smx205022 infop->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9525574Smx205022 DDI_PROP_DONTPASS, clsize_propname, 32); 9535574Smx205022 9545574Smx205022 infop->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9555574Smx205022 DDI_PROP_DONTPASS, latency_propname, 64); 9565574Smx205022 ngep->rx_datahwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9575574Smx205022 DDI_PROP_DONTPASS, rx_data_hw, 0x20); 9585574Smx205022 ngep->rx_prdlwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9595574Smx205022 DDI_PROP_DONTPASS, rx_prd_lw, 0x4); 9605574Smx205022 ngep->rx_prdhwm = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9615574Smx205022 DDI_PROP_DONTPASS, rx_prd_hw, 0xc); 9625574Smx205022 9635574Smx205022 ngep->sw_intr_intv = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9645574Smx205022 DDI_PROP_DONTPASS, sw_intr_intv, SWTR_ITC); 9655574Smx205022 ngep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9665574Smx205022 DDI_PROP_DONTPASS, debug_propname, NGE_DBG_CHIP); 9675574Smx205022 ngep->desc_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9685574Smx205022 DDI_PROP_DONTPASS, nge_desc_mode, dev_param_p->desc_type); 9695574Smx205022 ngep->lowmem_mode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9705574Smx205022 DDI_PROP_DONTPASS, low_memory_mode, 0); 9715574Smx205022 9725574Smx205022 if (dev_param_p->jumbo) { 9735574Smx205022 ngep->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 9745574Smx205022 DDI_PROP_DONTPASS, default_mtu, ETHERMTU); 9755574Smx205022 } else 9765574Smx205022 ngep->default_mtu = ETHERMTU; 9775574Smx205022 9785574Smx205022 if (ngep->default_mtu > ETHERMTU && 9795574Smx205022 ngep->default_mtu <= NGE_MTU_2500) { 9805574Smx205022 ngep->buf_size = NGE_JB2500_BUFSZ; 9815574Smx205022 ngep->tx_desc = NGE_SEND_JB2500_SLOTS_DESC; 9825574Smx205022 ngep->rx_desc = NGE_RECV_JB2500_SLOTS_DESC; 9835574Smx205022 ngep->rx_buf = NGE_RECV_JB2500_SLOTS_DESC * 2; 9845574Smx205022 ngep->nge_split = NGE_SPLIT_256; 9855574Smx205022 } else if (ngep->default_mtu > NGE_MTU_2500 && 9865574Smx205022 ngep->default_mtu <= NGE_MTU_4500) { 9875574Smx205022 ngep->buf_size = NGE_JB4500_BUFSZ; 9885574Smx205022 ngep->tx_desc = NGE_SEND_JB4500_SLOTS_DESC; 9895574Smx205022 ngep->rx_desc = NGE_RECV_JB4500_SLOTS_DESC; 9905574Smx205022 ngep->rx_buf = NGE_RECV_JB4500_SLOTS_DESC * 2; 9915574Smx205022 ngep->nge_split = NGE_SPLIT_256; 9925574Smx205022 } else if (ngep->default_mtu > NGE_MTU_4500 && 9935574Smx205022 ngep->default_mtu <= NGE_MAX_MTU) { 9945574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 9955574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 9965574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 9975574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 9985574Smx205022 ngep->nge_split = NGE_SPLIT_256; 9995574Smx205022 } else if (ngep->default_mtu > NGE_MAX_MTU) { 10005574Smx205022 ngep->default_mtu = NGE_MAX_MTU; 10015574Smx205022 ngep->buf_size = NGE_JB9000_BUFSZ; 10025574Smx205022 ngep->tx_desc = NGE_SEND_JB9000_SLOTS_DESC; 10035574Smx205022 ngep->rx_desc = NGE_RECV_JB9000_SLOTS_DESC; 10045574Smx205022 ngep->rx_buf = NGE_RECV_JB9000_SLOTS_DESC * 2; 10055574Smx205022 ngep->nge_split = NGE_SPLIT_256; 10065574Smx205022 } else if (ngep->lowmem_mode != 0) { 10075574Smx205022 ngep->default_mtu = ETHERMTU; 10085574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10095574Smx205022 ngep->tx_desc = NGE_SEND_LOWMEM_SLOTS_DESC; 10105574Smx205022 ngep->rx_desc = NGE_RECV_LOWMEM_SLOTS_DESC; 10115574Smx205022 ngep->rx_buf = NGE_RECV_LOWMEM_SLOTS_DESC * 2; 10125574Smx205022 ngep->nge_split = NGE_SPLIT_32; 10135574Smx205022 } else { 10145574Smx205022 ngep->default_mtu = ETHERMTU; 10155574Smx205022 ngep->buf_size = NGE_STD_BUFSZ; 10165574Smx205022 ngep->tx_desc = dev_param_p->tx_desc_num; 10175574Smx205022 ngep->rx_desc = dev_param_p->rx_desc_num; 10185574Smx205022 ngep->rx_buf = dev_param_p->rx_desc_num * 2; 10195574Smx205022 ngep->nge_split = dev_param_p->nge_split; 10205574Smx205022 } 10215574Smx205022 10225574Smx205022 nge_check_desc_prop(ngep); 10235574Smx205022 } 10245574Smx205022 10255574Smx205022 10265574Smx205022 static int 10275574Smx205022 nge_reset(nge_t *ngep) 10285574Smx205022 { 10295574Smx205022 int err; 10305574Smx205022 send_ring_t *srp = ngep->send; 10315574Smx205022 10325574Smx205022 ASSERT(mutex_owned(ngep->genlock)); 10335574Smx205022 mutex_enter(srp->tc_lock); 10345574Smx205022 mutex_enter(srp->tx_lock); 10355574Smx205022 10365574Smx205022 nge_tx_recycle_all(ngep); 10375574Smx205022 err = nge_reinit_ring(ngep); 10385574Smx205022 if (err == DDI_FAILURE) { 10395574Smx205022 mutex_exit(srp->tx_lock); 10405574Smx205022 mutex_exit(srp->tc_lock); 10415574Smx205022 return (err); 10425574Smx205022 } 10435574Smx205022 err = nge_chip_reset(ngep); 10445574Smx205022 mutex_exit(srp->tx_lock); 10455574Smx205022 mutex_exit(srp->tc_lock); 10465574Smx205022 if (err == DDI_FAILURE) 10475574Smx205022 return (err); 10485574Smx205022 ngep->watchdog = 0; 10495574Smx205022 ngep->resched_needed = B_FALSE; 10505574Smx205022 ngep->promisc = B_FALSE; 10515574Smx205022 ngep->param_loop_mode = NGE_LOOP_NONE; 10525574Smx205022 ngep->factotum_flag = 0; 10535574Smx205022 ngep->resched_needed = 0; 10545574Smx205022 ngep->nge_mac_state = NGE_MAC_RESET; 10555574Smx205022 ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL; 10565574Smx205022 ngep->max_sdu += VTAG_SIZE; 10575574Smx205022 ngep->rx_def = 0x16; 10585574Smx205022 return (DDI_SUCCESS); 10595574Smx205022 } 10605574Smx205022 10615574Smx205022 static void 10625574Smx205022 nge_m_stop(void *arg) 10635574Smx205022 { 10645574Smx205022 nge_t *ngep = arg; /* private device info */ 10655574Smx205022 10665574Smx205022 NGE_TRACE(("nge_m_stop($%p)", arg)); 10675574Smx205022 10685574Smx205022 /* 10695574Smx205022 * If suspended, adapter is already stopped, just return. 10705574Smx205022 */ 10715574Smx205022 if (ngep->suspended) { 10725574Smx205022 ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED); 10735574Smx205022 return; 10745574Smx205022 } 10755574Smx205022 10765574Smx205022 /* 10775574Smx205022 * Just stop processing, then record new MAC state 10785574Smx205022 */ 10795574Smx205022 mutex_enter(ngep->genlock); 10805574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 10815574Smx205022 10825574Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 10835574Smx205022 /* Try to wait all the buffer post to upper layer be released */ 10845574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 10855574Smx205022 10865574Smx205022 /* Recycle all the TX BD */ 10875574Smx205022 nge_tx_recycle_all(ngep); 10885574Smx205022 nge_fini_rings(ngep); 10895574Smx205022 nge_free_bufs(ngep); 10905574Smx205022 10915574Smx205022 NGE_DEBUG(("nge_m_stop($%p) done", arg)); 10925574Smx205022 10935574Smx205022 rw_exit(ngep->rwlock); 10945574Smx205022 mutex_exit(ngep->genlock); 10955574Smx205022 } 10965574Smx205022 10975574Smx205022 static int 10985574Smx205022 nge_m_start(void *arg) 10995574Smx205022 { 11005574Smx205022 int err; 11015574Smx205022 nge_t *ngep = arg; 11025574Smx205022 11035574Smx205022 NGE_TRACE(("nge_m_start($%p)", arg)); 11045574Smx205022 /* 11055574Smx205022 * If suspended, don't start, as the resume processing 11065574Smx205022 * will recall this function with the suspended flag off. 11075574Smx205022 */ 11085574Smx205022 if (ngep->suspended) 11095574Smx205022 return (DDI_FAILURE); 11105574Smx205022 /* 11115574Smx205022 * Start processing and record new MAC state 11125574Smx205022 */ 11135574Smx205022 mutex_enter(ngep->genlock); 11145574Smx205022 rw_enter(ngep->rwlock, RW_WRITER); 11155574Smx205022 err = nge_alloc_bufs(ngep); 11165574Smx205022 if (err != DDI_SUCCESS) { 11175574Smx205022 nge_problem(ngep, "nge_m_start: DMA buffer allocation failed"); 11185574Smx205022 goto finish; 11195574Smx205022 } 11205574Smx205022 err = nge_init_rings(ngep); 11215574Smx205022 if (err != DDI_SUCCESS) { 11225574Smx205022 nge_free_bufs(ngep); 11235574Smx205022 nge_problem(ngep, "nge_init_rings() failed,err=%x"); 11245574Smx205022 goto finish; 11255574Smx205022 } 11265574Smx205022 err = nge_restart(ngep); 11275574Smx205022 11285574Smx205022 NGE_DEBUG(("nge_m_start($%p) done", arg)); 11295574Smx205022 finish: 11305574Smx205022 rw_exit(ngep->rwlock); 11315574Smx205022 mutex_exit(ngep->genlock); 11325574Smx205022 11335574Smx205022 return (err); 11345574Smx205022 } 11355574Smx205022 11365574Smx205022 static int 11375574Smx205022 nge_m_unicst(void *arg, const uint8_t *macaddr) 11385574Smx205022 { 11395574Smx205022 nge_t *ngep = arg; 11405574Smx205022 11415574Smx205022 NGE_TRACE(("nge_m_unicst($%p)", arg)); 11425574Smx205022 /* 11435574Smx205022 * Remember the new current address in the driver state 11445574Smx205022 * Sync the chip's idea of the address too ... 11455574Smx205022 */ 11465574Smx205022 mutex_enter(ngep->genlock); 11475574Smx205022 11485574Smx205022 ethaddr_copy(macaddr, ngep->cur_uni_addr.addr); 11495574Smx205022 ngep->cur_uni_addr.set = 1; 11505574Smx205022 11515574Smx205022 /* 11525574Smx205022 * If we are suspended, we want to quit now, and not update 11535574Smx205022 * the chip. Doing so might put it in a bad state, but the 11545574Smx205022 * resume will get the unicast address installed. 11555574Smx205022 */ 11565574Smx205022 if (ngep->suspended) 11575574Smx205022 return (DDI_SUCCESS); 11585574Smx205022 11595574Smx205022 nge_chip_sync(ngep); 11605574Smx205022 11615574Smx205022 NGE_DEBUG(("nge_m_unicst($%p) done", arg)); 11625574Smx205022 mutex_exit(ngep->genlock); 11635574Smx205022 11645574Smx205022 return (0); 11655574Smx205022 } 11665574Smx205022 11675574Smx205022 static int 11685574Smx205022 nge_m_promisc(void *arg, boolean_t on) 11695574Smx205022 { 11705574Smx205022 nge_t *ngep = arg; 11715574Smx205022 11725574Smx205022 NGE_TRACE(("nge_m_promisc($%p)", arg)); 11735574Smx205022 /* 11745574Smx205022 * If suspended, we don't do anything, even record the promiscuious 11755574Smx205022 * mode, as we won't properly set it on resume. Just fail. 11765574Smx205022 */ 11775574Smx205022 if (ngep->suspended) 11785574Smx205022 return (DDI_FAILURE); 11795574Smx205022 11805574Smx205022 /* 11815574Smx205022 * Store specified mode and pass to chip layer to update h/w 11825574Smx205022 */ 11835574Smx205022 mutex_enter(ngep->genlock); 11845574Smx205022 if (ngep->promisc == on) { 11855574Smx205022 mutex_exit(ngep->genlock); 11865574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 11875574Smx205022 return (0); 11885574Smx205022 } 11895574Smx205022 ngep->promisc = on; 11905574Smx205022 nge_chip_sync(ngep); 11915574Smx205022 NGE_DEBUG(("nge_m_promisc($%p) done", arg)); 11925574Smx205022 mutex_exit(ngep->genlock); 11935574Smx205022 11945574Smx205022 return (0); 11955574Smx205022 } 11965574Smx205022 11975574Smx205022 static void nge_mulparam(nge_t *ngep) 11985574Smx205022 { 11995574Smx205022 uint8_t number; 12005574Smx205022 ether_addr_t pand; 12015574Smx205022 ether_addr_t por; 12025574Smx205022 mul_item *plist; 12035574Smx205022 12045574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12055574Smx205022 pand[number] = 0x00; 12065574Smx205022 por[number] = 0x00; 12075574Smx205022 } 12085574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; plist = plist->next) { 12095574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12105574Smx205022 pand[number] &= plist->mul_addr[number]; 12115574Smx205022 por[number] |= plist->mul_addr[number]; 12125574Smx205022 } 12135574Smx205022 } 12145574Smx205022 for (number = 0; number < ETHERADDRL; number++) { 12155574Smx205022 ngep->cur_mul_addr.addr[number] 12165574Smx205022 = pand[number] & por[number]; 12175574Smx205022 ngep->cur_mul_mask.addr[number] 12185574Smx205022 = pand [number] | (~por[number]); 12195574Smx205022 } 12205574Smx205022 } 12215574Smx205022 static int 12225574Smx205022 nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12235574Smx205022 { 12245574Smx205022 boolean_t update; 12255574Smx205022 boolean_t b_eq; 12265574Smx205022 nge_t *ngep = arg; 12275574Smx205022 mul_item *plist; 12285574Smx205022 mul_item *plist_prev; 12295574Smx205022 mul_item *pitem; 12305574Smx205022 12315574Smx205022 NGE_TRACE(("nge_m_multicst($%p, %s, %s)", arg, 12325574Smx205022 (add) ? "add" : "remove", ether_sprintf((void *)mca))); 12335574Smx205022 12345574Smx205022 update = B_FALSE; 12355574Smx205022 plist = plist_prev = NULL; 12365574Smx205022 mutex_enter(ngep->genlock); 12375574Smx205022 if (add) { 12385574Smx205022 if (ngep->pcur_mulist != NULL) { 12395574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 12405574Smx205022 plist = plist->next) { 12415574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 12425574Smx205022 if (b_eq) { 12435574Smx205022 plist->ref_cnt++; 12445574Smx205022 break; 12455574Smx205022 } 12465574Smx205022 plist_prev = plist; 12475574Smx205022 } 12485574Smx205022 } 12495574Smx205022 12505574Smx205022 if (plist == NULL) { 12515574Smx205022 pitem = kmem_zalloc(sizeof (mul_item), KM_SLEEP); 12525574Smx205022 ether_copy(mca, pitem->mul_addr); 12535574Smx205022 pitem ->ref_cnt++; 12545574Smx205022 pitem ->next = NULL; 12555574Smx205022 if (plist_prev == NULL) 12565574Smx205022 ngep->pcur_mulist = pitem; 12575574Smx205022 else 12585574Smx205022 plist_prev->next = pitem; 12595574Smx205022 update = B_TRUE; 12605574Smx205022 } 12615574Smx205022 } else { 12625574Smx205022 if (ngep->pcur_mulist != NULL) { 12635574Smx205022 for (plist = ngep->pcur_mulist; plist != NULL; 12645574Smx205022 plist = plist->next) { 12655574Smx205022 b_eq = ether_eq(plist->mul_addr, mca); 12665574Smx205022 if (b_eq) { 12675574Smx205022 update = B_TRUE; 12685574Smx205022 break; 12695574Smx205022 } 12705574Smx205022 plist_prev = plist; 12715574Smx205022 } 12725574Smx205022 12735574Smx205022 if (update) { 12745574Smx205022 if ((plist_prev == NULL) && 12755574Smx205022 (plist->next == NULL)) 12765574Smx205022 ngep->pcur_mulist = NULL; 12775574Smx205022 else if ((plist_prev == NULL) && 12785574Smx205022 (plist->next != NULL)) 12795574Smx205022 ngep->pcur_mulist = plist->next; 12805574Smx205022 else 12815574Smx205022 plist_prev->next = plist->next; 12825574Smx205022 kmem_free(plist, sizeof (mul_item)); 12835574Smx205022 } 12845574Smx205022 } 12855574Smx205022 } 12865574Smx205022 12875574Smx205022 if (update || !ngep->suspended) { 12885574Smx205022 nge_mulparam(ngep); 12895574Smx205022 nge_chip_sync(ngep); 12905574Smx205022 } 12915574Smx205022 NGE_DEBUG(("nge_m_multicst($%p) done", arg)); 12925574Smx205022 mutex_exit(ngep->genlock); 12935574Smx205022 12945574Smx205022 return (0); 12955574Smx205022 } 12965574Smx205022 12975574Smx205022 static void 12985574Smx205022 nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 12995574Smx205022 { 13005574Smx205022 int err; 13015574Smx205022 int cmd; 13025574Smx205022 nge_t *ngep = arg; 13035574Smx205022 struct iocblk *iocp; 13045574Smx205022 enum ioc_reply status; 13055574Smx205022 boolean_t need_privilege; 13065574Smx205022 13075574Smx205022 /* 13085574Smx205022 * If suspended, we might actually be able to do some of 13095574Smx205022 * these ioctls, but it is harder to make sure they occur 13105574Smx205022 * without actually putting the hardware in an undesireable 13115574Smx205022 * state. So just NAK it. 13125574Smx205022 */ 13135574Smx205022 if (ngep->suspended) { 13145574Smx205022 miocnak(wq, mp, 0, EINVAL); 13155574Smx205022 return; 13165574Smx205022 } 13175574Smx205022 13185574Smx205022 /* 13195574Smx205022 * Validate the command before bothering with the mutex ... 13205574Smx205022 */ 13215574Smx205022 iocp = (struct iocblk *)mp->b_rptr; 13225574Smx205022 iocp->ioc_error = 0; 13235574Smx205022 need_privilege = B_TRUE; 13245574Smx205022 cmd = iocp->ioc_cmd; 13255574Smx205022 13265574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x", cmd)); 13275574Smx205022 switch (cmd) { 13285574Smx205022 default: 13295574Smx205022 NGE_LDB(NGE_DBG_BADIOC, 13305574Smx205022 ("nge_m_ioctl: unknown cmd 0x%x", cmd)); 13315574Smx205022 13325574Smx205022 miocnak(wq, mp, 0, EINVAL); 13335574Smx205022 return; 13345574Smx205022 13355574Smx205022 case NGE_MII_READ: 13365574Smx205022 case NGE_MII_WRITE: 13375574Smx205022 case NGE_SEE_READ: 13385574Smx205022 case NGE_SEE_WRITE: 13395574Smx205022 case NGE_DIAG: 13405574Smx205022 case NGE_PEEK: 13415574Smx205022 case NGE_POKE: 13425574Smx205022 case NGE_PHY_RESET: 13435574Smx205022 case NGE_SOFT_RESET: 13445574Smx205022 case NGE_HARD_RESET: 13455574Smx205022 break; 13465574Smx205022 13475574Smx205022 case LB_GET_INFO_SIZE: 13485574Smx205022 case LB_GET_INFO: 13495574Smx205022 case LB_GET_MODE: 13505574Smx205022 need_privilege = B_FALSE; 13515574Smx205022 break; 13525574Smx205022 case LB_SET_MODE: 13535574Smx205022 break; 13545574Smx205022 13555574Smx205022 case ND_GET: 13565574Smx205022 need_privilege = B_FALSE; 13575574Smx205022 break; 13585574Smx205022 case ND_SET: 13595574Smx205022 break; 13605574Smx205022 } 13615574Smx205022 13625574Smx205022 if (need_privilege) { 13635574Smx205022 /* 13645574Smx205022 * Check for specific net_config privilege. 13655574Smx205022 */ 13665574Smx205022 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 13675574Smx205022 if (err != 0) { 13685574Smx205022 NGE_DEBUG(("nge_m_ioctl: rejected cmd 0x%x, err %d", 13695574Smx205022 cmd, err)); 13705574Smx205022 miocnak(wq, mp, 0, err); 13715574Smx205022 return; 13725574Smx205022 } 13735574Smx205022 } 13745574Smx205022 13755574Smx205022 mutex_enter(ngep->genlock); 13765574Smx205022 13775574Smx205022 switch (cmd) { 13785574Smx205022 default: 13795574Smx205022 _NOTE(NOTREACHED) 13805574Smx205022 status = IOC_INVAL; 13815574Smx205022 break; 13825574Smx205022 13835574Smx205022 case NGE_MII_READ: 13845574Smx205022 case NGE_MII_WRITE: 13855574Smx205022 case NGE_SEE_READ: 13865574Smx205022 case NGE_SEE_WRITE: 13875574Smx205022 case NGE_DIAG: 13885574Smx205022 case NGE_PEEK: 13895574Smx205022 case NGE_POKE: 13905574Smx205022 case NGE_PHY_RESET: 13915574Smx205022 case NGE_SOFT_RESET: 13925574Smx205022 case NGE_HARD_RESET: 13935574Smx205022 status = nge_chip_ioctl(ngep, mp, iocp); 13945574Smx205022 break; 13955574Smx205022 13965574Smx205022 case LB_GET_INFO_SIZE: 13975574Smx205022 case LB_GET_INFO: 13985574Smx205022 case LB_GET_MODE: 13995574Smx205022 case LB_SET_MODE: 14005574Smx205022 status = nge_loop_ioctl(ngep, mp, iocp); 14015574Smx205022 break; 14025574Smx205022 14035574Smx205022 case ND_GET: 14045574Smx205022 case ND_SET: 14055574Smx205022 status = nge_nd_ioctl(ngep, wq, mp, iocp); 14065574Smx205022 break; 14075574Smx205022 14085574Smx205022 } 14095574Smx205022 14105574Smx205022 /* 14115574Smx205022 * Do we need to reprogram the PHY and/or the MAC? 14125574Smx205022 * Do it now, while we still have the mutex. 14135574Smx205022 * 14145574Smx205022 * Note: update the PHY first, 'cos it controls the 14155574Smx205022 * speed/duplex parameters that the MAC code uses. 14165574Smx205022 */ 14175574Smx205022 14185574Smx205022 NGE_DEBUG(("nge_m_ioctl: cmd 0x%x status %d", cmd, status)); 14195574Smx205022 14205574Smx205022 switch (status) { 14215574Smx205022 case IOC_RESTART_REPLY: 14225574Smx205022 case IOC_RESTART_ACK: 14235574Smx205022 (*ngep->physops->phys_update)(ngep); 14245574Smx205022 nge_chip_sync(ngep); 14255574Smx205022 break; 14265574Smx205022 14275574Smx205022 default: 14285574Smx205022 break; 14295574Smx205022 } 14305574Smx205022 14315574Smx205022 mutex_exit(ngep->genlock); 14325574Smx205022 14335574Smx205022 /* 14345574Smx205022 * Finally, decide how to reply 14355574Smx205022 */ 14365574Smx205022 switch (status) { 14375574Smx205022 14385574Smx205022 default: 14395574Smx205022 case IOC_INVAL: 14405574Smx205022 miocnak(wq, mp, 0, iocp->ioc_error == 0 ? 14415574Smx205022 EINVAL : iocp->ioc_error); 14425574Smx205022 break; 14435574Smx205022 14445574Smx205022 case IOC_DONE: 14455574Smx205022 break; 14465574Smx205022 14475574Smx205022 case IOC_RESTART_ACK: 14485574Smx205022 case IOC_ACK: 14495574Smx205022 miocack(wq, mp, 0, 0); 14505574Smx205022 break; 14515574Smx205022 14525574Smx205022 case IOC_RESTART_REPLY: 14535574Smx205022 case IOC_REPLY: 14545574Smx205022 mp->b_datap->db_type = iocp->ioc_error == 0 ? 14555574Smx205022 M_IOCACK : M_IOCNAK; 14565574Smx205022 qreply(wq, mp); 14575574Smx205022 break; 14585574Smx205022 } 14595574Smx205022 } 14605574Smx205022 14615574Smx205022 static void 14625574Smx205022 nge_chip_blank(void *arg, time_t ticks, uint_t count) 14635574Smx205022 { 14645574Smx205022 _NOTE(ARGUNUSED(arg, ticks, count)); 14655574Smx205022 } 14665574Smx205022 14675574Smx205022 static void 14685574Smx205022 nge_m_resources(void *arg) 14695574Smx205022 { 14705574Smx205022 nge_t *ngep = arg; 14715574Smx205022 recv_ring_t *rrp; 14725574Smx205022 mac_rx_fifo_t mrf; 14735574Smx205022 14745574Smx205022 mutex_enter(ngep->genlock); 14755574Smx205022 14765574Smx205022 /* 14775574Smx205022 * Register Rx rings as resources and save mac 14785574Smx205022 * resource id for future reference 14795574Smx205022 */ 14805574Smx205022 mrf.mrf_type = MAC_RX_FIFO; 14815574Smx205022 mrf.mrf_blank = nge_chip_blank; 14825574Smx205022 mrf.mrf_arg = (void *)ngep; 14835574Smx205022 mrf.mrf_normal_blank_time = NGE_TICKS_CNT; 14845574Smx205022 mrf.mrf_normal_pkt_count = NGE_RX_PKT_CNT; 14855574Smx205022 14865574Smx205022 rrp = ngep->recv; 14875574Smx205022 rrp->handle = mac_resource_add(ngep->mh, (mac_resource_t *)&mrf); 14885574Smx205022 mutex_exit(ngep->genlock); 14895574Smx205022 } 14905574Smx205022 14915574Smx205022 /* ARGSUSED */ 14925574Smx205022 static boolean_t 14935574Smx205022 nge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 14945574Smx205022 { 14955574Smx205022 nge_t *ngep = arg; 14965574Smx205022 nge_dev_spec_param_t *dev_param_p; 14975574Smx205022 14985574Smx205022 dev_param_p = &ngep->dev_spec_param; 14995574Smx205022 15005574Smx205022 switch (cap) { 15015574Smx205022 case MAC_CAPAB_HCKSUM: { 15025574Smx205022 uint32_t *hcksum_txflags = cap_data; 15035574Smx205022 15045574Smx205022 if (dev_param_p->tx_hw_checksum) { 15055574Smx205022 *hcksum_txflags = dev_param_p->tx_hw_checksum; 15065574Smx205022 } else 15075574Smx205022 return (B_FALSE); 15085574Smx205022 break; 15095574Smx205022 } 15105574Smx205022 case MAC_CAPAB_POLL: 15115574Smx205022 /* 15125574Smx205022 * There's nothing for us to fill in, simply returning 15135574Smx205022 * B_TRUE, stating that we support polling is sufficient. 15145574Smx205022 */ 15155574Smx205022 break; 15165574Smx205022 default: 15175574Smx205022 return (B_FALSE); 15185574Smx205022 } 15195574Smx205022 return (B_TRUE); 15205574Smx205022 } 15215574Smx205022 15225574Smx205022 #undef NGE_DBG 15235574Smx205022 #define NGE_DBG NGE_DBG_INIT /* debug flag for this code */ 15245574Smx205022 int 15255574Smx205022 nge_restart(nge_t *ngep) 15265574Smx205022 { 15275574Smx205022 int err = 0; 15285574Smx205022 err += nge_reset(ngep); 15295574Smx205022 err += nge_chip_start(ngep); 15305574Smx205022 15315574Smx205022 if (err) { 15325574Smx205022 ngep->nge_mac_state = NGE_MAC_STOPPED; 15335574Smx205022 return (DDI_FAILURE); 15345574Smx205022 } else { 15355574Smx205022 ngep->nge_mac_state = NGE_MAC_STARTED; 15365574Smx205022 return (DDI_SUCCESS); 15375574Smx205022 } 15385574Smx205022 } 15395574Smx205022 15405574Smx205022 void 15415574Smx205022 nge_wake_factotum(nge_t *ngep) 15425574Smx205022 { 15435574Smx205022 mutex_enter(ngep->softlock); 15445574Smx205022 if (ngep->factotum_flag == 0) { 15455574Smx205022 ngep->factotum_flag = 1; 15465574Smx205022 (void) ddi_intr_trigger_softint(ngep->factotum_hdl, NULL); 15475574Smx205022 } 15485574Smx205022 mutex_exit(ngep->softlock); 15495574Smx205022 } 15505574Smx205022 15515574Smx205022 /* 15525574Smx205022 * High-level cyclic handler 15535574Smx205022 * 15545574Smx205022 * This routine schedules a (low-level) softint callback to the 15555574Smx205022 * factotum. 15565574Smx205022 */ 15575574Smx205022 15585574Smx205022 static void 15595574Smx205022 nge_chip_cyclic(void *arg) 15605574Smx205022 { 15615574Smx205022 nge_t *ngep; 15625574Smx205022 15635574Smx205022 ngep = (nge_t *)arg; 15645574Smx205022 15655574Smx205022 switch (ngep->nge_chip_state) { 15665574Smx205022 default: 15675574Smx205022 return; 15685574Smx205022 15695574Smx205022 case NGE_CHIP_RUNNING: 15705574Smx205022 break; 15715574Smx205022 15725574Smx205022 case NGE_CHIP_FAULT: 15735574Smx205022 case NGE_CHIP_ERROR: 15745574Smx205022 break; 15755574Smx205022 } 15765574Smx205022 15775574Smx205022 nge_wake_factotum(ngep); 15785574Smx205022 } 15795574Smx205022 15805574Smx205022 static void 15815574Smx205022 nge_unattach(nge_t *ngep) 15825574Smx205022 { 15835574Smx205022 send_ring_t *srp; 15845574Smx205022 buff_ring_t *brp; 15855574Smx205022 15865574Smx205022 srp = ngep->send; 15875574Smx205022 brp = ngep->buff; 15885574Smx205022 NGE_TRACE(("nge_unattach($%p)", (void *)ngep)); 15895574Smx205022 15905574Smx205022 /* 15915574Smx205022 * Flag that no more activity may be initiated 15925574Smx205022 */ 15935574Smx205022 ngep->progress &= ~PROGRESS_READY; 15945574Smx205022 ngep->nge_mac_state = NGE_MAC_UNATTACH; 15955574Smx205022 15965574Smx205022 /* 15975574Smx205022 * Quiesce the PHY and MAC (leave it reset but still powered). 15985574Smx205022 * Clean up and free all NGE data structures 15995574Smx205022 */ 16005574Smx205022 if (ngep->periodic_id != NULL) { 16015574Smx205022 ddi_periodic_delete(ngep->periodic_id); 16025574Smx205022 ngep->periodic_id = NULL; 16035574Smx205022 } 16045574Smx205022 16055574Smx205022 if (ngep->progress & PROGRESS_KSTATS) 16065574Smx205022 nge_fini_kstats(ngep); 16075574Smx205022 16085574Smx205022 if (ngep->progress & PROGRESS_NDD) 16095574Smx205022 nge_nd_cleanup(ngep); 16105574Smx205022 16115574Smx205022 if (ngep->progress & PROGRESS_HWINT) { 16125574Smx205022 mutex_enter(ngep->genlock); 16135574Smx205022 nge_restore_mac_addr(ngep); 16145574Smx205022 (void) nge_chip_stop(ngep, B_FALSE); 16155574Smx205022 mutex_exit(ngep->genlock); 16165574Smx205022 } 16175574Smx205022 16185574Smx205022 if (ngep->progress & PROGRESS_SWINT) 16195574Smx205022 nge_rem_intrs(ngep); 16205574Smx205022 16215574Smx205022 if (ngep->progress & PROGRESS_FACTOTUM) 16225574Smx205022 (void) ddi_intr_remove_softint(ngep->factotum_hdl); 16235574Smx205022 16245574Smx205022 if (ngep->progress & PROGRESS_RESCHED) 16255574Smx205022 (void) ddi_intr_remove_softint(ngep->resched_hdl); 16265574Smx205022 16275574Smx205022 if (ngep->progress & PROGRESS_INTR) { 16285574Smx205022 mutex_destroy(srp->tx_lock); 16295574Smx205022 mutex_destroy(srp->tc_lock); 16305574Smx205022 mutex_destroy(&srp->dmah_lock); 16315574Smx205022 mutex_destroy(brp->recycle_lock); 16325574Smx205022 16335574Smx205022 mutex_destroy(ngep->genlock); 16345574Smx205022 mutex_destroy(ngep->softlock); 16355574Smx205022 rw_destroy(ngep->rwlock); 16365574Smx205022 } 16375574Smx205022 16385574Smx205022 if (ngep->progress & PROGRESS_REGS) 16395574Smx205022 ddi_regs_map_free(&ngep->io_handle); 16405574Smx205022 16415574Smx205022 if (ngep->progress & PROGRESS_CFG) 16425574Smx205022 pci_config_teardown(&ngep->cfg_handle); 16435574Smx205022 16445574Smx205022 ddi_remove_minor_node(ngep->devinfo, NULL); 16455574Smx205022 16465574Smx205022 kmem_free(ngep, sizeof (*ngep)); 16475574Smx205022 } 16485574Smx205022 16495574Smx205022 static int 16505574Smx205022 nge_resume(dev_info_t *devinfo) 16515574Smx205022 { 16525574Smx205022 nge_t *ngep; 16535574Smx205022 chip_info_t *infop; 16545574Smx205022 16555574Smx205022 ASSERT(devinfo != NULL); 16565574Smx205022 16575574Smx205022 ngep = ddi_get_driver_private(devinfo); 16585574Smx205022 /* 16595574Smx205022 * If there are state inconsistancies, this is bad. Returning 16605574Smx205022 * DDI_FAILURE here will eventually cause the machine to panic, 16615574Smx205022 * so it is best done here so that there is a possibility of 16625574Smx205022 * debugging the problem. 16635574Smx205022 */ 16645574Smx205022 if (ngep == NULL) 16655574Smx205022 cmn_err(CE_PANIC, 16665574Smx205022 "nge: ngep returned from ddi_get_driver_private was NULL"); 16675574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 16685574Smx205022 16695574Smx205022 if (ngep->devinfo != devinfo) 16705574Smx205022 cmn_err(CE_PANIC, 16715574Smx205022 "nge: passed devinfo not the same as saved definfo"); 16725574Smx205022 16735574Smx205022 ngep->suspended = B_FALSE; 16745574Smx205022 16755574Smx205022 /* 16765574Smx205022 * Fetch the config space. Even though we have most of it cached, 16775574Smx205022 * some values *might* change across a suspend/resume. 16785574Smx205022 */ 16795574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 16805574Smx205022 16815574Smx205022 /* 16825574Smx205022 * Start the controller. In this case (and probably most GLDv3 16835574Smx205022 * devices), it is sufficient to call nge_m_start(). 16845574Smx205022 */ 16855574Smx205022 if (nge_m_start((void *)ngep) != DDI_SUCCESS) { 16865574Smx205022 /* 16875574Smx205022 * We note the failure, but return success, as the 16885574Smx205022 * system is still usable without this controller. 16895574Smx205022 */ 16905574Smx205022 cmn_err(CE_WARN, "nge: resume: failed to restart controller"); 16915574Smx205022 } 16925574Smx205022 return (DDI_SUCCESS); 16935574Smx205022 } 16945574Smx205022 16955574Smx205022 /* 16965574Smx205022 * attach(9E) -- Attach a device to the system 16975574Smx205022 * 16985574Smx205022 * Called once for each board successfully probed. 16995574Smx205022 */ 17005574Smx205022 static int 17015574Smx205022 nge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 17025574Smx205022 { 17035574Smx205022 int err; 17045574Smx205022 int i; 17055574Smx205022 int instance; 17065574Smx205022 caddr_t regs; 17075574Smx205022 nge_t *ngep; 17085574Smx205022 chip_info_t *infop; 17095574Smx205022 mac_register_t *macp; 17105574Smx205022 17115574Smx205022 switch (cmd) { 17125574Smx205022 default: 17135574Smx205022 return (DDI_FAILURE); 17145574Smx205022 17155574Smx205022 case DDI_RESUME: 17165574Smx205022 return (nge_resume(devinfo)); 17175574Smx205022 17185574Smx205022 case DDI_ATTACH: 17195574Smx205022 break; 17205574Smx205022 } 17215574Smx205022 17225574Smx205022 ngep = kmem_zalloc(sizeof (*ngep), KM_SLEEP); 17235574Smx205022 instance = ddi_get_instance(devinfo); 17245574Smx205022 ddi_set_driver_private(devinfo, ngep); 17255574Smx205022 ngep->devinfo = devinfo; 17265574Smx205022 17275574Smx205022 (void) snprintf(ngep->ifname, sizeof (ngep->ifname), "%s%d", 17285574Smx205022 NGE_DRIVER_NAME, instance); 17295574Smx205022 err = pci_config_setup(devinfo, &ngep->cfg_handle); 17305574Smx205022 if (err != DDI_SUCCESS) { 17315574Smx205022 nge_problem(ngep, "nge_attach: pci_config_setup() failed"); 17325574Smx205022 goto attach_fail; 17335574Smx205022 } 17345574Smx205022 infop = (chip_info_t *)&ngep->chipinfo; 17355574Smx205022 nge_chip_cfg_init(ngep, infop, B_FALSE); 17365574Smx205022 nge_init_dev_spec_param(ngep); 17375574Smx205022 nge_get_props(ngep); 17385574Smx205022 ngep->progress |= PROGRESS_CFG; 17395574Smx205022 17405574Smx205022 err = ddi_regs_map_setup(devinfo, NGE_PCI_OPREGS_RNUMBER, 17415574Smx205022 ®s, 0, 0, &nge_reg_accattr, &ngep->io_handle); 17425574Smx205022 if (err != DDI_SUCCESS) { 17435574Smx205022 nge_problem(ngep, "nge_attach: ddi_regs_map_setup() failed"); 17445574Smx205022 goto attach_fail; 17455574Smx205022 } 17465574Smx205022 ngep->io_regs = regs; 17475574Smx205022 ngep->progress |= PROGRESS_REGS; 17485574Smx205022 17495574Smx205022 err = nge_register_intrs_and_init_locks(ngep); 17505574Smx205022 if (err != DDI_SUCCESS) { 17515574Smx205022 nge_problem(ngep, "nge_attach:" 17525574Smx205022 " register intrs and init locks failed"); 17535574Smx205022 goto attach_fail; 17545574Smx205022 } 17555574Smx205022 nge_init_ring_param_lock(ngep); 17565574Smx205022 ngep->progress |= PROGRESS_INTR; 17575574Smx205022 17585574Smx205022 mutex_enter(ngep->genlock); 17595574Smx205022 17605574Smx205022 /* 17615574Smx205022 * Initialise link state variables 17625574Smx205022 * Stop, reset & reinitialise the chip. 17635574Smx205022 * Initialise the (internal) PHY. 17645574Smx205022 */ 17655574Smx205022 nge_phys_init(ngep); 17665574Smx205022 err = nge_chip_reset(ngep); 17675574Smx205022 if (err != DDI_SUCCESS) { 17685574Smx205022 nge_problem(ngep, "nge_attach: nge_chip_reset() failed"); 17695574Smx205022 mutex_exit(ngep->genlock); 17705574Smx205022 goto attach_fail; 17715574Smx205022 } 17725574Smx205022 nge_chip_sync(ngep); 17735574Smx205022 17745574Smx205022 /* 17755574Smx205022 * Now that mutex locks are initialized, enable interrupts. 17765574Smx205022 */ 17775574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 17785574Smx205022 /* Call ddi_intr_block_enable() for MSI interrupts */ 17795574Smx205022 (void) ddi_intr_block_enable(ngep->htable, 17805574Smx205022 ngep->intr_actual_cnt); 17815574Smx205022 } else { 17825574Smx205022 /* Call ddi_intr_enable for MSI or FIXED interrupts */ 17835574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 17845574Smx205022 (void) ddi_intr_enable(ngep->htable[i]); 17855574Smx205022 } 17865574Smx205022 } 17875574Smx205022 17885574Smx205022 ngep->link_state = LINK_STATE_UNKNOWN; 17895574Smx205022 ngep->progress |= PROGRESS_HWINT; 17905574Smx205022 17915574Smx205022 /* 17925574Smx205022 * Register NDD-tweakable parameters 17935574Smx205022 */ 17945574Smx205022 if (nge_nd_init(ngep)) { 17955574Smx205022 nge_problem(ngep, "nge_attach: nge_nd_init() failed"); 17965574Smx205022 mutex_exit(ngep->genlock); 17975574Smx205022 goto attach_fail; 17985574Smx205022 } 17995574Smx205022 ngep->progress |= PROGRESS_NDD; 18005574Smx205022 18015574Smx205022 /* 18025574Smx205022 * Create & initialise named kstats 18035574Smx205022 */ 18045574Smx205022 nge_init_kstats(ngep, instance); 18055574Smx205022 ngep->progress |= PROGRESS_KSTATS; 18065574Smx205022 18075574Smx205022 mutex_exit(ngep->genlock); 18085574Smx205022 18095574Smx205022 if ((macp = mac_alloc(MAC_VERSION)) == NULL) 18105574Smx205022 goto attach_fail; 18115574Smx205022 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 18125574Smx205022 macp->m_driver = ngep; 18135574Smx205022 macp->m_dip = devinfo; 18145574Smx205022 macp->m_src_addr = infop->vendor_addr.addr; 18155574Smx205022 macp->m_callbacks = &nge_m_callbacks; 18165574Smx205022 macp->m_min_sdu = 0; 18175574Smx205022 macp->m_max_sdu = ngep->default_mtu; 18185574Smx205022 /* 18195574Smx205022 * Finally, we're ready to register ourselves with the mac 18205574Smx205022 * interface; if this succeeds, we're all ready to start() 18215574Smx205022 */ 18225574Smx205022 err = mac_register(macp, &ngep->mh); 18235574Smx205022 mac_free(macp); 18245574Smx205022 if (err != 0) 18255574Smx205022 goto attach_fail; 18265574Smx205022 18275574Smx205022 /* 18285574Smx205022 * Register a periodical handler. 18295574Smx205022 * nge_chip_cyclic() is invoked in kernel context. 18305574Smx205022 */ 18315574Smx205022 ngep->periodic_id = ddi_periodic_add(nge_chip_cyclic, ngep, 18325574Smx205022 NGE_CYCLIC_PERIOD, DDI_IPL_0); 18335574Smx205022 18345574Smx205022 ngep->progress |= PROGRESS_READY; 18355574Smx205022 return (DDI_SUCCESS); 18365574Smx205022 18375574Smx205022 attach_fail: 18385574Smx205022 nge_unattach(ngep); 18395574Smx205022 return (DDI_FAILURE); 18405574Smx205022 } 18415574Smx205022 18425574Smx205022 /* 18435574Smx205022 * detach(9E) -- Detach a device from the system 18445574Smx205022 */ 18455574Smx205022 static int 18465574Smx205022 nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 18475574Smx205022 { 18485574Smx205022 int i; 18495574Smx205022 nge_t *ngep; 18505574Smx205022 mul_item *p, *nextp; 18515574Smx205022 buff_ring_t *brp; 18525574Smx205022 18535574Smx205022 NGE_GTRACE(("nge_detach($%p, %d)", (void *)devinfo, cmd)); 18545574Smx205022 18555574Smx205022 ngep = ddi_get_driver_private(devinfo); 18565574Smx205022 brp = ngep->buff; 18575574Smx205022 18585574Smx205022 switch (cmd) { 18595574Smx205022 default: 18605574Smx205022 return (DDI_FAILURE); 18615574Smx205022 18625574Smx205022 case DDI_SUSPEND: 18635574Smx205022 /* 18645574Smx205022 * Stop the NIC 18655574Smx205022 * I suspect that we can actually suspend if the stop 18665574Smx205022 * routine returns a failure, as the resume will 18675574Smx205022 * effectively fully reset the hardware (i.e. we don't 18685574Smx205022 * really save any hardware state). However, nge_m_stop 18695574Smx205022 * doesn't return an error code. 18705574Smx205022 * Note: This driver doesn't currently support WOL, but 18715574Smx205022 * should it in the future, it is important to 18725574Smx205022 * make sure the PHY remains powered so that the 18735574Smx205022 * wakeup packet can actually be recieved. 18745574Smx205022 */ 18755574Smx205022 nge_m_stop(ngep); 18765574Smx205022 ngep->suspended = B_TRUE; 18775574Smx205022 return (DDI_SUCCESS); 18785574Smx205022 18795574Smx205022 case DDI_DETACH: 18805574Smx205022 break; 18815574Smx205022 } 18825574Smx205022 18835574Smx205022 /* Try to wait all the buffer post to upper layer be released */ 18845574Smx205022 for (i = 0; i < 1000; i++) { 18855574Smx205022 if (brp->rx_hold == 0) 18865574Smx205022 break; 18875574Smx205022 drv_usecwait(1000); 18885574Smx205022 } 18895574Smx205022 18905574Smx205022 /* If there is any posted buffer, reject to detach */ 18915574Smx205022 if (brp->rx_hold != 0) 18925574Smx205022 return (DDI_FAILURE); 18935574Smx205022 18945574Smx205022 /* Recycle the multicast table */ 18955574Smx205022 for (p = ngep->pcur_mulist; p != NULL; p = nextp) { 18965574Smx205022 nextp = p->next; 18975574Smx205022 kmem_free(p, sizeof (mul_item)); 18985574Smx205022 } 18995574Smx205022 ngep->pcur_mulist = NULL; 19005574Smx205022 19015574Smx205022 /* 19025574Smx205022 * Unregister from the GLD subsystem. This can fail, in 19035574Smx205022 * particular if there are DLPI style-2 streams still open - 19045574Smx205022 * in which case we just return failure without shutting 19055574Smx205022 * down chip operations. 19065574Smx205022 */ 19075574Smx205022 if (mac_unregister(ngep->mh) != DDI_SUCCESS) 19085574Smx205022 return (DDI_FAILURE); 19095574Smx205022 19105574Smx205022 /* 19115574Smx205022 * All activity stopped, so we can clean up & exit 19125574Smx205022 */ 19135574Smx205022 nge_unattach(ngep); 19145574Smx205022 return (DDI_SUCCESS); 19155574Smx205022 } 19165574Smx205022 19175574Smx205022 19185574Smx205022 /* 19195574Smx205022 * ========== Module Loading Data & Entry Points ========== 19205574Smx205022 */ 19215574Smx205022 19225574Smx205022 DDI_DEFINE_STREAM_OPS(nge_dev_ops, nulldev, nulldev, nge_attach, nge_detach, 19235574Smx205022 nodev, NULL, D_MP, NULL); 19245574Smx205022 19255574Smx205022 19265574Smx205022 static struct modldrv nge_modldrv = { 19275574Smx205022 &mod_driverops, /* Type of module. This one is a driver */ 19285574Smx205022 nge_ident, /* short description */ 19295574Smx205022 &nge_dev_ops /* driver specific ops */ 19305574Smx205022 }; 19315574Smx205022 19325574Smx205022 static struct modlinkage modlinkage = { 19335574Smx205022 MODREV_1, (void *)&nge_modldrv, NULL 19345574Smx205022 }; 19355574Smx205022 19365574Smx205022 19375574Smx205022 int 19385574Smx205022 _info(struct modinfo *modinfop) 19395574Smx205022 { 19405574Smx205022 return (mod_info(&modlinkage, modinfop)); 19415574Smx205022 } 19425574Smx205022 19435574Smx205022 int 19445574Smx205022 _init(void) 19455574Smx205022 { 19465574Smx205022 int status; 19475574Smx205022 19485574Smx205022 mac_init_ops(&nge_dev_ops, "nge"); 19495574Smx205022 status = mod_install(&modlinkage); 19505574Smx205022 if (status != DDI_SUCCESS) 19515574Smx205022 mac_fini_ops(&nge_dev_ops); 19525574Smx205022 else 19535574Smx205022 mutex_init(nge_log_mutex, NULL, MUTEX_DRIVER, NULL); 19545574Smx205022 19555574Smx205022 return (status); 19565574Smx205022 } 19575574Smx205022 19585574Smx205022 int 19595574Smx205022 _fini(void) 19605574Smx205022 { 19615574Smx205022 int status; 19625574Smx205022 19635574Smx205022 status = mod_remove(&modlinkage); 19645574Smx205022 if (status == DDI_SUCCESS) { 19655574Smx205022 mac_fini_ops(&nge_dev_ops); 19665574Smx205022 mutex_destroy(nge_log_mutex); 19675574Smx205022 } 19685574Smx205022 19695574Smx205022 return (status); 19705574Smx205022 } 19715574Smx205022 19725574Smx205022 /* 19735574Smx205022 * ============ Init MSI/Fixed/SoftInterrupt routines ============== 19745574Smx205022 */ 19755574Smx205022 19765574Smx205022 /* 19775574Smx205022 * Register interrupts and initialize each mutex and condition variables 19785574Smx205022 */ 19795574Smx205022 19805574Smx205022 static int 19815574Smx205022 nge_register_intrs_and_init_locks(nge_t *ngep) 19825574Smx205022 { 19835574Smx205022 int err; 19845574Smx205022 int intr_types; 19855574Smx205022 uint_t soft_prip; 19865574Smx205022 nge_msi_mask msi_mask; 19875574Smx205022 nge_msi_map0_vec map0_vec; 19885574Smx205022 nge_msi_map1_vec map1_vec; 19895574Smx205022 19905574Smx205022 /* 19915574Smx205022 * Add the softint handlers: 19925574Smx205022 * 19935574Smx205022 * Both of these handlers are used to avoid restrictions on the 19945574Smx205022 * context and/or mutexes required for some operations. In 19955574Smx205022 * particular, the hardware interrupt handler and its subfunctions 19965574Smx205022 * can detect a number of conditions that we don't want to handle 19975574Smx205022 * in that context or with that set of mutexes held. So, these 19985574Smx205022 * softints are triggered instead: 19995574Smx205022 * 20005574Smx205022 * the <resched> softint is triggered if if we have previously 20015574Smx205022 * had to refuse to send a packet because of resource shortage 20025574Smx205022 * (we've run out of transmit buffers), but the send completion 20035574Smx205022 * interrupt handler has now detected that more buffers have 20045574Smx205022 * become available. Its only purpose is to call gld_sched() 20055574Smx205022 * to retry the pending transmits (we're not allowed to hold 20065574Smx205022 * driver-defined mutexes across gld_sched()). 20075574Smx205022 * 20085574Smx205022 * the <factotum> is triggered if the h/w interrupt handler 20095574Smx205022 * sees the <link state changed> or <error> bits in the status 20105574Smx205022 * block. It's also triggered periodically to poll the link 20115574Smx205022 * state, just in case we aren't getting link status change 20125574Smx205022 * interrupts ... 20135574Smx205022 */ 20145574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->resched_hdl, 20155574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_reschedule, (caddr_t)ngep); 20165574Smx205022 if (err != DDI_SUCCESS) { 20175574Smx205022 nge_problem(ngep, 20185574Smx205022 "nge_attach: add nge_reschedule softintr failed"); 20195574Smx205022 20205574Smx205022 return (DDI_FAILURE); 20215574Smx205022 } 20225574Smx205022 ngep->progress |= PROGRESS_RESCHED; 20235574Smx205022 err = ddi_intr_add_softint(ngep->devinfo, &ngep->factotum_hdl, 20245574Smx205022 DDI_INTR_SOFTPRI_MIN, nge_chip_factotum, (caddr_t)ngep); 20255574Smx205022 if (err != DDI_SUCCESS) { 20265574Smx205022 nge_problem(ngep, 20275574Smx205022 "nge_attach: add nge_chip_factotum softintr failed!"); 20285574Smx205022 20295574Smx205022 return (DDI_FAILURE); 20305574Smx205022 } 20315574Smx205022 if (ddi_intr_get_softint_pri(ngep->factotum_hdl, &soft_prip) 20325574Smx205022 != DDI_SUCCESS) { 20335574Smx205022 nge_problem(ngep, "nge_attach: get softintr priority failed\n"); 20345574Smx205022 20355574Smx205022 return (DDI_FAILURE); 20365574Smx205022 } 20375574Smx205022 ngep->soft_pri = soft_prip; 20385574Smx205022 20395574Smx205022 ngep->progress |= PROGRESS_FACTOTUM; 20405574Smx205022 /* Get supported interrupt types */ 20415574Smx205022 if (ddi_intr_get_supported_types(ngep->devinfo, &intr_types) 20425574Smx205022 != DDI_SUCCESS) { 20435574Smx205022 nge_error(ngep, "ddi_intr_get_supported_types failed\n"); 20445574Smx205022 20455574Smx205022 return (DDI_FAILURE); 20465574Smx205022 } 20475574Smx205022 20485574Smx205022 NGE_DEBUG(("ddi_intr_get_supported_types() returned: %x", 20495574Smx205022 intr_types)); 20505574Smx205022 20515574Smx205022 if ((intr_types & DDI_INTR_TYPE_MSI) && nge_enable_msi) { 20525574Smx205022 20535574Smx205022 /* MSI Configurations for mcp55 chipset */ 20545574Smx205022 if (ngep->chipinfo.device == DEVICE_ID_MCP55_373 || 20555574Smx205022 ngep->chipinfo.device == DEVICE_ID_MCP55_372) { 20565574Smx205022 20575574Smx205022 20585574Smx205022 /* Enable the 8 vectors */ 20595574Smx205022 msi_mask.msi_mask_val = 20605574Smx205022 nge_reg_get32(ngep, NGE_MSI_MASK); 20615574Smx205022 msi_mask.msi_msk_bits.vec0 = NGE_SET; 20625574Smx205022 msi_mask.msi_msk_bits.vec1 = NGE_SET; 20635574Smx205022 msi_mask.msi_msk_bits.vec2 = NGE_SET; 20645574Smx205022 msi_mask.msi_msk_bits.vec3 = NGE_SET; 20655574Smx205022 msi_mask.msi_msk_bits.vec4 = NGE_SET; 20665574Smx205022 msi_mask.msi_msk_bits.vec5 = NGE_SET; 20675574Smx205022 msi_mask.msi_msk_bits.vec6 = NGE_SET; 20685574Smx205022 msi_mask.msi_msk_bits.vec7 = NGE_SET; 20695574Smx205022 nge_reg_put32(ngep, NGE_MSI_MASK, 20705574Smx205022 msi_mask.msi_mask_val); 20715574Smx205022 20725574Smx205022 /* 20735574Smx205022 * Remapping the MSI MAP0 and MAP1. MCP55 20745574Smx205022 * is default mapping all the interrupt to 0 vector. 20755574Smx205022 * Software needs to remapping this. 20765574Smx205022 * This mapping is same as CK804. 20775574Smx205022 */ 20785574Smx205022 map0_vec.msi_map0_val = 20795574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP0); 20805574Smx205022 map1_vec.msi_map1_val = 20815574Smx205022 nge_reg_get32(ngep, NGE_MSI_MAP1); 20825574Smx205022 map0_vec.vecs_bits.reint_vec = 0; 20835574Smx205022 map0_vec.vecs_bits.rcint_vec = 0; 20845574Smx205022 map0_vec.vecs_bits.miss_vec = 3; 20855574Smx205022 map0_vec.vecs_bits.teint_vec = 5; 20865574Smx205022 map0_vec.vecs_bits.tcint_vec = 5; 20875574Smx205022 map0_vec.vecs_bits.stint_vec = 2; 20885574Smx205022 map0_vec.vecs_bits.mint_vec = 6; 20895574Smx205022 map0_vec.vecs_bits.rfint_vec = 0; 20905574Smx205022 map1_vec.vecs_bits.tfint_vec = 5; 20915574Smx205022 map1_vec.vecs_bits.feint_vec = 6; 20925574Smx205022 map1_vec.vecs_bits.resv8_11 = 3; 20935574Smx205022 map1_vec.vecs_bits.resv12_15 = 1; 20945574Smx205022 map1_vec.vecs_bits.resv16_19 = 0; 20955574Smx205022 map1_vec.vecs_bits.resv20_23 = 7; 20965574Smx205022 map1_vec.vecs_bits.resv24_31 = 0xff; 20975574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP0, 20985574Smx205022 map0_vec.msi_map0_val); 20995574Smx205022 nge_reg_put32(ngep, NGE_MSI_MAP1, 21005574Smx205022 map1_vec.msi_map1_val); 21015574Smx205022 } 21025574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) { 21035574Smx205022 NGE_DEBUG(("MSI registration failed, " 21045574Smx205022 "trying FIXED interrupt type\n")); 21055574Smx205022 } else { 21065574Smx205022 nge_log(ngep, "Using MSI interrupt type\n"); 21075574Smx205022 21085574Smx205022 ngep->intr_type = DDI_INTR_TYPE_MSI; 21095574Smx205022 ngep->progress |= PROGRESS_SWINT; 21105574Smx205022 } 21115574Smx205022 } 21125574Smx205022 21135574Smx205022 if (!(ngep->progress & PROGRESS_SWINT) && 21145574Smx205022 (intr_types & DDI_INTR_TYPE_FIXED)) { 21155574Smx205022 if (nge_add_intrs(ngep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) { 21165574Smx205022 nge_error(ngep, "FIXED interrupt " 21175574Smx205022 "registration failed\n"); 21185574Smx205022 21195574Smx205022 return (DDI_FAILURE); 21205574Smx205022 } 21215574Smx205022 21225574Smx205022 nge_log(ngep, "Using FIXED interrupt type\n"); 21235574Smx205022 21245574Smx205022 ngep->intr_type = DDI_INTR_TYPE_FIXED; 21255574Smx205022 ngep->progress |= PROGRESS_SWINT; 21265574Smx205022 } 21275574Smx205022 21285574Smx205022 21295574Smx205022 if (!(ngep->progress & PROGRESS_SWINT)) { 21305574Smx205022 nge_error(ngep, "No interrupts registered\n"); 21315574Smx205022 21325574Smx205022 return (DDI_FAILURE); 21335574Smx205022 } 21345574Smx205022 mutex_init(ngep->genlock, NULL, MUTEX_DRIVER, 21355574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 21365574Smx205022 mutex_init(ngep->softlock, NULL, MUTEX_DRIVER, 21375574Smx205022 DDI_INTR_PRI(ngep->soft_pri)); 21385574Smx205022 rw_init(ngep->rwlock, NULL, RW_DRIVER, 21395574Smx205022 DDI_INTR_PRI(ngep->intr_pri)); 21405574Smx205022 21415574Smx205022 return (DDI_SUCCESS); 21425574Smx205022 } 21435574Smx205022 21445574Smx205022 /* 21455574Smx205022 * nge_add_intrs: 21465574Smx205022 * 21475574Smx205022 * Register FIXED or MSI interrupts. 21485574Smx205022 */ 21495574Smx205022 static int 21505574Smx205022 nge_add_intrs(nge_t *ngep, int intr_type) 21515574Smx205022 { 21525574Smx205022 dev_info_t *dip = ngep->devinfo; 21535574Smx205022 int avail, actual, intr_size, count = 0; 21545574Smx205022 int i, flag, ret; 21555574Smx205022 21565574Smx205022 NGE_DEBUG(("nge_add_intrs: interrupt type 0x%x\n", intr_type)); 21575574Smx205022 21585574Smx205022 /* Get number of interrupts */ 21595574Smx205022 ret = ddi_intr_get_nintrs(dip, intr_type, &count); 21605574Smx205022 if ((ret != DDI_SUCCESS) || (count == 0)) { 21615574Smx205022 nge_error(ngep, "ddi_intr_get_nintrs() failure, ret: %d, " 21625574Smx205022 "count: %d", ret, count); 21635574Smx205022 21645574Smx205022 return (DDI_FAILURE); 21655574Smx205022 } 21665574Smx205022 21675574Smx205022 /* Get number of available interrupts */ 21685574Smx205022 ret = ddi_intr_get_navail(dip, intr_type, &avail); 21695574Smx205022 if ((ret != DDI_SUCCESS) || (avail == 0)) { 21705574Smx205022 nge_error(ngep, "ddi_intr_get_navail() failure, " 21715574Smx205022 "ret: %d, avail: %d\n", ret, avail); 21725574Smx205022 21735574Smx205022 return (DDI_FAILURE); 21745574Smx205022 } 21755574Smx205022 21765574Smx205022 if (avail < count) { 21775574Smx205022 NGE_DEBUG(("nitrs() returned %d, navail returned %d\n", 21785574Smx205022 count, avail)); 21795574Smx205022 } 21805574Smx205022 flag = DDI_INTR_ALLOC_NORMAL; 21815574Smx205022 21825574Smx205022 /* Allocate an array of interrupt handles */ 21835574Smx205022 intr_size = count * sizeof (ddi_intr_handle_t); 21845574Smx205022 ngep->htable = kmem_alloc(intr_size, KM_SLEEP); 21855574Smx205022 21865574Smx205022 /* Call ddi_intr_alloc() */ 21875574Smx205022 ret = ddi_intr_alloc(dip, ngep->htable, intr_type, 0, 21885574Smx205022 count, &actual, flag); 21895574Smx205022 21905574Smx205022 if ((ret != DDI_SUCCESS) || (actual == 0)) { 21915574Smx205022 nge_error(ngep, "ddi_intr_alloc() failed %d\n", ret); 21925574Smx205022 21935574Smx205022 kmem_free(ngep->htable, intr_size); 21945574Smx205022 return (DDI_FAILURE); 21955574Smx205022 } 21965574Smx205022 21975574Smx205022 if (actual < count) { 21985574Smx205022 NGE_DEBUG(("Requested: %d, Received: %d\n", 21995574Smx205022 count, actual)); 22005574Smx205022 } 22015574Smx205022 22025574Smx205022 ngep->intr_actual_cnt = actual; 22035574Smx205022 ngep->intr_req_cnt = count; 22045574Smx205022 22055574Smx205022 /* 22065574Smx205022 * Get priority for first msi, assume remaining are all the same 22075574Smx205022 */ 22085574Smx205022 if ((ret = ddi_intr_get_pri(ngep->htable[0], &ngep->intr_pri)) != 22095574Smx205022 DDI_SUCCESS) { 22105574Smx205022 nge_error(ngep, "ddi_intr_get_pri() failed %d\n", ret); 22115574Smx205022 22125574Smx205022 /* Free already allocated intr */ 22135574Smx205022 for (i = 0; i < actual; i++) { 22145574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 22155574Smx205022 } 22165574Smx205022 22175574Smx205022 kmem_free(ngep->htable, intr_size); 22185574Smx205022 22195574Smx205022 return (DDI_FAILURE); 22205574Smx205022 } 22215574Smx205022 /* Test for high level mutex */ 22225574Smx205022 if (ngep->intr_pri >= ddi_intr_get_hilevel_pri()) { 22235574Smx205022 nge_error(ngep, "nge_add_intrs:" 22245574Smx205022 "Hi level interrupt not supported"); 22255574Smx205022 22265574Smx205022 for (i = 0; i < actual; i++) 22275574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 22285574Smx205022 22295574Smx205022 kmem_free(ngep->htable, intr_size); 22305574Smx205022 22315574Smx205022 return (DDI_FAILURE); 22325574Smx205022 } 22335574Smx205022 22345574Smx205022 22355574Smx205022 /* Call ddi_intr_add_handler() */ 22365574Smx205022 for (i = 0; i < actual; i++) { 22375574Smx205022 if ((ret = ddi_intr_add_handler(ngep->htable[i], nge_chip_intr, 22385574Smx205022 (caddr_t)ngep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 22395574Smx205022 nge_error(ngep, "ddi_intr_add_handler() " 22405574Smx205022 "failed %d\n", ret); 22415574Smx205022 22425574Smx205022 /* Free already allocated intr */ 22435574Smx205022 for (i = 0; i < actual; i++) { 22445574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 22455574Smx205022 } 22465574Smx205022 22475574Smx205022 kmem_free(ngep->htable, intr_size); 22485574Smx205022 22495574Smx205022 return (DDI_FAILURE); 22505574Smx205022 } 22515574Smx205022 } 22525574Smx205022 22535574Smx205022 if ((ret = ddi_intr_get_cap(ngep->htable[0], &ngep->intr_cap)) 22545574Smx205022 != DDI_SUCCESS) { 22555574Smx205022 nge_error(ngep, "ddi_intr_get_cap() failed %d\n", ret); 22565574Smx205022 22575574Smx205022 for (i = 0; i < actual; i++) { 22585574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 22595574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 22605574Smx205022 } 22615574Smx205022 22625574Smx205022 kmem_free(ngep->htable, intr_size); 22635574Smx205022 22645574Smx205022 return (DDI_FAILURE); 22655574Smx205022 } 22665574Smx205022 22675574Smx205022 return (DDI_SUCCESS); 22685574Smx205022 } 22695574Smx205022 22705574Smx205022 /* 22715574Smx205022 * nge_rem_intrs: 22725574Smx205022 * 22735574Smx205022 * Unregister FIXED or MSI interrupts 22745574Smx205022 */ 22755574Smx205022 static void 22765574Smx205022 nge_rem_intrs(nge_t *ngep) 22775574Smx205022 { 22785574Smx205022 int i; 22795574Smx205022 22805574Smx205022 NGE_DEBUG(("nge_rem_intrs\n")); 22815574Smx205022 22825574Smx205022 /* Disable all interrupts */ 22835574Smx205022 if (ngep->intr_cap & DDI_INTR_FLAG_BLOCK) { 22845574Smx205022 /* Call ddi_intr_block_disable() */ 22855574Smx205022 (void) ddi_intr_block_disable(ngep->htable, 22865574Smx205022 ngep->intr_actual_cnt); 22875574Smx205022 } else { 22885574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 22895574Smx205022 (void) ddi_intr_disable(ngep->htable[i]); 22905574Smx205022 } 22915574Smx205022 } 22925574Smx205022 22935574Smx205022 /* Call ddi_intr_remove_handler() */ 22945574Smx205022 for (i = 0; i < ngep->intr_actual_cnt; i++) { 22955574Smx205022 (void) ddi_intr_remove_handler(ngep->htable[i]); 22965574Smx205022 (void) ddi_intr_free(ngep->htable[i]); 22975574Smx205022 } 22985574Smx205022 22995574Smx205022 kmem_free(ngep->htable, 23005574Smx205022 ngep->intr_req_cnt * sizeof (ddi_intr_handle_t)); 23015574Smx205022 } 2302