| /* |
| * 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" |
| |
| |
| ddi_dma_attr_t bnxeRxDmaAttrib = |
| { |
| DMA_ATTR_V0, /* dma_attr_version */ |
| 0, /* dma_attr_addr_lo */ |
| 0xffffffffffffffff, /* dma_attr_addr_hi */ |
| 0xffffffffffffffff, /* dma_attr_count_max */ |
| BNXE_DMA_ALIGNMENT, /* 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 */ |
| }; |
| |
| |
| static void BnxeRxPostBuffers(um_device_t * pUM, |
| int idx, |
| s_list_t * pReclaimList) |
| { |
| lm_rx_chain_t * pLmRxChain = &LM_RXQ(&pUM->lm_dev, idx); |
| u32_t returnedBytes = 0; |
| lm_packet_t * pLmPkt; |
| |
| /* return bytes from reclaimed list to LM */ |
| pLmPkt = (lm_packet_t *)s_list_peek_head(pReclaimList); |
| while (pLmPkt) |
| { |
| returnedBytes += pLmPkt->size; |
| pLmPkt = (lm_packet_t *)s_list_next_entry(&pLmPkt->link); |
| } |
| |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| |
| if (pUM->rxq[idx].rxLowWater > s_list_entry_cnt(&pLmRxChain->active_descq)) |
| { |
| pUM->rxq[idx].rxLowWater = s_list_entry_cnt(&pLmRxChain->active_descq); |
| } |
| |
| lm_return_packet_bytes(&pUM->lm_dev, idx, returnedBytes); |
| |
| s_list_add_tail(&pLmRxChain->common.free_descq, pReclaimList); |
| s_list_clear(pReclaimList); |
| |
| #if 0 |
| /* |
| * Don't post buffers if we don't have too many free buffers and there are a |
| * lot of buffers already posted. |
| */ |
| if (lm_bd_chain_avail_bds(&pLmRxChain->bd_chain) < 32) |
| { |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| return; |
| } |
| |
| /* |
| * Don't post buffers if there aren't really that many to post yet. |
| */ |
| if (s_list_entry_cnt(&pLmRxChain->common.free_descq) < 32) |
| { |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| return; |
| } |
| #endif |
| |
| lm_post_buffers(&pUM->lm_dev, idx, NULL, 0); |
| |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| } |
| |
| |
| static u32_t BnxeRxPktDescrSize(um_device_t * pUM) |
| { |
| u32_t descSize; |
| |
| (void)pUM; |
| |
| descSize = sizeof(um_rxpacket_t) + SIZEOF_SIG; |
| |
| return ALIGN_VALUE_TO_WORD_BOUNDARY(descSize); |
| } |
| |
| |
| static void BnxeRxPktDescrFree(um_device_t * pUM, |
| um_rxpacket_t * pRxPkt) |
| { |
| u32_t descSize; |
| caddr_t pMem; |
| |
| BnxeDbgBreakIfFastPath(pUM, SIG(pRxPkt) != L2PACKET_RX_SIG); |
| |
| descSize = BnxeRxPktDescrSize(pUM); |
| pMem = (caddr_t)pRxPkt - SIZEOF_SIG; |
| |
| kmem_free(pMem, descSize); |
| } |
| |
| |
| static void BnxeRxPktFree(char * free_arg) |
| { |
| um_rxpacket_t * pRxPkt = (um_rxpacket_t *)free_arg; |
| um_device_t * pUM = (um_device_t *)pRxPkt->pUM; |
| int idx = pRxPkt->idx; |
| s_list_t doneRxQ; |
| |
| if (pUM->magic != BNXE_MAGIC) |
| { |
| /* |
| * Oh my! The free_arg data got corrupted. Log a message and leak this |
| * packet. We don't decrement the 'up in the stack count' since we |
| * can't be sure this packet really was a packet we previously sent up. |
| */ |
| BnxeLogWarn(NULL, "ERROR freeing packet - UM is invalid! (%p)", pRxPkt); |
| return; |
| } |
| |
| if (pUM->rxBufSignature[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)] != |
| pRxPkt->signature) |
| { |
| /* |
| * The stack is freeing a packet that was from a previous plumb of |
| * the interface. |
| */ |
| pRxPkt->lm_pkt.u1.rx.mem_phys[0].as_u64 = 0; |
| pRxPkt->rx_info.mem_virt = NULL; |
| pRxPkt->rx_info.mem_size = 0; |
| |
| ddi_dma_unbind_handle(pRxPkt->dmaHandle); |
| ddi_dma_mem_free(&pRxPkt->dmaAccHandle); |
| ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| |
| BnxeRxPktDescrFree(pUM, pRxPkt); |
| } |
| else |
| { |
| s_list_clear(&doneRxQ); |
| |
| BNXE_LOCK_ENTER_DONERX(pUM, idx); |
| |
| s_list_push_tail(&pUM->rxq[idx].doneRxQ, |
| &((lm_packet_t *)pRxPkt)->link); |
| |
| /* post packets when a bunch are ready */ |
| if (s_list_entry_cnt(&pUM->rxq[idx].doneRxQ) >= pUM->devParams.maxRxFree) |
| { |
| doneRxQ = pUM->rxq[idx].doneRxQ; |
| s_list_clear(&pUM->rxq[idx].doneRxQ); |
| } |
| |
| BNXE_LOCK_EXIT_DONERX(pUM, idx); |
| |
| if (s_list_entry_cnt(&doneRxQ)) |
| { |
| BnxeRxPostBuffers(pUM, idx, &doneRxQ); |
| } |
| } |
| |
| atomic_dec_32(&pUM->rxq[idx].rxBufUpInStack); |
| } |
| |
| |
| boolean_t BnxeWaitForPacketsFromClient(um_device_t * pUM, |
| int cliIdx) |
| { |
| int i, idx, cnt=0, tot=0; |
| |
| switch (cliIdx) |
| { |
| case LM_CLI_IDX_FCOE: |
| |
| for (i = 0; i < 5; i++) |
| { |
| if ((cnt = pUM->rxq[FCOE_CID(&pUM->lm_dev)].rxBufUpInStack) == 0) |
| { |
| break; |
| } |
| |
| /* twiddle our thumbs for one second */ |
| delay(drv_usectohz(1000000)); |
| } |
| |
| if (cnt) |
| { |
| BnxeLogWarn(pUM, "%d packets still held by FCoE (chain %d)!", |
| cnt, FCOE_CID(&pUM->lm_dev)); |
| return B_FALSE; |
| } |
| |
| break; |
| |
| case LM_CLI_IDX_NDIS: |
| |
| tot = 0; |
| |
| LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| { |
| for (i = 0; i < 5; i++) |
| { |
| if ((cnt = pUM->rxq[idx].rxBufUpInStack) == 0) |
| { |
| break; |
| } |
| |
| /* twiddle our thumbs for one second */ |
| delay(drv_usectohz(1000000)); |
| } |
| |
| tot += cnt; |
| } |
| |
| if (tot) |
| { |
| BnxeLogWarn(pUM, "%d packets still held by the stack (chain %d)!", |
| tot, idx); |
| return B_FALSE; |
| } |
| |
| break; |
| |
| default: |
| |
| BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeWaitForPacketsFromClient (%d)", cliIdx); |
| break; |
| } |
| |
| return B_TRUE; |
| } |
| |
| |
| /* numBytes is only valid when polling is TRUE */ |
| mblk_t * BnxeRxRingProcess(um_device_t * pUM, |
| int idx, |
| boolean_t polling, |
| int numBytes) |
| { |
| RxQueue * pRxQ; |
| lm_rx_chain_t * pLmRxChain; |
| u32_t activeDescqCount; |
| boolean_t forceCopy; |
| um_rxpacket_t * pRxPkt; |
| lm_packet_t * pLmPkt; |
| u32_t pktLen; |
| boolean_t dataCopied; |
| u32_t notCopiedCount; |
| mblk_t * pMblk; |
| int ofldFlags; |
| mblk_t * head = NULL; |
| mblk_t * tail = NULL; |
| s_list_t rxList; |
| s_list_t reclaimList; |
| int procBytes = 0; |
| s_list_t tmpList; |
| sp_cqes_info sp_cqes; |
| u32_t pktsRxed; |
| |
| pRxQ = &pUM->rxq[idx]; |
| |
| s_list_clear(&tmpList); |
| |
| /* get the list of packets received */ |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| |
| pktsRxed = lm_get_packets_rcvd(&pUM->lm_dev, idx, &tmpList, &sp_cqes); |
| |
| /* grab any waiting packets */ |
| rxList = pRxQ->waitRxQ; |
| s_list_clear(&pRxQ->waitRxQ); |
| |
| /* put any new packets at the end of the queue */ |
| s_list_add_tail(&rxList, &tmpList); |
| |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| |
| /* now complete the ramrods */ |
| lm_complete_ramrods(&pUM->lm_dev, &sp_cqes); |
| |
| if (s_list_entry_cnt(&rxList) == 0) |
| { |
| return NULL; |
| } |
| |
| s_list_clear(&reclaimList); |
| notCopiedCount = 0; |
| |
| pLmRxChain = &LM_RXQ(&pUM->lm_dev, idx); |
| |
| activeDescqCount = s_list_entry_cnt(&pLmRxChain->active_descq); |
| |
| forceCopy = (activeDescqCount < |
| (pUM->lm_dev.params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)] >> 3)); |
| |
| /* send the packets up the stack */ |
| while (1) |
| { |
| pRxPkt = (um_rxpacket_t *)s_list_pop_head(&rxList); |
| if (pRxPkt == NULL) |
| { |
| break; |
| } |
| |
| pLmPkt = &(pRxPkt->lm_pkt); |
| |
| if (pLmPkt->status != LM_STATUS_SUCCESS) |
| { |
| /* XXX increment error stat? */ |
| s_list_push_tail(&reclaimList, &pLmPkt->link); |
| continue; |
| } |
| |
| pktLen = pLmPkt->size; |
| |
| if (polling == TRUE) |
| { |
| /* When polling an rx ring we can only process up to numBytes */ |
| if ((procBytes + pktLen) <= numBytes) |
| { |
| /* continue to process this packet */ |
| procBytes += pktLen; |
| } |
| else |
| { |
| /* put this packet not processed back on the list (front) */ |
| s_list_push_head(&rxList, &pRxPkt->lm_pkt.link); |
| break; |
| } |
| } |
| |
| (void)ddi_dma_sync(pRxPkt->dmaHandle, |
| 0, |
| pktLen, |
| DDI_DMA_SYNC_FORKERNEL); |
| |
| if (pUM->fmCapabilities && |
| BnxeCheckDmaHandle(pRxPkt->dmaHandle) != DDI_FM_OK) |
| { |
| ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED); |
| } |
| |
| dataCopied = B_FALSE; |
| |
| if (forceCopy || |
| (pUM->devParams.rxCopyThreshold && |
| (pktLen < pUM->devParams.rxCopyThreshold))) |
| { |
| if ((pMblk = allocb(pktLen, BPRI_MED)) == NULL) |
| { |
| pRxQ->rxDiscards++; |
| s_list_push_tail(&reclaimList, &pLmPkt->link); |
| continue; |
| } |
| |
| /* copy the packet into the new mblk */ |
| bcopy((pRxPkt->rx_info.mem_virt + BNXE_DMA_RX_OFFSET), |
| pMblk->b_rptr, pktLen); |
| pMblk->b_wptr = (pMblk->b_rptr + pktLen); |
| dataCopied = B_TRUE; |
| |
| pRxQ->rxCopied++; |
| |
| goto BnxeRxRingProcess_sendup; |
| } |
| |
| if ((activeDescqCount == 0) && (s_list_entry_cnt(&rxList) == 0)) |
| { |
| /* |
| * If the hardware is out of receive buffers and we are on the last |
| * receive packet then drop the packet. We do this because we might |
| * not be able to allocate any new receive buffers before the ISR |
| * completes. If this happens, the driver will enter an infinite |
| * interrupt loop where the hardware is requesting rx buffers the |
| * driver cannot allocate. To prevent a system livelock we leave |
| * one buffer perpetually available. Note that we do this after |
| * giving the double copy code a chance to claim the packet. |
| */ |
| |
| /* FIXME |
| * Make sure to add one more to the rx packet descriptor count |
| * before allocating them. |
| */ |
| |
| pRxQ->rxDiscards++; |
| s_list_push_tail(&reclaimList, &pLmPkt->link); |
| continue; |
| } |
| |
| /* |
| * If we got here then the packet wasn't copied so we need to create a |
| * new mblk_t which references the lm_packet_t buffer. |
| */ |
| |
| pRxPkt->freeRtn.free_func = BnxeRxPktFree; |
| pRxPkt->freeRtn.free_arg = (char *)pRxPkt; |
| pRxPkt->pUM = (void *)pUM; |
| pRxPkt->idx = idx; |
| |
| if ((pMblk = desballoc((pRxPkt->rx_info.mem_virt + BNXE_DMA_RX_OFFSET), |
| pktLen, |
| BPRI_MED, |
| &pRxPkt->freeRtn)) == NULL) |
| { |
| pRxQ->rxDiscards++; |
| s_list_push_tail(&reclaimList, &pLmPkt->link); |
| continue; |
| } |
| |
| pMblk->b_wptr = (pMblk->b_rptr + pktLen); |
| |
| BnxeRxRingProcess_sendup: |
| |
| /* |
| * Check if the checksum was offloaded so we can pass the result to |
| * the stack. |
| */ |
| ofldFlags = 0; |
| |
| if ((pUM->devParams.enabled_oflds & LM_OFFLOAD_RX_IP_CKSUM) && |
| (pRxPkt->rx_info.flags & LM_RX_FLAG_IP_CKSUM_IS_GOOD)) |
| { |
| ofldFlags |= HCK_IPV4_HDRCKSUM_OK; |
| } |
| |
| if (((pUM->devParams.enabled_oflds & LM_OFFLOAD_RX_TCP_CKSUM) && |
| (pRxPkt->rx_info.flags & LM_RX_FLAG_TCP_CKSUM_IS_GOOD)) || |
| ((pUM->devParams.enabled_oflds & LM_OFFLOAD_RX_UDP_CKSUM) && |
| (pRxPkt->rx_info.flags & LM_RX_FLAG_UDP_CKSUM_IS_GOOD))) |
| { |
| ofldFlags |= HCK_FULLCKSUM_OK; |
| } |
| |
| if (ofldFlags != 0) |
| { |
| mac_hcksum_set(pMblk, 0, 0, 0, 0, ofldFlags); |
| } |
| |
| /* |
| * If the packet data was copied into a new recieve buffer then put this |
| * descriptor in a list to be reclaimed later. If not, then increment a |
| * counter so we can track how many of our descriptors are held by the |
| * stack. |
| */ |
| if (dataCopied == B_TRUE) |
| { |
| s_list_push_tail(&reclaimList, &pLmPkt->link); |
| } |
| else |
| { |
| notCopiedCount++; |
| } |
| |
| if (head == NULL) |
| { |
| head = pMblk; |
| } |
| else |
| { |
| tail->b_next = pMblk; |
| } |
| |
| tail = pMblk; |
| tail->b_next = NULL; |
| |
| #if 0 |
| BnxeDumpPkt(pUM, |
| (BNXE_FCOE(pUM) && (idx == FCOE_CID(&pUM->lm_dev))) ? |
| "<- FCoE L2 RX <-" : "<- L2 RX <-", |
| pMblk, B_TRUE); |
| #endif |
| } |
| |
| if (head) |
| { |
| if (notCopiedCount) |
| { |
| /* track all non-copied packets that will be held by the stack */ |
| atomic_add_32(&pUM->rxq[idx].rxBufUpInStack, notCopiedCount); |
| } |
| |
| /* pass the mblk chain up the stack */ |
| if (polling == FALSE) |
| { |
| |
| /* XXX NEED TO ADD STATS FOR RX PATH UPCALLS */ |
| |
| if (BNXE_FCOE(pUM) && (idx == FCOE_CID(&pUM->lm_dev))) |
| { |
| /* XXX verify fcoe frees all packets on success or error */ |
| if (pUM->fcoe.pDev && pUM->fcoe.bind.cliIndicateRx) |
| { |
| pUM->fcoe.bind.cliIndicateRx(pUM->fcoe.pDev, head); |
| } |
| else |
| { |
| /* FCoE isn't bound? Reclaim the chain... */ |
| freemsgchain(head); |
| head = NULL; |
| } |
| } |
| else |
| { |
| #if defined(BNXE_RINGS) && (defined(__S11) || defined(__S12)) |
| mac_rx_ring(pUM->pMac, |
| pUM->rxq[idx].ringHandle, |
| head, |
| pUM->rxq[idx].genNumber); |
| #else |
| mac_rx(pUM->pMac, |
| pUM->macRxResourceHandles[idx], |
| head); |
| #endif |
| } |
| } |
| } |
| |
| if ((polling == TRUE) && s_list_entry_cnt(&rxList)) |
| { |
| /* put the packets not processed back on the list (front) */ |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| s_list_add_head(&pRxQ->waitRxQ, &rxList); |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| } |
| |
| if (s_list_entry_cnt(&reclaimList)) |
| { |
| BnxeRxPostBuffers(pUM, idx, &reclaimList); |
| } |
| |
| return (polling == TRUE) ? head : NULL; |
| } |
| |
| |
| /* |
| * Dumping packets simply moves all packets from the waiting queue to the free |
| * queue. Note that the packets are not posted back to the LM. |
| */ |
| static void BnxeRxRingDump(um_device_t * pUM, |
| int idx) |
| { |
| s_list_t tmpList; |
| |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| |
| tmpList = pUM->rxq[idx].waitRxQ; |
| s_list_clear(&pUM->rxq[idx].waitRxQ); |
| |
| s_list_add_tail(&LM_RXQ(&pUM->lm_dev, idx).common.free_descq, &tmpList); |
| |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| } |
| |
| |
| /* |
| * Aborting packets stops all rx processing by dumping the currently waiting |
| * packets and aborting all the rx descriptors currently posted in the LM. |
| */ |
| static void BnxeRxPktsAbortIdx(um_device_t * pUM, |
| int idx) |
| { |
| BnxeRxRingDump(pUM, idx); |
| |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| lm_abort(&pUM->lm_dev, ABORT_OP_RX_CHAIN, idx); |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| } |
| |
| |
| void BnxeRxPktsAbort(um_device_t * pUM, |
| int cliIdx) |
| { |
| int idx; |
| |
| switch (cliIdx) |
| { |
| case LM_CLI_IDX_FCOE: |
| |
| BnxeRxPktsAbortIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| break; |
| |
| case LM_CLI_IDX_NDIS: |
| |
| LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| { |
| BnxeRxPktsAbortIdx(pUM, idx); |
| } |
| |
| break; |
| |
| default: |
| |
| BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsAbort (%d)", cliIdx); |
| break; |
| } |
| } |
| |
| |
| static int BnxeRxBufAlloc(um_device_t * pUM, |
| int idx, |
| um_rxpacket_t * pRxPkt) |
| { |
| ddi_dma_cookie_t cookie; |
| u32_t count; |
| size_t length; |
| int rc; |
| |
| if ((rc = ddi_dma_alloc_handle(pUM->pDev, |
| &bnxeRxDmaAttrib, |
| DDI_DMA_DONTWAIT, |
| NULL, |
| &pRxPkt->dmaHandle)) != DDI_SUCCESS) |
| { |
| BnxeLogWarn(pUM, "Failed to alloc DMA handle for rx buffer"); |
| return -1; |
| } |
| |
| pRxPkt->rx_info.mem_size = MAX_L2_CLI_BUFFER_SIZE(&pUM->lm_dev, idx); |
| |
| if ((rc = ddi_dma_mem_alloc(pRxPkt->dmaHandle, |
| pRxPkt->rx_info.mem_size, |
| &bnxeAccessAttribBUF, |
| DDI_DMA_STREAMING, |
| DDI_DMA_DONTWAIT, |
| NULL, |
| (caddr_t *)&pRxPkt->rx_info.mem_virt, |
| &length, |
| &pRxPkt->dmaAccHandle)) != DDI_SUCCESS) |
| { |
| BnxeLogWarn(pUM, "Failed to alloc DMA memory for rx buffer"); |
| ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| return -1; |
| } |
| |
| if ((rc = ddi_dma_addr_bind_handle(pRxPkt->dmaHandle, |
| NULL, |
| (caddr_t)pRxPkt->rx_info.mem_virt, |
| pRxPkt->rx_info.mem_size, |
| DDI_DMA_READ | DDI_DMA_STREAMING, |
| DDI_DMA_DONTWAIT, |
| NULL, |
| &cookie, |
| &count)) != DDI_DMA_MAPPED) |
| { |
| BnxeLogWarn(pUM, "Failed to bind DMA address for rx buffer"); |
| ddi_dma_mem_free(&pRxPkt->dmaAccHandle); |
| ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| return -1; |
| } |
| |
| pRxPkt->lm_pkt.u1.rx.mem_phys[0].as_u64 = cookie.dmac_laddress; |
| |
| return 0; |
| } |
| |
| |
| static int BnxeRxPktsInitPostBuffersIdx(um_device_t * pUM, |
| int idx) |
| { |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| lm_post_buffers(&pUM->lm_dev, idx, NULL, 0); |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| |
| return 0; |
| } |
| |
| |
| int BnxeRxPktsInitPostBuffers(um_device_t * pUM, |
| int cliIdx) |
| { |
| int idx; |
| |
| switch (cliIdx) |
| { |
| case LM_CLI_IDX_FCOE: |
| |
| BnxeRxPktsInitPostBuffersIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| break; |
| |
| case LM_CLI_IDX_NDIS: |
| |
| LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| { |
| BnxeRxPktsInitPostBuffersIdx(pUM, idx); |
| } |
| |
| break; |
| |
| default: |
| |
| BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsInit (%d)", cliIdx); |
| break; |
| } |
| |
| return 0; |
| } |
| |
| |
| static int BnxeRxPktsInitIdx(um_device_t * pUM, |
| int idx) |
| { |
| lm_device_t * pLM = &pUM->lm_dev; |
| lm_rx_chain_t * pLmRxChain; |
| um_rxpacket_t * pRxPkt; |
| lm_packet_t * pLmPkt; |
| u8_t * pTmp; |
| int postCnt, i; |
| |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| |
| pLmRxChain = &LM_RXQ(pLM, idx); |
| |
| s_list_clear(&pUM->rxq[idx].doneRxQ); |
| pUM->rxq[idx].rxLowWater = pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)]; |
| pUM->rxq[idx].rxDiscards = 0; |
| pUM->rxq[idx].rxCopied = 0; |
| |
| s_list_clear(&pUM->rxq[idx].waitRxQ); |
| |
| /* allocate the packet descriptors */ |
| for (i = 0; |
| i < pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)]; |
| i++) |
| { |
| if ((pTmp = kmem_zalloc(BnxeRxPktDescrSize(pUM), |
| KM_NOSLEEP)) == NULL) |
| { |
| BnxeLogWarn(pUM, "Failed to alloc an rx packet descriptor!!!"); |
| break; /* continue without error */ |
| } |
| |
| pRxPkt = (um_rxpacket_t *)(pTmp + SIZEOF_SIG); |
| SIG(pRxPkt) = L2PACKET_RX_SIG; |
| pRxPkt->signature = pUM->rxBufSignature[LM_CHAIN_IDX_CLI(pLM, idx)]; |
| |
| pLmPkt = (lm_packet_t *)pRxPkt; |
| pLmPkt->u1.rx.hash_val_ptr = &pRxPkt->hash_value; |
| pLmPkt->l2pkt_rx_info = &pRxPkt->rx_info; |
| |
| if (BnxeRxBufAlloc(pUM, idx, pRxPkt) != 0) |
| { |
| BnxeRxPktDescrFree(pUM, pRxPkt); |
| break; /* continue without error */ |
| } |
| |
| s_list_push_tail(&pLmRxChain->common.free_descq, &pLmPkt->link); |
| } |
| |
| postCnt = s_list_entry_cnt(&pLmRxChain->common.free_descq); |
| |
| if (postCnt != pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)]) |
| { |
| BnxeLogWarn(pUM, "%d rx buffers requested and only %d allocated!!!", |
| pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)], |
| postCnt); |
| } |
| |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| |
| return 0; |
| } |
| |
| |
| int BnxeRxPktsInit(um_device_t * pUM, |
| int cliIdx) |
| { |
| int idx; |
| |
| /* set the rx buffer signature for this plumb */ |
| atomic_swap_32(&pUM->rxBufSignature[cliIdx], (u32_t)ddi_get_time()); |
| |
| switch (cliIdx) |
| { |
| case LM_CLI_IDX_FCOE: |
| |
| BnxeRxPktsInitIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| break; |
| |
| case LM_CLI_IDX_NDIS: |
| |
| LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| { |
| BnxeRxPktsInitIdx(pUM, idx); |
| } |
| |
| break; |
| |
| default: |
| |
| BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsInit (%d)", cliIdx); |
| break; |
| } |
| |
| return 0; |
| } |
| |
| |
| static void BnxeRxPktsFiniIdx(um_device_t * pUM, |
| int idx) |
| { |
| lm_rx_chain_t * pLmRxChain; |
| um_rxpacket_t * pRxPkt; |
| s_list_t tmpList; |
| |
| pLmRxChain = &LM_RXQ(&pUM->lm_dev, idx); |
| |
| s_list_clear(&tmpList); |
| |
| BNXE_LOCK_ENTER_RX(pUM, idx); |
| s_list_add_tail(&tmpList, &pLmRxChain->common.free_descq); |
| s_list_clear(&pLmRxChain->common.free_descq); |
| BNXE_LOCK_EXIT_RX(pUM, idx); |
| |
| BNXE_LOCK_ENTER_DONERX(pUM, idx); |
| s_list_add_tail(&tmpList, &pUM->rxq[idx].doneRxQ); |
| s_list_clear(&pUM->rxq[idx].doneRxQ); |
| BNXE_LOCK_EXIT_DONERX(pUM, idx); |
| |
| if (s_list_entry_cnt(&tmpList) != |
| pUM->lm_dev.params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)]) |
| { |
| BnxeLogWarn(pUM, "WARNING Missing RX packets (idx:%d) (%lu / %d - %u in stack)", |
| idx, s_list_entry_cnt(&tmpList), |
| pUM->lm_dev.params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)], |
| pUM->rxq[idx].rxBufUpInStack); |
| } |
| |
| /* |
| * Back out all the packets in the "available for hardware use" queue. |
| * Free the buffers associated with the descriptors as we go. |
| */ |
| while (1) |
| { |
| pRxPkt = (um_rxpacket_t *)s_list_pop_head(&tmpList); |
| if (pRxPkt == NULL) |
| { |
| break; |
| } |
| |
| pRxPkt->lm_pkt.u1.rx.mem_phys[0].as_u64 = 0; |
| pRxPkt->rx_info.mem_virt = NULL; |
| pRxPkt->rx_info.mem_size = 0; |
| |
| ddi_dma_unbind_handle(pRxPkt->dmaHandle); |
| ddi_dma_mem_free(&pRxPkt->dmaAccHandle); |
| ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| |
| BnxeRxPktDescrFree(pUM, pRxPkt); |
| } |
| } |
| |
| |
| void BnxeRxPktsFini(um_device_t * pUM, |
| int cliIdx) |
| { |
| int idx; |
| |
| /* reset the signature for this unplumb */ |
| atomic_swap_32(&pUM->rxBufSignature[cliIdx], 0); |
| |
| switch (cliIdx) |
| { |
| case LM_CLI_IDX_FCOE: |
| |
| BnxeRxPktsFiniIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| break; |
| |
| case LM_CLI_IDX_NDIS: |
| |
| LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| { |
| BnxeRxPktsFiniIdx(pUM, idx); |
| } |
| |
| break; |
| |
| default: |
| |
| BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsFini (%d)", cliIdx); |
| break; |
| } |
| } |
| |