/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2014 QLogic Corporation * The contents of this file are subject to the terms of the * QLogic End User License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the License at * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/ * QLogic_End_User_Software_License.txt * See the License for the specific language governing permissions * and limitations under the License. */ /* * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. */ #include "bnxe.h" #define BNXE_DEF_TX_BD_PAGE_CNT 12 #define BNXE_DEF_TX_COAL_BUF_CNT 10 typedef struct { int bufCnt; int txBdPageCnt; int txCoalBufCnt; } BnxeHwPageConfig; static BnxeHwPageConfig bnxeHwPageConfigs[] = { /* Buffers TX BD Pages TX Coalesce Bufs */ { 1000, 4, 10 }, { 1500, 6, 10 }, { 3000, 12, 10 }, { 0, 0, 0 } }; #if 0 #define MEM_LOG BnxeLogInfo #else #define MEM_LOG #endif ddi_device_acc_attr_t bnxeAccessAttribBAR = { DDI_DEVICE_ATTR_V0, /* devacc_attr_version */ DDI_STRUCTURE_LE_ACC, /* devacc_attr_endian_flags */ DDI_STRICTORDER_ACC, /* devacc_attr_dataorder */ DDI_DEFAULT_ACC /* devacc_attr_access */ }; ddi_device_acc_attr_t bnxeAccessAttribBUF = { DDI_DEVICE_ATTR_V0, /* devacc_attr_version */ DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */ DDI_STRICTORDER_ACC, /* devacc_attr_dataorder */ DDI_DEFAULT_ACC /* devacc_attr_access */ }; ddi_dma_attr_t bnxeDmaPageAttrib = { DMA_ATTR_V0, /* dma_attr_version */ 0, /* dma_attr_addr_lo */ 0xffffffffffffffff, /* dma_attr_addr_hi */ 0xffffffffffffffff, /* dma_attr_count_max */ 0, /* dma_attr_align */ 0xffffffff, /* dma_attr_burstsizes */ 1, /* dma_attr_minxfer */ 0xffffffffffffffff, /* dma_attr_maxxfer */ 0xffffffffffffffff, /* dma_attr_seg */ 1, /* dma_attr_sgllen */ 1, /* dma_attr_granular */ 0, /* dma_attr_flags */ }; void mm_wait(lm_device_t * pDev, u32_t delayUs) { (void)pDev; drv_usecwait(delayUs); } lm_status_t mm_read_pci(lm_device_t * pDev, u32_t pciReg, u32_t * pRegValue) { um_device_t * pUM = (um_device_t *)pDev; *pRegValue = pci_config_get32(pUM->pPciCfg, (off_t)pciReg); return LM_STATUS_SUCCESS; } lm_status_t mm_write_pci(lm_device_t * pDev, u32_t pciReg, u32_t regValue) { um_device_t * pUM = (um_device_t *)pDev; pci_config_put32(pUM->pPciCfg, (off_t)pciReg, regValue); return LM_STATUS_SUCCESS; } void BnxeInitBdCnts(um_device_t * pUM, int cli_idx) { lm_device_t * pLM = (lm_device_t *)pUM; BnxeHwPageConfig * pPageCfg; pLM->params.l2_tx_bd_page_cnt[cli_idx] = BNXE_DEF_TX_BD_PAGE_CNT; pLM->params.l2_tx_coal_buf_cnt[cli_idx] = BNXE_DEF_TX_COAL_BUF_CNT; pPageCfg = &bnxeHwPageConfigs[0]; while (pPageCfg->bufCnt) { if (pLM->params.l2_rx_desc_cnt[cli_idx] <= pPageCfg->bufCnt) { pLM->params.l2_tx_bd_page_cnt[cli_idx] = pPageCfg->txBdPageCnt; pLM->params.l2_tx_coal_buf_cnt[cli_idx] = pPageCfg->txCoalBufCnt; break; } pPageCfg++; } } extern u32_t LOG2(u32_t v); unsigned long log2_align(unsigned long n); lm_status_t mm_get_user_config(lm_device_t * pLM) { um_device_t * pUM = (um_device_t *)pLM; u32_t total_size; u32_t required_page_size; BnxeCfgInit(pUM); pLM->params.sw_config = LM_SWCFG_10G; pLM->params.ofld_cap = (LM_OFFLOAD_TX_IP_CKSUM | LM_OFFLOAD_RX_IP_CKSUM | LM_OFFLOAD_TX_TCP_CKSUM | LM_OFFLOAD_RX_TCP_CKSUM | LM_OFFLOAD_TX_TCP6_CKSUM | LM_OFFLOAD_RX_TCP6_CKSUM | LM_OFFLOAD_TX_UDP_CKSUM | LM_OFFLOAD_RX_UDP_CKSUM | LM_OFFLOAD_TX_UDP6_CKSUM | LM_OFFLOAD_RX_UDP6_CKSUM); /* XXX Wake on LAN? */ //pLM->params.wol_cap = (LM_WAKE_UP_MODE_MAGIC_PACKET | LM_WAKE_UP_MODE_NWUF); /* keep the VLAN tag in the mac header when receiving */ pLM->params.keep_vlan_tag = 1; /* set in BnxeIntrInit based on the allocated number of MSIX interrupts */ //pLM->params.rss_chain_cnt = pUM->devParams.numRings; //pLM->params.tss_chain_cnt = pUM->devParams.numRings; pLM->params.l2_rx_desc_cnt[LM_CLI_IDX_NDIS] = pUM->devParams.numRxDesc[LM_CLI_IDX_NDIS]; pLM->params.l2_tx_bd_page_cnt[LM_CLI_IDX_NDIS] = 0; pLM->params.l2_tx_coal_buf_cnt[LM_CLI_IDX_NDIS] = 0; BnxeInitBdCnts(pUM, LM_CLI_IDX_NDIS); pLM->params.l2_rx_desc_cnt[LM_CLI_IDX_FWD] = 0; pLM->params.l2_tx_bd_page_cnt[LM_CLI_IDX_FWD] = 0; pLM->params.l2_tx_coal_buf_cnt[LM_CLI_IDX_FWD] = 0; pLM->params.l2_rx_desc_cnt[LM_CLI_IDX_ISCSI] = 0; pLM->params.l2_tx_bd_page_cnt[LM_CLI_IDX_ISCSI] = 0; pLM->params.l2_tx_coal_buf_cnt[LM_CLI_IDX_ISCSI] = 0; pLM->params.l2_rx_desc_cnt[LM_CLI_IDX_FCOE] = 0; pLM->params.l2_tx_bd_page_cnt[LM_CLI_IDX_FCOE] = 0; pLM->params.l2_tx_coal_buf_cnt[LM_CLI_IDX_FCOE] = 0; pLM->params.max_func_toe_cons = 0; pLM->params.max_func_iscsi_cons = 0; pLM->params.max_func_rdma_cons = 0; pLM->params.max_func_fcoe_cons = pUM->lm_dev.hw_info.max_port_fcoe_conn; pLM->params.max_func_connections = log2_align(pLM->params.max_func_toe_cons + pLM->params.max_func_rdma_cons + pLM->params.max_func_iscsi_cons + pLM->params.max_func_fcoe_cons + MAX_ETH_CONS); /* determine: 1. itl_client_page_size, #context in page*/ /* based on PCIe block INIT document */ /* We now need to calculate the page size based on the maximum number of * connections supported. Since this property is identical to all ports, and * is configured in COMMON registers, we need to use the maximum number of * connections in all ports. */ /* The L2P table is used to map logical addresses to physical ones. There * are four clients that use this table. We want to use only the ILT * (Internal), we need to calculate the total size required for all clients, * divide it by the number of entries in the ILT table and that will give us * the page size we want. The following table describes the needs of each of * these clients: * * HW block(L2P client) Area name Size [B] * Searcher T1 ROUNDUP(LOG2(N)) * 64 * Timers Linear Array N * 8 * QM Queues N * 32 * 4 * CDU Context N * S + W * ROUNDUP (N/m) (W=0) * * N: Number of connections * S: Context Size * W: Block Waste (not really interesting) we configure the context size to * be a power of 2. * m: Number of cids in a block (not really interesting, since W will always * be 0) */ total_size = (pLM->hw_info.max_common_conns * (SEARCHER_TOTAL_MEM_REQUIRED_PER_CON + TIMERS_TOTAL_MEM_REQUIRED_PER_CON + QM_TOTAL_MEM_REQUIRED_PER_CON + pLM->params.context_line_size)); required_page_size = (total_size / ILT_NUM_PAGE_ENTRIES_PER_FUNC); required_page_size = (2 << LOG2(required_page_size)); if (required_page_size < LM_PAGE_SIZE) { required_page_size = LM_PAGE_SIZE; } pLM->params.ilt_client_page_size = required_page_size; pLM->params.num_context_in_page = (pLM->params.ilt_client_page_size / pLM->params.context_line_size); if (pUM->devParams.intrCoalesce) { pLM->params.int_coalesing_mode = LM_INT_COAL_PERIODIC_SYNC; pLM->params.int_per_sec_rx_override = pUM->devParams.intrRxPerSec; pLM->params.int_per_sec_tx_override = pUM->devParams.intrTxPerSec; } else { pLM->params.int_coalesing_mode = LM_INT_COAL_NONE; } pLM->params.enable_dynamic_hc[0] = 0; pLM->params.enable_dynamic_hc[1] = 0; pLM->params.enable_dynamic_hc[2] = 0; pLM->params.enable_dynamic_hc[3] = 0; /* * l2_fw_flow_ctrl is read from the shmem in MF mode in E2 and above. In * all other cases this parameter is read from the driver conf. We also * read this parameter from the driver conf in E1.5 MF mode since 57711 * boot code does not have the struct func_ext_cfg. */ if (((pLM->hw_info.mf_info.mf_mode != MULTI_FUNCTION_SI) && (pLM->hw_info.mf_info.mf_mode != MULTI_FUNCTION_AFEX)) || (CHIP_IS_E1x(pLM))) { pLM->params.l2_fw_flow_ctrl = (pUM->devParams.l2_fw_flow_ctrl) ? 1 : 0; } pLM->params.rcv_buffer_offset = BNXE_DMA_RX_OFFSET; pLM->params.debug_cap_flags = DEFAULT_DEBUG_CAP_FLAGS_VAL; pLM->params.max_fcoe_task = lm_fc_max_fcoe_task_sup(pLM); /* enable rate shaping */ pLM->params.cmng_enable = 1; pLM->params.validate_sq_complete = 1; return LM_STATUS_SUCCESS; } static boolean_t BnxeIsBarUsed(um_device_t * pUM, int regNumber, offset_t offset, u32_t size) { BnxeMemRegion * pMem; BNXE_LOCK_ENTER_MEM(pUM); pMem = (BnxeMemRegion *)d_list_peek_head(&pUM->memRegionList); while (pMem) { if ((pMem->regNumber == regNumber) && (pMem->offset == offset) && (pMem->size == size)) { BNXE_LOCK_EXIT_MEM(pUM); return B_TRUE; } pMem = (BnxeMemRegion *)d_list_next_entry(D_LINK_CAST(pMem)); } BNXE_LOCK_EXIT_MEM(pUM); return B_FALSE; } void * mm_map_io_base(lm_device_t * pLM, lm_address_t baseAddr, u32_t size, u8_t bar) { um_device_t * pUM = (um_device_t *)pLM; BnxeMemRegion * pMem; //int numRegs; off_t regSize; int rc; /* * Solaris identifies: * BAR 0 - size 0 (pci config regs?) * BAR 1 - size 0x800000 (Everest 1/2 LM BAR 0) * BAR 2 - size 0x4000000 (Everest 1 LM BAR 1) * 0x800000 (Everest 2 LM BAR 1) * BAR 3 - size 0x10000 (Everest 2 LM BAR 2) */ bar++; //ddi_dev_nregs(pUM->pDev, &numRegs); ddi_dev_regsize(pUM->pDev, bar, ®Size); if ((size > regSize) || BnxeIsBarUsed(pUM, bar, 0, size)) { BnxeLogWarn(pUM, "BAR %d at offset %d and size %d is already being used!", bar, 0, (int)regSize); return NULL; } if ((pMem = kmem_zalloc(sizeof(BnxeMemRegion), KM_NOSLEEP)) == NULL) { BnxeLogWarn(pUM, "Memory allocation for BAR %d at offset %d and size %d failed!", bar, 0, (int)regSize); return NULL; } if ((rc = ddi_regs_map_setup(pUM->pDev, bar, // bar number &pMem->pRegAddr, 0, // region map offset, size, // region memory window size (0=all) &bnxeAccessAttribBAR, &pMem->regAccess)) != DDI_SUCCESS) { BnxeLogWarn(pUM, "Failed to memory map device (BAR=%d, offset=%d, size=%d) (%d)", bar, 0, size, rc); kmem_free(pMem, sizeof(BnxeMemRegion)); return NULL; } pMem->baseAddr = baseAddr; pMem->regNumber = bar; pMem->offset = 0; pMem->size = size; BNXE_LOCK_ENTER_MEM(pUM); d_list_push_head(&pUM->memRegionList, D_LINK_CAST(pMem)); BNXE_LOCK_EXIT_MEM(pUM); bar--; pLM->vars.reg_handle[bar] = pMem->regAccess; return pMem->pRegAddr; } void * mm_map_io_space_solaris(lm_device_t * pLM, lm_address_t physAddr, u8_t bar, u32_t offset, u32_t size, ddi_acc_handle_t * pRegAccHandle) { um_device_t * pUM = (um_device_t *)pLM; BnxeMemRegion * pMem; off_t regSize; int rc; /* see bar mapping described in mm_map_io_base above */ bar++; ddi_dev_regsize(pUM->pDev, bar, ®Size); if ((size > regSize) || BnxeIsBarUsed(pUM, bar, offset, size)) { BnxeLogWarn(pUM, "BAR %d at offset %d and size %d is already being used!", bar, offset, (int)regSize); return NULL; } if ((pMem = kmem_zalloc(sizeof(BnxeMemRegion), KM_NOSLEEP)) == NULL) { BnxeLogWarn(pUM, "Memory allocation for BAR %d at offset %d and size %d failed!", bar, offset, (int)regSize); return NULL; } if ((rc = ddi_regs_map_setup(pUM->pDev, bar, // bar number &pMem->pRegAddr, offset, // region map offset, size, // region memory window size (0=all) &bnxeAccessAttribBAR, pRegAccHandle)) != DDI_SUCCESS) { BnxeLogWarn(pUM, "Failed to memory map device (BAR=%d, offset=%d, size=%d) (%d)", bar, offset, size, rc); kmem_free(pMem, sizeof(BnxeMemRegion)); return NULL; } pMem->baseAddr = physAddr; pMem->regNumber = bar; pMem->offset = offset; pMem->size = size; pMem->regAccess = *pRegAccHandle; BNXE_LOCK_ENTER_MEM(pUM); d_list_push_head(&pUM->memRegionList, D_LINK_CAST(pMem)); BNXE_LOCK_EXIT_MEM(pUM); return pMem->pRegAddr; } void mm_unmap_io_space(lm_device_t * pLM, void * pVirtAddr, u32_t size) { um_device_t * pUM = (um_device_t *)pLM; BnxeMemRegion * pMemRegion; BNXE_LOCK_ENTER_MEM(pUM); pMemRegion = (BnxeMemRegion *)d_list_peek_head(&pUM->memRegionList); while (pMemRegion) { if ((pMemRegion->pRegAddr == pVirtAddr) && (pMemRegion->size == size)) { d_list_remove_entry(&pUM->memRegionList, D_LINK_CAST(pMemRegion)); ddi_regs_map_free(&pMemRegion->regAccess); kmem_free(pMemRegion, sizeof(BnxeMemRegion)); break; } pMemRegion = (BnxeMemRegion *)d_list_next_entry(D_LINK_CAST(pMemRegion)); } BNXE_LOCK_EXIT_MEM(pUM); } void * mm_alloc_mem_imp(lm_device_t * pLM, u32_t memSize, const char * sz_file, const unsigned long line, u8_t cli_idx) { um_device_t * pUM = (um_device_t *)pLM; BnxeMemBlock * pMem; void * pBuf; u32_t * pTmp; int i; (void)cli_idx; if ((pMem = kmem_zalloc(sizeof(BnxeMemBlock), KM_NOSLEEP)) == NULL) { return NULL; } /* allocated space for header/trailer checks */ memSize += (BNXE_MEM_CHECK_LEN * 2); MEM_LOG(pUM, "*** MEM: %8u", memSize); if ((pBuf = kmem_zalloc(memSize, KM_NOSLEEP)) == NULL) { BnxeLogWarn(pUM, "Failed to allocate memory"); kmem_free(pMem, sizeof(BnxeMemBlock)); return NULL; } /* fill in the header check */ for (i = 0, pTmp = (u32_t *)pBuf; i < BNXE_MEM_CHECK_LEN; i += 4, pTmp++) { *pTmp = BNXE_MAGIC; } /* fill in the trailer check */ for (i = 0, pTmp = (u32_t *)((char *)pBuf + memSize - BNXE_MEM_CHECK_LEN); i < BNXE_MEM_CHECK_LEN; i += 4, pTmp++) { *pTmp = BNXE_MAGIC; } pMem->size = memSize; pMem->pBuf = pBuf; snprintf(pMem->fileName, sizeof(pMem->fileName), "%s", sz_file); pMem->fileLine = line; BNXE_LOCK_ENTER_MEM(pUM); d_list_push_head(&pUM->memBlockList, D_LINK_CAST(pMem)); BNXE_LOCK_EXIT_MEM(pUM); MEM_LOG(pUM, "Allocated %d byte block virt:%p", memSize, ((char *)pBuf + BNXE_MEM_CHECK_LEN)); return ((char *)pBuf + BNXE_MEM_CHECK_LEN); } void * mm_alloc_phys_mem_align_imp(lm_device_t * pLM, u32_t memSize, lm_address_t * pPhysAddr, u32_t alignment, u8_t memType, const char * sz_file, const unsigned long line, u8_t cli_idx) { um_device_t * pUM = (um_device_t *)pLM; int rc; caddr_t pBuf; size_t length; unsigned int count; ddi_dma_attr_t dmaAttrib; ddi_dma_handle_t * pDmaHandle; ddi_acc_handle_t * pDmaAccHandle; ddi_dma_cookie_t cookie; BnxeMemDma * pMem; size_t size; (void)memType; (void)cli_idx; if (memSize == 0) { return NULL; } if ((pMem = kmem_zalloc(sizeof(BnxeMemDma), KM_NOSLEEP)) == NULL) { return NULL; } dmaAttrib = bnxeDmaPageAttrib; dmaAttrib.dma_attr_align = alignment; pDmaHandle = &pMem->dmaHandle; pDmaAccHandle = &pMem->dmaAccHandle; size = memSize; size += (alignment - 1); size &= ~((u32_t)(alignment - 1)); MEM_LOG(pUM, "*** DMA: %8u (%4d) - %8u", memSize, alignment, size); if ((rc = ddi_dma_alloc_handle(pUM->pDev, &dmaAttrib, DDI_DMA_DONTWAIT, (void *)0, pDmaHandle)) != DDI_SUCCESS) { BnxeLogWarn(pUM, "Failed to alloc DMA handle"); kmem_free(pMem, sizeof(BnxeMemDma)); return NULL; } if ((rc = ddi_dma_mem_alloc(*pDmaHandle, size, &bnxeAccessAttribBUF, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, (void *)0, &pBuf, &length, pDmaAccHandle)) != DDI_SUCCESS) { BnxeLogWarn(pUM, "Failed to alloc DMA memory"); ddi_dma_free_handle(pDmaHandle); kmem_free(pMem, sizeof(BnxeMemDma)); return NULL; } if ((rc = ddi_dma_addr_bind_handle(*pDmaHandle, (struct as *)0, pBuf, length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, (void *)0, &cookie, &count)) != DDI_DMA_MAPPED) { BnxeLogWarn(pUM, "Failed to bind DMA address"); ddi_dma_mem_free(pDmaAccHandle); ddi_dma_free_handle(pDmaHandle); kmem_free(pMem, sizeof(BnxeMemDma)); return NULL; } pPhysAddr->as_u64 = cookie.dmac_laddress; /* save the virtual memory address so we can get the dma_handle later */ pMem->size = memSize; pMem->pDmaVirt = pBuf; pMem->physAddr = *pPhysAddr; snprintf(pMem->fileName, sizeof(pMem->fileName), "%s", sz_file); pMem->fileLine = line; #if 0 MEM_LOG(pUM, "*** DMA: virt %p / phys 0x%0llx (%d/%d)", pBuf, pPhysAddr->as_u64, (!((u32_t)pBuf % (u32_t)alignment)) ? 1 : 0, (!((u32_t)pPhysAddr->as_ptr % (u32_t)alignment) ? 1 : 0)); #endif BNXE_LOCK_ENTER_MEM(pUM); d_list_push_head(&pUM->memDmaList, D_LINK_CAST(pMem)); BNXE_LOCK_EXIT_MEM(pUM); MEM_LOG(pUM, "Allocated %d sized DMA block phys:%p virt:%p", memSize, pMem->physAddr.as_ptr, pMem->pDmaVirt); /* Zero memory! */ bzero(pBuf, length); /* make sure the new contents are flushed back to main memory */ ddi_dma_sync(*pDmaHandle, 0, length, DDI_DMA_SYNC_FORDEV); return pBuf; } void * mm_alloc_phys_mem_imp(lm_device_t * pLM, u32_t memSize, lm_address_t * pPhysAddr, u8_t memType, const char * sz_file, const unsigned long line, u8_t cli_idx) { return mm_alloc_phys_mem_align_imp(pLM, memSize, pPhysAddr, BNXE_DMA_ALIGNMENT, memType, sz_file, line, cli_idx); } void * mm_rt_alloc_mem_imp(lm_device_t * pDev, u32_t memSize, const char * sz_file, const unsigned long line, u8_t cli_idx) { return mm_alloc_mem_imp(pDev, memSize, sz_file, line, cli_idx); } void * mm_rt_alloc_phys_mem_imp(lm_device_t * pDev, u32_t memSize, lm_address_t * pPhysAddr, u8_t flushType, const char * sz_file, const unsigned long line, u8_t cli_idx) { return mm_alloc_phys_mem_imp(pDev, memSize, pPhysAddr, flushType, sz_file, line, cli_idx); } u64_t mm_get_current_time(lm_device_t * pDev) { um_device_t * pUM = (um_device_t *)pDev; BnxeDbgBreakMsg(pUM, "MM_GET_CURRENT_TIME"); return 0; } void mm_rt_free_mem(lm_device_t * pDev, void * pBuf, u32_t memSize, u8_t cli_idx) { um_device_t * pUM = (um_device_t *)pDev; BnxeMemBlock * pMem; u32_t * pTmp; int i; (void)cli_idx; BNXE_LOCK_ENTER_MEM(pUM); pMem = (BnxeMemBlock *)d_list_peek_head(&pUM->memBlockList); /* adjuest for header/trailer checks */ pBuf = ((char *)pBuf - BNXE_MEM_CHECK_LEN); memSize += (BNXE_MEM_CHECK_LEN * 2); /* verify header check */ for (i = 0, pTmp = (u32_t *)pBuf; i < BNXE_MEM_CHECK_LEN; i += 4, pTmp++) { if (*pTmp != BNXE_MAGIC) { BnxeLogWarn(pUM, "Header overflow! (%p/%u)", pBuf, memSize); BnxeDbgBreak(pUM); } } /* verify trailer check */ for (i = 0, pTmp = (u32_t *)((char *)pBuf + memSize - BNXE_MEM_CHECK_LEN); i < BNXE_MEM_CHECK_LEN; i += 4, pTmp++) { if (*pTmp != BNXE_MAGIC) { BnxeLogWarn(pUM, "Trailer overflow! (%p/%u)", pBuf, memSize); BnxeDbgBreak(pUM); } } while (pMem) { if (pBuf == pMem->pBuf) { if (memSize != pMem->size) { /* Uh-Oh! */ BnxeLogWarn(pUM, "Attempt to free memory block with invalid size (%d/%d)", memSize, pMem->size); BnxeDbgBreak(pUM); BNXE_LOCK_EXIT_MEM(pUM); return; } d_list_remove_entry(&pUM->memBlockList, D_LINK_CAST(pMem)); kmem_free(pBuf, memSize); kmem_free(pMem, sizeof(BnxeMemBlock)); BNXE_LOCK_EXIT_MEM(pUM); return; } pMem = (BnxeMemBlock *)d_list_next_entry(D_LINK_CAST(pMem)); } BNXE_LOCK_EXIT_MEM(pUM); } void mm_rt_free_phys_mem(lm_device_t * pDev, u32_t memSize, void * pBuf, lm_address_t pPhysAddr, u8_t cli_idx) { um_device_t * pUM = (um_device_t *)pDev; BnxeMemDma * pMem; (void)pPhysAddr; (void)cli_idx; BNXE_LOCK_ENTER_MEM(pUM); pMem = (BnxeMemDma *)d_list_peek_head(&pUM->memDmaList); while (pMem) { if (pBuf == pMem->pDmaVirt) { if (memSize != pMem->size) { /* Uh-Oh! */ BnxeLogWarn(pUM, "Attempt to free DMA memory with invalid size (%d/%d)", memSize, pMem->size); BnxeDbgBreak(pUM); BNXE_LOCK_EXIT_MEM(pUM); return; } d_list_remove_entry(&pUM->memDmaList, D_LINK_CAST(pMem)); ddi_dma_unbind_handle(pMem->dmaHandle); ddi_dma_mem_free(&pMem->dmaAccHandle); ddi_dma_free_handle(&pMem->dmaHandle); kmem_free(pMem, sizeof(BnxeMemDma)); BNXE_LOCK_EXIT_MEM(pUM); return; } pMem = (BnxeMemDma *)d_list_next_entry(D_LINK_CAST(pMem)); } BNXE_LOCK_EXIT_MEM(pUM); } void mm_memset(void * pBuf, u8_t val, u32_t memSize) { memset(pBuf, val, memSize); } void mm_memcpy(void * pDest, const void * pSrc, u32_t memSize) { memcpy(pDest, pSrc, memSize); } u8_t mm_memcmp(void * pBuf1, void * pBuf2, u32_t count) { return (memcmp(pBuf1, pBuf2, count) == 0) ? 1 : 0; } void mm_indicate_tx(lm_device_t * pLM, u32_t idx, s_list_t * packet_list) { BnxeTxPktsReclaim((um_device_t *)pLM, idx, packet_list); } void mm_set_done(lm_device_t * pDev, u32_t cid, void * cookie) { #if 0 um_device_t * pUM = (um_device_t *)pDev; BnxeLogInfo(pUM, "RAMROD on cid %d cmd is done", cid); #else (void)pDev; (void)cid; #endif } void mm_return_sq_pending_command(lm_device_t * pDev, struct sq_pending_command * pPending) { /* XXX probably need a memory pool to pull from... */ mm_rt_free_mem(pDev, pPending, sizeof(struct sq_pending_command), LM_CLI_IDX_NDIS); } struct sq_pending_command * mm_get_sq_pending_command(lm_device_t * pDev) { /* XXX probably need a memory pool to pull from... */ return mm_rt_alloc_mem(pDev, sizeof(struct sq_pending_command), LM_CLI_IDX_NDIS); } u32_t mm_copy_packet_buf(lm_device_t * pDev, lm_packet_t * pLMPkt, u8_t * pMemBuf, u32_t size) { //um_device_t * pUM = (um_device_t *)pDev; um_txpacket_t * pTxPkt = (um_txpacket_t *)pLMPkt; mblk_t * pMblk; u32_t copied; u32_t mblkDataLen; u32_t toCopy; pMblk = pTxPkt->pMblk; copied = 0; while (size && pMblk) { mblkDataLen = (pMblk->b_wptr - pMblk->b_rptr); toCopy = (mblkDataLen <= size) ? mblkDataLen : size; bcopy(pMblk->b_rptr, pMemBuf, toCopy); pMemBuf += toCopy; copied += toCopy; size -= toCopy; pMblk = pMblk->b_cont; } return copied; } lm_status_t mm_fan_failure(lm_device_t * pDev) { um_device_t * pUM = (um_device_t *)pDev; BnxeLogWarn(pUM, "FAN FAILURE!"); return LM_STATUS_SUCCESS; } static void BnxeLinkStatus(um_device_t * pUM, lm_status_t link, lm_medium_t medium) { #define TBUF_SIZE 64 char tbuf[TBUF_SIZE]; char * pDuplex; char * pRxFlow; char * pTxFlow; char * pSpeed; if (link != LM_STATUS_LINK_ACTIVE) { /* reset the link status */ pUM->props.link_speed = 0; pUM->props.link_duplex = B_FALSE; pUM->props.link_txpause = B_FALSE; pUM->props.link_rxpause = B_FALSE; pUM->props.uptime = 0; /* reset the link partner status */ pUM->remote.link_autoneg = B_FALSE; pUM->remote.param_20000fdx = B_FALSE; pUM->remote.param_10000fdx = B_FALSE; pUM->remote.param_2500fdx = B_FALSE; pUM->remote.param_1000fdx = B_FALSE; pUM->remote.param_100fdx = B_FALSE; pUM->remote.param_100hdx = B_FALSE; pUM->remote.param_10fdx = B_FALSE; pUM->remote.param_10hdx = B_FALSE; pUM->remote.param_txpause = B_FALSE; pUM->remote.param_rxpause = B_FALSE; BnxeLogInfo(pUM, "Link Down"); return; } pUM->props.uptime = ddi_get_time(); if (GET_MEDIUM_DUPLEX(medium) == LM_MEDIUM_HALF_DUPLEX) { pDuplex = "Half"; pUM->props.link_duplex = B_FALSE; } else { pDuplex = "Full"; pUM->props.link_duplex = B_TRUE; } if (pUM->lm_dev.vars.flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) { pRxFlow = "ON"; pUM->props.link_rxpause = B_TRUE; } else { pRxFlow = "OFF"; pUM->props.link_rxpause = B_FALSE; } if (pUM->lm_dev.vars.flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE) { pTxFlow = "ON"; pUM->props.link_txpause = B_TRUE; } else { pTxFlow = "OFF"; pUM->props.link_txpause = B_FALSE; } #if 0 if (pUM->curcfg.lnkcfg.link_autoneg == B_TRUE) { BnxeUpdateLpCap(pUM); } #endif switch (GET_MEDIUM_SPEED(medium)) { case LM_MEDIUM_SPEED_10MBPS: pUM->props.link_speed = 10; pSpeed = "10Mb"; break; case LM_MEDIUM_SPEED_100MBPS: pUM->props.link_speed = 100; pSpeed = "100Mb"; break; case LM_MEDIUM_SPEED_1000MBPS: pUM->props.link_speed = 1000; pSpeed = "1Gb"; break; case LM_MEDIUM_SPEED_2500MBPS: pUM->props.link_speed = 2500; pSpeed = "2.5Gb"; break; case LM_MEDIUM_SPEED_10GBPS: pUM->props.link_speed = 10000; pSpeed = "10Gb"; break; case LM_MEDIUM_SPEED_12GBPS: pUM->props.link_speed = 12000; pSpeed = "12Gb"; break; case LM_MEDIUM_SPEED_12_5GBPS: pUM->props.link_speed = 12500; pSpeed = "12.5Gb"; break; case LM_MEDIUM_SPEED_13GBPS: pUM->props.link_speed = 13000; pSpeed = "13Gb"; break; case LM_MEDIUM_SPEED_15GBPS: pUM->props.link_speed = 15000; pSpeed = "15Gb"; break; case LM_MEDIUM_SPEED_16GBPS: pUM->props.link_speed = 16000; pSpeed = "16Gb"; break; case LM_MEDIUM_SPEED_20GBPS: pUM->props.link_speed = 20000; pSpeed = "20Gb"; break; default: if ((GET_MEDIUM_SPEED(medium) >= LM_MEDIUM_SPEED_SEQ_START) && (GET_MEDIUM_SPEED(medium) <= LM_MEDIUM_SPEED_SEQ_END)) { pUM->props.link_speed = (((GET_MEDIUM_SPEED(medium) >> 8) - (LM_MEDIUM_SPEED_SEQ_START >> 8) + 1) * 100); snprintf(tbuf, TBUF_SIZE, "%u", pUM->props.link_speed); pSpeed = tbuf; break; } pUM->props.link_speed = 0; pSpeed = ""; break; } if (*pSpeed == 0) { BnxeLogInfo(pUM, "%s Duplex Rx Flow %s Tx Flow %s Link Up", pDuplex, pRxFlow, pTxFlow); } else { BnxeLogInfo(pUM, "%s %s Duplex Rx Flow %s Tx Flow %s Link Up", pSpeed, pDuplex, pRxFlow, pTxFlow); } } void mm_indicate_link(lm_device_t * pLM, lm_status_t link, lm_medium_t medium) { um_device_t * pUM = (um_device_t *)pLM; /* ignore link status if it has not changed since the last indicate */ if ((pUM->devParams.lastIndLink == link) && (pUM->devParams.lastIndMedium == medium)) { return; } pUM->devParams.lastIndLink = link; pUM->devParams.lastIndMedium = medium; BnxeLinkStatus(pUM, link, medium); if (CLIENT_BOUND(pUM, LM_CLI_IDX_NDIS)) { BnxeGldLink(pUM, (link == LM_STATUS_LINK_ACTIVE) ? LINK_STATE_UP : LINK_STATE_DOWN); } if (CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)) { if (pUM->fcoe.pDev == NULL) { BnxeLogWarn(pUM, "FCoE Client bound and pDev is NULL (LINK STATUS failed!) %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); } else if (pUM->fcoe.bind.cliCtl == NULL) { BnxeLogWarn(pUM, "FCoE Client bound and cliCtl is NULL (LINK STATUS failed!) %s@%s", BNXEF_NAME, ddi_get_name_addr(pUM->pDev)); } else { pUM->fcoe.bind.cliCtl(pUM->fcoe.pDev, (link == LM_STATUS_LINK_ACTIVE) ? CLI_CTL_LINK_UP : CLI_CTL_LINK_DOWN, NULL, 0); } } } lm_status_t mm_schedule_task(lm_device_t * pDev, u32_t delay_ms, lm_task_cb_t task, void * param) { um_device_t * pUM = (um_device_t *)pDev; BnxeWorkQueueAddDelayNoCopy(pUM, (void (*)(um_device_t *, void *))task, param, delay_ms); return LM_STATUS_SUCCESS; } lm_status_t mm_register_lpme(lm_device_t * pDev, lm_generic_workitem_function * func, u8_t b_fw_access, u8_t b_queue_for_fw) { um_device_t * pUM = (um_device_t *)pDev; (void)b_fw_access; (void)b_queue_for_fw; BnxeWorkQueueAddGeneric(pUM, (void (*)(um_device_t *))func); return LM_STATUS_SUCCESS; } void MM_ACQUIRE_SPQ_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_SPQ((um_device_t *)pDev); } void MM_RELEASE_SPQ_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_SPQ((um_device_t *)pDev); } void MM_ACQUIRE_SPQ_LOCK_DPC_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_SPQ((um_device_t *)pDev); } void MM_RELEASE_SPQ_LOCK_DPC_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_SPQ((um_device_t *)pDev); } void MM_ACQUIRE_CID_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_CID((um_device_t *)pDev); } void MM_RELEASE_CID_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_CID((um_device_t *)pDev); } void MM_ACQUIRE_REQUEST_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_RRREQ((um_device_t *)pDev); } void MM_RELEASE_REQUEST_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_RRREQ((um_device_t *)pDev); } void MM_ACQUIRE_PHY_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_PHY((um_device_t *)pDev); } void MM_RELEASE_PHY_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_PHY((um_device_t *)pDev); } void MM_ACQUIRE_PHY_LOCK_DPC_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_PHY((um_device_t *)pDev); } void MM_RELEASE_PHY_LOCK_DPC_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_PHY((um_device_t *)pDev); } void mm_init_lock(lm_device_t * pDev, mm_spin_lock_t * spinlock) { um_device_t * pUM = (um_device_t *)pDev; mutex_init(spinlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); } lm_status_t mm_acquire_lock(mm_spin_lock_t * spinlock) { if (spinlock == NULL) { return LM_STATUS_INVALID_PARAMETER; } mutex_enter(spinlock); return LM_STATUS_SUCCESS; } lm_status_t mm_release_lock(mm_spin_lock_t * spinlock) { if (spinlock == NULL) { return LM_STATUS_INVALID_PARAMETER; } mutex_exit(spinlock); return LM_STATUS_SUCCESS; } void MM_ACQUIRE_MCP_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_MCP((um_device_t *)pDev); } void MM_RELEASE_MCP_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_MCP((um_device_t *)pDev); } void MM_ACQUIRE_ISLES_CONTROL_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_ISLES_CONTROL((um_device_t *)pDev); } void MM_RELEASE_ISLES_CONTROL_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_ISLES_CONTROL((um_device_t *)pDev); } void MM_ACQUIRE_ISLES_CONTROL_LOCK_DPC_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_ISLES_CONTROL((um_device_t *)pDev); } void MM_RELEASE_ISLES_CONTROL_LOCK_DPC_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_ISLES_CONTROL((um_device_t *)pDev); } void MM_ACQUIRE_IND_REG_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_IND((um_device_t *)pDev); } void MM_RELEASE_IND_REG_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_IND((um_device_t *)pDev); } void MM_ACQUIRE_LOADER_LOCK_IMP() { mutex_enter(&bnxeLoaderMutex); } void MM_RELEASE_LOADER_LOCK_IMP() { mutex_exit(&bnxeLoaderMutex); } void MM_ACQUIRE_SP_REQ_MGR_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_SPREQ((um_device_t *)pDev); } void MM_RELEASE_SP_REQ_MGR_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_SPREQ((um_device_t *)pDev); } void MM_ACQUIRE_SB_LOCK_IMP(lm_device_t * pDev, u8_t sb_idx) { BNXE_LOCK_ENTER_SB((um_device_t *)pDev, sb_idx); } void MM_RELEASE_SB_LOCK_IMP(lm_device_t * pDev, u8_t sb_idx) { BNXE_LOCK_EXIT_SB((um_device_t *)pDev, sb_idx); } void MM_ACQUIRE_ETH_CON_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_ENTER_ETH_CON((um_device_t *)pDev); } void MM_RELEASE_ETH_CON_LOCK_IMP(lm_device_t * pDev) { BNXE_LOCK_EXIT_ETH_CON((um_device_t *)pDev); } unsigned int mm_crc32(unsigned char * address, unsigned int size, unsigned int crc) { return 0; } unsigned short mm_crc16(unsigned char * address, unsigned int size, unsigned short crc) { return 0; } lm_status_t mm_event_log_generic_arg_fwd(lm_device_t * pDev, const lm_log_id_t lm_log_id, va_list argp) { um_device_t * pUM = (um_device_t *)pDev; u8_t port = 0 ; char * sz_vendor_name = NULL; char * sz_vendor_pn = NULL; switch (lm_log_id) { case LM_LOG_ID_FAN_FAILURE: // fan failure detected BnxeLogWarn(pUM, "FAN FAILURE!"); break; case LM_LOG_ID_UNQUAL_IO_MODULE: // SFP+ unqualified io module /* * expected parameters: * u8 port, const char * vendor_name, const char * vendor_pn */ port = va_arg(argp, int); sz_vendor_name = va_arg(argp, char*); sz_vendor_pn = va_arg(argp, char*); BnxeLogInfo(pUM, "Unqualified IO Module: %s %s (port=%d)", sz_vendor_name, sz_vendor_pn, port); break; case LM_LOG_ID_OVER_CURRENT: // SFP+ over current power /* * expected parametrs: * u8 port */ port = va_arg(argp, int); BnxeLogWarn(pUM, "SFP+ over current, power failure! (port=%d)", port); break; case LM_LOG_ID_NO_10G_SUPPORT: // 10g speed is requested but not supported /* * expected parametrs: * u8 port */ port = va_arg(argp, int); BnxeLogWarn(pUM, "10Gb speed not supported! (port=%d)", port); break; case LM_LOG_ID_PHY_UNINITIALIZED: /* * expected parametrs: * u8 port */ port = va_arg(argp, int); BnxeLogWarn(pUM, "PHY uninitialized! (port=%d)", port); break; case LM_LOG_ID_MDIO_ACCESS_TIMEOUT: #define MM_PORT_NUM(pdev) \ (CHIP_PORT_MODE(pdev) == LM_CHIP_PORT_MODE_4) ? \ (PATH_ID(pdev) + (2 * PORT_ID(pdev))) : \ (PATH_ID(pdev) + PORT_ID(pdev)) port = MM_PORT_NUM(&pUM->lm_dev); BnxeLogWarn(pUM, "MDIO access timeout! (port=%d)", port); break; default: BnxeLogWarn(pUM, "Unknown MM event log! (type=%d)", lm_log_id); break; } return LM_STATUS_SUCCESS; } lm_status_t mm_event_log_generic(lm_device_t * pDev, const lm_log_id_t lm_log_id, ...) { lm_status_t lm_status = LM_STATUS_SUCCESS; va_list argp; va_start(argp, lm_log_id); lm_status = mm_event_log_generic_arg_fwd(pDev, lm_log_id, argp); va_end(argp); return lm_status; } u32_t mm_build_ver_string(lm_device_t * pDev) { um_device_t * pUM = (um_device_t *)pDev; snprintf((char *)pDev->ver_str, sizeof(pDev->ver_str), "%s", pUM->version); return min(strlen((char *)pDev->ver_str), strlen(pUM->version)); } void mm_indicate_hw_failure(lm_device_t * pDev) { um_device_t * pUM = (um_device_t *)pDev; BnxeLogWarn(pUM, "HW failure indicated!"); } void mm_bar_read_byte(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u8_t *ret) { mm_read_barrier(); *ret = ddi_get8(pdev->vars.reg_handle[bar], (uint8_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset)); } void mm_bar_read_word(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u16_t *ret) { mm_read_barrier(); *ret = ddi_get16(pdev->vars.reg_handle[bar], (uint16_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset)); } void mm_bar_read_dword(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u32_t *ret) { mm_read_barrier(); *ret = ddi_get32(pdev->vars.reg_handle[bar], (uint32_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset)); } void mm_bar_read_ddword(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u64_t *ret) { mm_read_barrier(); *ret = ddi_get64(pdev->vars.reg_handle[bar], (uint64_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset)); } void mm_bar_write_byte(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u8_t val) { ddi_put8(pdev->vars.reg_handle[bar], (uint8_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset), val); mm_write_barrier(); } void mm_bar_write_word(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u16_t val) { ddi_put16(pdev->vars.reg_handle[bar], (uint16_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset), val); mm_write_barrier(); } void mm_bar_write_dword(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u32_t val) { ddi_put32(pdev->vars.reg_handle[bar], (uint32_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset), val); mm_write_barrier(); } void mm_bar_write_ddword(struct _lm_device_t *pdev, u8_t bar, u32_t offset, u64_t val) { ddi_put64(pdev->vars.reg_handle[bar], (uint64_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset), val); mm_write_barrier(); } void mm_bar_copy_buffer(struct _lm_device_t * pdev, u8_t bar, u32_t offset, u32_t size, u32_t *buf_ptr) { u32_t i; for (i = 0; i < size; i++) { ddi_put32(pdev->vars.reg_handle[bar], (uint32_t *)((caddr_t)pdev->vars.mapped_bar_addr[bar] + offset + (i * 4)), *(buf_ptr + i)); } } u32_t mm_get_cap_offset(struct _lm_device_t * pdev, u32_t capabilityID) { u32_t cap_offset = PCI_CAPABILITY_LIST; //CapPtr ofset u8_t cap_id; u32_t reg_value = 0; lm_status_t lm_status = mm_read_pci(pdev, cap_offset, ®_value); if ((lm_status == LM_STATUS_SUCCESS) && (reg_value != 0xFFFFFFFF)) { cap_offset = (u8_t)(reg_value & 0x000000FF); if ((cap_offset == 0) || (cap_offset >= 0x100)) { return 0xFFFFFFFF; } } else { return 0xFFFFFFFF; } do { reg_value = 0; lm_status = mm_read_pci(pdev, cap_offset, ®_value); if ((lm_status == LM_STATUS_SUCCESS) && (reg_value != 0xFFFFFFFF)) { cap_id = (u8_t)(reg_value & 0x000000FF); if (cap_id == capabilityID) { break; } cap_offset = (reg_value & 0x0000FF00) >> 8; if (cap_offset == 0) { break; } } else { cap_offset = 0xFFFFFFFF; break; } } while ((lm_status == LM_STATUS_SUCCESS)); return cap_offset; } u32_t mm_get_wol_flags(struct _lm_device_t * pdev) { return LM_WAKE_UP_MODE_NONE; } u32_t mm_get_feature_flags(struct _lm_device_t * pdev) { return 0; } u32_t mm_get_vmq_cnt(struct _lm_device_t * pdev) { return 0; } lm_status_t mm_i2c_update(struct _lm_device_t * pdev) { return LM_STATUS_SUCCESS; } u64_t mm_query_system_time(void) { return 0; }