c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe/*
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * CDDL HEADER START
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * The contents of this file are subject to the terms of the
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * Common Development and Distribution License (the "License").
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * You may not use this file except in compliance with the License.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * or http://www.opensolaris.org/os/licensing.
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * See the License for the specific language governing permissions
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * and limitations under the License.
ead9bb4b1be81d7bbf8ed86ee41d6c1e58b069a3Yuri Pankov *
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * When distributing Covered Code, include this CDDL HEADER in each
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
ead9bb4b1be81d7bbf8ed86ee41d6c1e58b069a3Yuri Pankov * If applicable, add the following below this CDDL HEADER, with the
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe * fields enclosed by brackets "[]" replaced with your own identifying
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * information: Portions Copyright [yyyy] [name of copyright owner]
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov *
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * CDDL HEADER END
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Copyright 2014 QLogic Corporation
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * The contents of this file are subject to the terms of the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * QLogic End User License (the "License").
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * You may not use this file except in compliance with the License.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov *
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * You can obtain a copy of the License at
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * QLogic_End_User_Software_License.txt
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * See the License for the specific language governing permissions
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * and limitations under the License.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#include "bnxe.h"
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovddi_dma_attr_t bnxeTxDmaAttrib =
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov DMA_ATTR_V0, /* dma_attr_version */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_addr_lo */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_addr_hi */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_count_max */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_DMA_ALIGNMENT, /* dma_attr_align */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffff, /* dma_attr_burstsizes */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 1, /* dma_attr_minxfer */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_maxxfer */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_seg */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_MAX_DMA_SGLLEN, /* dma_attr_sgllen */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 1, /* dma_attr_granular */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_flags */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov};
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovddi_dma_attr_t bnxeTxCbDmaAttrib =
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov DMA_ATTR_V0, /* dma_attr_version */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_addr_lo */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_addr_hi */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_count_max */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_DMA_ALIGNMENT, /* dma_attr_align */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffff, /* dma_attr_burstsizes */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 1, /* dma_attr_minxfer */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_maxxfer */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0xffffffffffffffff, /* dma_attr_seg */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 1, /* dma_attr_sgllen */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 1, /* dma_attr_granular */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov 0, /* dma_attr_flags */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov};
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic um_txpacket_t * BnxeTxPktAlloc(um_device_t * pUM, size_t size);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline void BnxeTxPktUnmap(um_txpacket_t * pTxPkt)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int i;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (i = 0; i < pTxPkt->num_handles; i++)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_unbind_handle(pTxPkt->dmaHandles[i]);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->num_handles = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic void BnxeTxPktsFree(um_txpacket_t * pTxPkt)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int i;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->num_handles > 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeTxPktUnmap(pTxPkt);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->pMblk != NULL)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov freemsg(pTxPkt->pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (i = 0; i < BNXE_MAX_DMA_HANDLES_PER_PKT; i++)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_free_handle(&pTxPkt->dmaHandles[i]);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->pMblk = NULL;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->num_handles = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->frag_list.cnt = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_unbind_handle(pTxPkt->cbDmaHandle);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_mem_free(&pTxPkt->cbDmaAccHandle);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov kmem_free(pTxPkt, sizeof(um_txpacket_t));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic void BnxeTxPktsFreeList(s_list_t * pPktList)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov um_txpacket_t * pTxPkt;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov while (!s_list_is_empty(pPktList))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_pop_head(pPktList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeTxPktsFree(pTxPkt);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Free the mblk and all frag mappings used by each packet in the list
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * and then put the entire list on the free queue for immediate use.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovvoid BnxeTxPktsReclaim(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int idx,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_t * pPktList)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov um_txpacket_t * pTxPkt;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (s_list_entry_cnt(pPktList) == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pTxPkt = (um_txpacket_t *)s_list_peek_head(pPktList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_next_entry(&pTxPkt->lm_pkt.link))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->num_handles > 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeTxPktUnmap(pTxPkt);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->pMblk != NULL)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov freemsg(pTxPkt->pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->pMblk = NULL;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_LOCK_ENTER_FREETX(pUM, idx);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_add_tail(&pUM->txq[idx].freeTxDescQ, pPktList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_LOCK_EXIT_FREETX(pUM, idx);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/* Must be called with TX lock held!!! */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic int BnxeTxSendWaitingPkt(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int idx)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov TxQueue * pTxQ = &pUM->txq[idx];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov lm_device_t * pLM = &pUM->lm_dev;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov lm_tx_chain_t * pLmTxChain;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov um_txpacket_t * pTxPkt;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int rc;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pLmTxChain = &pLM->tx_info.chain[idx];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov while (s_list_entry_cnt(&pTxQ->waitTxDescQ))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_peek_head(&pTxQ->waitTxDescQ);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->frag_list.cnt + 2 > pLmTxChain->bd_chain.bd_left)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_DEFERPKT;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt = (um_txpacket_t *)s_list_pop_head(&pTxQ->waitTxDescQ);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov rc = lm_send_packet(pLM, idx, &pTxPkt->lm_pkt, &pTxPkt->frag_list);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pUM->fmCapabilities &&
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (rc != LM_STATUS_SUCCESS)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Send failed (probably not enough BDs available)...
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Put the packet back at the head of the wait queue.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxQ->txFailed++;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_push_head(&pTxQ->waitTxDescQ, &pTxPkt->lm_pkt.link);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_DEFERPKT;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_GOODXMIT;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovvoid BnxeTxRingProcess(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int idx)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov TxQueue * pTxQ = &pUM->txq[idx];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov lm_device_t * pLM = &pUM->lm_dev;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov lm_tx_chain_t * pLmTxChain;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_t tmpList;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t pktsTxed;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int rc;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_clear(&tmpList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_LOCK_ENTER_TX(pUM, idx);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pktsTxed = lm_get_packets_sent(&pUM->lm_dev, idx, &tmpList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pUM->fmCapabilities &&
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeCheckAccHandle(pUM->lm_dev.vars.reg_handle[BAR_0]) != DDI_FM_OK)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((pktsTxed + s_list_entry_cnt(&pTxQ->sentTxQ)) >=
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pUM->devParams.maxTxFree)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_add_tail(&tmpList, &pTxQ->sentTxQ);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_clear(&pTxQ->sentTxQ);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_add_tail(&pTxQ->sentTxQ, &tmpList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov s_list_clear(&tmpList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_LOCK_EXIT_TX(pUM, idx);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (s_list_entry_cnt(&tmpList))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeTxPktsReclaim(pUM, idx, &tmpList);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxQ->noTxCredits == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* no need to notify the stack */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pLmTxChain = &pUM->lm_dev.tx_info.chain[idx];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxQ->noTxCredits & BNXE_TX_RESOURCES_NO_CREDIT)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_LOCK_ENTER_TX(pUM, idx);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov rc = BnxeTxSendWaitingPkt(pUM, idx);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BNXE_LOCK_EXIT_TX(pUM, idx);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((rc == BNXE_TX_GOODXMIT) &&
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (pLmTxChain->bd_chain.bd_left >= BNXE_MAX_DMA_FRAGS_PER_PKT))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov atomic_and_32(&pTxQ->noTxCredits, ~BNXE_TX_RESOURCES_NO_CREDIT);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((pTxQ->noTxCredits & BNXE_TX_RESOURCES_NO_DESC) &&
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (s_list_entry_cnt(&pTxQ->freeTxDescQ) > pTxQ->thresh_pdwm))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov atomic_and_32(&pTxQ->noTxCredits, ~BNXE_TX_RESOURCES_NO_DESC);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxQ->noTxCredits == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (idx == FCOE_CID(pLM))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogInfo(pUM, "FCoE tx credit ok, no upcall!");
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* notify the stack that tx resources are now available */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#if defined(BNXE_RINGS) && (defined(__S11) || defined(__S12))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mac_tx_ring_update(pUM->pMac, pTxQ->ringHandle);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mac_tx_update(pUM->pMac);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#endif
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline int BnxeTxPktMapFrag(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov um_txpacket_t * pTxPkt,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mblk_t * pMblk)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_handle_t dmaHandle;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_cookie_t cookie;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov lm_frag_t * pFrag;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov boolean_t partial;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t bindLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t count;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int rc, i;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->num_handles == BNXE_MAX_DMA_HANDLES_PER_PKT)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_RESOURCES_NO_OS_DMA_RES;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->frag_list.cnt >= BNXE_MAX_DMA_FRAGS_PER_PKT)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_RESOURCES_TOO_MANY_FRAGS;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov dmaHandle = pTxPkt->dmaHandles[pTxPkt->num_handles];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((rc = ddi_dma_addr_bind_handle(dmaHandle,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov NULL,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (caddr_t)pMblk->b_rptr,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (pMblk->b_wptr - pMblk->b_rptr),
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (DDI_DMA_WRITE | DDI_DMA_STREAMING),
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov DDI_DMA_DONTWAIT,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov NULL,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov &cookie,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov &count)) != DDI_DMA_MAPPED)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogWarn(pUM, "Failed to bind DMA address for tx packet (%d)", rc);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_RESOURCES_NO_OS_DMA_RES;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * ddi_dma_addr_bind_handle() correctly returns an error if the physical
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * fragment count exceeds the maximum fragment count specified in the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * ddi_dma_attrib structure for the current pMblk. However, a packet can
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * span multiple mblk's. The purpose of the check below is to make sure we
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * do not overflow our fragment count limit based on what has already been
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * mapped from this packet.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov partial = ((pTxPkt->frag_list.cnt + count) >
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov (pMblk->b_cont ? BNXE_MAX_DMA_FRAGS_PER_PKT - 1
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov : BNXE_MAX_DMA_FRAGS_PER_PKT));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (partial)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Going to try a partial dma so (re)set count to the remaining number
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * of dma fragments that are available leaving one fragment at the end.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov count = (BNXE_MAX_DMA_FRAGS_PER_PKT - 1 - pTxPkt->frag_list.cnt);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (count == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * No more dma fragments are available. This fragment was not
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * mapped and will be copied into the copy buffer along with the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * rest of the packet data.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_unbind_handle(dmaHandle);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_RESOURCES_TOO_MANY_FRAGS;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pFrag = &pTxPkt->frag_list.frag_arr[pTxPkt->frag_list.cnt];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->frag_list.cnt += count;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* map "count" dma fragments */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov bindLen = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (i = 0; i < (count - 1); i++)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pFrag->addr.as_u64 = cookie.dmac_laddress;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov bindLen += pFrag->size = cookie.dmac_size;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pFrag++;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_dma_nextcookie(dmaHandle, &cookie);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pFrag->addr.as_u64 = cookie.dmac_laddress;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov bindLen += pFrag->size = cookie.dmac_size;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->num_handles++;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (partial)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Move the mblk's read pointer past the data that was bound to a DMA
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * fragment. Any remaining data will get copied into the copy buffer.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pMblk->b_rptr += bindLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return BNXE_TX_RESOURCES_TOO_MANY_FRAGS;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic int BnxeTxPktCopy(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov TxQueue * pTxQ,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov um_txpacket_t * pTxPkt)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov lm_frag_t * pCopyFrag = NULL;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov size_t msgSize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov size_t copySize = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov size_t pktLen = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov boolean_t tryMap = B_TRUE;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mblk_t * pMblk;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov caddr_t pTmp;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov int rc;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* Walk the chain to get the total pkt length... */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pktLen += MBLKL(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * If the packet length is under the tx copy threshold then copy
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * the all data into the copy buffer.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pktLen < pUM->devParams.txCopyThreshold)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT(pktLen <= pTxPkt->cbLength);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTmp = pTxPkt->pCbBuf;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((msgSize = MBLKL(pMblk)) == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov continue;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov bcopy(pMblk->b_rptr, pTmp, msgSize);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTmp += msgSize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag = &pTxPkt->frag_list.frag_arr[0];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag->addr.as_u64 = pTxPkt->cbPhysAddr.as_u64;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag->size = pktLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->frag_list.cnt++;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov copySize = pktLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxQ->txCopied++;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* Done! */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov goto _BnxeTxPktCopy_DMA_SYNC_COPY_BUFFER;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* Try to DMA map all the blocks... */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((msgSize = MBLKL(pMblk)) == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov continue;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (tryMap)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (BnxeTxPktMapFrag(pUM, pTxPkt, pMblk) == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * The fragment was successfully mapped now move on to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * next one. Here we set pCopyFrag to NULL which represents
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * a break of continuous data in the copy buffer. If the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * packet header was copied the first fragment points to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * beginning of the copy buffer. Since this block was mapped
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * any future blocks that have to be copied must be handled by
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * a new fragment even though the fragment is pointed to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * copied data in the copy buffer.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag = NULL;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov continue;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * The frament was not mapped or was partially mapped. In
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * either case we will no longer try to map the remaining
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * blocks. All remaining packet data is copied.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov tryMap = B_FALSE;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov msgSize = MBLKL(pMblk); /* new msgSize with partial binding */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#if 0
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((copySize + msgSize) > pTxPkt->cbLength)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* remaining packet is too large (length more than copy buffer) */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeTxPktUnmap(pTxPkt);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return -1;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT((copySize + msgSize) <= pTxPkt->cbLength);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#endif
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov bcopy(pMblk->b_rptr, (pTxPkt->pCbBuf + copySize), msgSize);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * If pCopyFrag is already specified then simply update the copy size.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * If not then set pCopyFrag to the next available fragment.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pCopyFrag)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag->size += msgSize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT((pTxPkt->frag_list.cnt + 1) <= BNXE_MAX_DMA_FRAGS_PER_PKT);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag = &pTxPkt->frag_list.frag_arr[pTxPkt->frag_list.cnt++];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag->size = msgSize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pCopyFrag->addr.as_u64 = pTxPkt->cbPhysAddr.as_u64 + copySize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* update count of bytes in the copy buffer needed for DMA sync */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov copySize += msgSize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov_BnxeTxPktCopy_DMA_SYNC_COPY_BUFFER:
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (copySize > 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* DMA sync the copy buffer before sending */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov rc = ddi_dma_sync(pTxPkt->cbDmaHandle, 0, copySize,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov DDI_DMA_SYNC_FORDEV);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pUM->fmCapabilities &&
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeCheckDmaHandle(pTxPkt->cbDmaHandle) != DDI_FM_OK)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (rc != DDI_SUCCESS)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogWarn(pUM, "(%d) Failed to dma sync tx copy (%p / %d)",
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov rc, pTxPkt, copySize);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (pTxPkt->num_handles == 0)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov freemsg(pTxPkt->pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->pMblk = NULL;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/* this code is derived from that shown in RFC 1071 Section 4.1 */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline u16_t BnxeCalcCksum(void * start,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t len,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u16_t prev_sum)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u16_t * pword;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t sum = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pword = (u16_t *)start;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov for ( ; len > 1; len -= 2, pword++)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* the inner loop */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum += *pword;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* add left-over byte, if any */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (len)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum += (u16_t)(*((u8_t *)pword));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum += prev_sum;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* fold 32-bit sum to 16 bits */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov while (sum >> 16)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum = ((sum & 0xffff) + (sum >> 16));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return (u16_t)sum;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov/*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * Everest1 (i.e. 57710, 57711, 57711E) does not natively support UDP checksums
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * and does not know anything about the UDP header and where the checksum field
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * is located. It only knows about TCP. Therefore we "lie" to the hardware for
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * outgoing UDP packets w/ checksum offload. Since the checksum field offset
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * for TCP is 16 bytes and for UDP it is 6 bytes we pass a pointer to the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * hardware that is 10 bytes less than the start of the UDP header. This allows
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * the hardware to write the checksum in the correct spot. But the hardware
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * will compute a checksum which includes the last 10 bytes of the IP header.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * To correct this we tweak the stack computed pseudo checksum by folding in the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * calculation of the inverse checksum for those final 10 bytes of the IP
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * header. This allows the correct checksum to be computed by the hardware.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#define TCP_CS_OFFSET 16
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#define UDP_CS_OFFSET 6
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#define UDP_TCP_CS_OFFSET_DIFF (TCP_CS_OFFSET - UDP_CS_OFFSET)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline u16_t BnxeUdpPseudoCsum(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u8_t * pUdpHdr,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u8_t * pIpHdr,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u8_t ipHdrLen)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t sum32;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u16_t sum16;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u16_t pseudo_cs;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT(ipHdrLen >= UDP_TCP_CS_OFFSET_DIFF);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* calc cksum on last UDP_TCP_CS_OFFSET_DIFF bytes of ip header */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum16 = BnxeCalcCksum(&pIpHdr[ipHdrLen - UDP_TCP_CS_OFFSET_DIFF],
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov UDP_TCP_CS_OFFSET_DIFF, 0);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* substruct the calculated cksum from the udp pseudo cksum */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pseudo_cs = (*((u16_t *)&pUdpHdr[6]));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum16 = ~sum16;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum32 = (pseudo_cs + sum16);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* fold 32-bit sum to 16 bits */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov while (sum32 >> 16)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov sum32 = ((sum32 & 0xffff) + (sum32 >> 16));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return ntohs((u16_t)sum32);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline u16_t BnxeGetVlanTag(mblk_t * pMblk)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT(MBLKL(pMblk) >= sizeof(struct ether_vlan_header));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return GLD_VTAG_VID(ntohs(((struct ether_vlan_header *)pMblk->b_rptr)->ether_tci));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov}
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankovstatic inline int BnxeGetHdrInfo(um_device_t * pUM,
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov um_txpacket_t * pTxPkt)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov{
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mblk_t * pMblk;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov size_t msgSize;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov uint32_t csStart;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov uint32_t csStuff;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov uint32_t csFlags;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov uint32_t lso;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u8_t * pL2Hdr;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov uint32_t l2HdrLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u8_t * pL3Hdr;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t l3HdrLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u8_t * pL4Hdr;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov u32_t l4HdrLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pMblk = pTxPkt->pMblk;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov msgSize = MBLKL(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* At least the MAC header... */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#if 0
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (msgSize < sizeof(struct ether_header))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeLogWarn(pUM, "Invalid initial segment size in packet!");
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return -1;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT(msgSize >= sizeof(struct ether_header));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov#endif
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov mac_hcksum_get(pMblk, &csStart, &csStuff, NULL, NULL, &csFlags);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov lso = DB_LSOFLAGS(pMblk) & HW_LSO;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* get the Ethernet header */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pL2Hdr = (u8_t *)pMblk->b_rptr;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* grab the destination mac addr */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov memcpy(pTxPkt->tx_info.dst_mac_addr, pL2Hdr, 6);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (lso)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_TCP_LSO_FRAME;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.lso_mss = (u16_t)DB_LSOMSS(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else if (!csFlags)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* no offload requested, just check for VLAN */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (((struct ether_header *)pMblk->b_rptr)->ether_type ==
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov htons(ETHERTYPE_VLAN))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.vlan_tag = BnxeGetVlanTag(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_VLAN_TAG_EXISTS;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (((struct ether_header *)pL2Hdr)->ether_type == htons(ETHERTYPE_VLAN))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l2HdrLen = sizeof(struct ether_vlan_header);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.vlan_tag = BnxeGetVlanTag(pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_VLAN_TAG_EXISTS;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l2HdrLen = sizeof(struct ether_header);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (csFlags & HCK_IPV4_HDRCKSUM)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_COMPUTE_IP_CKSUM;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (csFlags & HCK_PARTIALCKSUM)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.flags |= LM_TX_FLAG_COMPUTE_TCP_UDP_CKSUM;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l3HdrLen = csStart;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l4HdrLen = (l2HdrLen + csStuff + sizeof(u16_t));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /*
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * For TCP, here we ignore the urgent pointer and size of the
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov * options. We'll get that info later.
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else if (lso)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* Solaris doesn't do LSO if there is option in the IP header. */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l3HdrLen = sizeof(struct ip);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l4HdrLen = (l2HdrLen + l3HdrLen + sizeof(struct tcphdr));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (msgSize >= l4HdrLen)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* the header is in the first block */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pL3Hdr = (pL2Hdr + l2HdrLen);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((msgSize <= l2HdrLen) && pMblk->b_cont &&
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ((msgSize + MBLKL(pMblk->b_cont)) >= l4HdrLen))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* the header is in the second block */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pL3Hdr = pMblk->b_cont->b_rptr + (l2HdrLen - msgSize);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* do a pullup to make sure headers are in the first block */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pUM->txMsgPullUp++;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if ((pMblk = msgpullup(pMblk, l4HdrLen)) == NULL)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov return -1;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe freemsg(pTxPkt->pMblk);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->pMblk = pMblk;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pL3Hdr = (pMblk->b_rptr + l2HdrLen);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* must be IPv4 or IPv6 */
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe ASSERT((pL3Hdr[0] & 0xf0) == 0x60 || (pL3Hdr[0] & 0xf0) == 0x40);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if ((pL3Hdr[0] & 0xf0) == 0x60)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.flags |= LM_TX_FLAG_IPV6_PACKET;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov if (lso || ((csStuff - csStart) == TCP_CS_OFFSET))
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* get the TCP header */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pL4Hdr = (pL3Hdr + l3HdrLen);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov l4HdrLen = ((pL4Hdr[12] & 0xf0) >> 2);
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.cs_any_offset = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.tcp_nonce_sum_bit = (pL4Hdr[12] & 0x1);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.tcp_pseudo_csum = ntohs(*((u16_t *)&pL4Hdr[TCP_CS_OFFSET]));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe if (lso)
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.lso_ipid = ntohs(*((u16_t *)&pL3Hdr[4]));
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.lso_tcp_send_seq = ntohl(*((u32_t *)&pL4Hdr[4]));
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.lso_tcp_flags = pL4Hdr[13];
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov }
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe }
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov else
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe {
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov ASSERT((csStuff - csStart) == UDP_CS_OFFSET);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov /* get the UDP header */
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pL4Hdr = pL3Hdr + l3HdrLen;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe l4HdrLen = sizeof(struct udphdr);
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.cs_any_offset = UDP_TCP_CS_OFFSET_DIFF;
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe pTxPkt->tx_info.tcp_nonce_sum_bit = 0;
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov pTxPkt->tx_info.tcp_pseudo_csum =
c10c16dec587a0662068f6e2991c29ed3a9db943Richard Lowe CHIP_IS_E1x(((lm_device_t *)pUM)) ?
a9478106a12424322498e53cf7cd75bd8a4d6004Yuri Pankov BnxeUdpPseudoCsum(pUM, pL4Hdr, pL3Hdr, l3HdrLen) :
ntohs(*((u16_t *)&pL4Hdr[UDP_CS_OFFSET]));
}
pTxPkt->tx_info.lso_ip_hdr_len = l3HdrLen;
pTxPkt->tx_info.lso_tcp_hdr_len = l4HdrLen;
return 0;
}
int BnxeTxSendMblk(um_device_t * pUM,
int idx,
mblk_t * pMblk,
u32_t flags,
u16_t vlan_tag)
{
lm_device_t * pLM = &pUM->lm_dev;
TxQueue * pTxQ = &pUM->txq[idx];
lm_tx_chain_t * pLmTxChain;
um_txpacket_t * pTxPkt;
s_list_t tmpList;
u32_t numPkts;
int rc;
BNXE_LOCK_ENTER_FREETX(pUM, idx);
pTxPkt = (um_txpacket_t *)s_list_pop_head(&pTxQ->freeTxDescQ);
if (pTxQ->txLowWater > s_list_entry_cnt(&pTxQ->freeTxDescQ))
{
pTxQ->txLowWater = s_list_entry_cnt(&pTxQ->freeTxDescQ);
}
BNXE_LOCK_EXIT_FREETX(pUM, idx);
/* try to recycle if no more packet available */
if (pTxPkt == NULL)
{
pTxQ->txRecycle++;
s_list_clear(&tmpList);
BNXE_LOCK_ENTER_TX(pUM, idx);
numPkts = lm_get_packets_sent(pLM, idx, &tmpList);
BNXE_LOCK_EXIT_TX(pUM, idx);
if (pUM->fmCapabilities &&
BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
{
ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
}
if (!numPkts)
{
atomic_or_32(&pTxQ->noTxCredits, BNXE_TX_RESOURCES_NO_DESC);
pTxQ->txBlocked++;
return BNXE_TX_HDWRFULL;
}
/* steal the first packet from the list before reclaiming */
pTxPkt = (um_txpacket_t *)s_list_pop_head(&tmpList);
if (pTxPkt->num_handles)
{
BnxeTxPktUnmap(pTxPkt);
}
if (pTxPkt->pMblk)
{
freemsg(pTxPkt->pMblk);
pTxPkt->pMblk = NULL;
}
BnxeTxPktsReclaim(pUM, idx, &tmpList);
}
pTxPkt->lm_pkt.link.next = NULL;
pTxPkt->tx_info.flags = 0;
pTxPkt->tx_info.vlan_tag = 0;
pTxPkt->frag_list.cnt = 0;
pTxPkt->pMblk = pMblk;
#if 0
BnxeDumpPkt(pUM,
(BNXE_FCOE(pUM) && (idx == FCOE_CID(&pUM->lm_dev))) ?
"-> FCoE L2 TX ->" : "-> L2 TX ->",
pMblk, B_TRUE);
#endif
if (idx == FCOE_CID(pLM))
{
if (flags & PRV_TX_VLAN_TAG)
{
pTxPkt->tx_info.vlan_tag = vlan_tag;
pTxPkt->tx_info.flags |= LM_TX_FLAG_INSERT_VLAN_TAG;
}
}
else if (BnxeGetHdrInfo(pUM, pTxPkt))
{
goto BnxeTxSendMblk_fail;
}
if (BnxeTxPktCopy(pUM, pTxQ, pTxPkt))
{
goto BnxeTxSendMblk_fail;
}
/* Now try to send the packet... */
pLmTxChain = &pLM->tx_info.chain[idx];
BNXE_LOCK_ENTER_TX(pUM, idx);
/* Try to reclaim sent packets if available BDs is lower than threshold */
if (pLmTxChain->bd_chain.bd_left < BNXE_MAX_DMA_FRAGS_PER_PKT + 2)
{
pTxQ->txRecycle++;
s_list_clear(&tmpList);
numPkts = lm_get_packets_sent(pLM, idx, &tmpList);
if (pUM->fmCapabilities &&
BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
{
ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
}
if (numPkts)
{
BnxeTxPktsReclaim(pUM, idx, &tmpList);
}
}
/*
* If there are no packets currently waiting to be sent and there are enough
* BDs available to satisfy this packet then send it now.
*/
if (s_list_is_empty(&pTxQ->waitTxDescQ) &&
(pLmTxChain->bd_chain.bd_left >= pTxPkt->frag_list.cnt + 2))
{
rc = lm_send_packet(pLM, idx, &pTxPkt->lm_pkt, &pTxPkt->frag_list);
if (pUM->fmCapabilities &&
BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
{
ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
}
if (pUM->fmCapabilities &&
BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_1]) != DDI_FM_OK)
{
ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
}
if (rc == LM_STATUS_SUCCESS)
{
/* send completely successfully */
BNXE_LOCK_EXIT_TX(pUM, idx);
return BNXE_TX_GOODXMIT;
}
/*
* Send failed (probably not enough BDs available)...
* Continue on with putting this packet on the wait queue.
*/
pTxQ->txFailed++;
}
#if 0
BnxeLogWarn(pUM, "WAIT TX DESCQ %lu %d %d",
s_list_entry_cnt(&pTxQ->waitTxDescQ),
pLmTxChain->bd_chain.bd_left, pTxPkt->frag_list.cnt);
#endif
/*
* If we got here then there are other packets waiting to be sent or there
* aren't enough BDs available. In either case put this packet at the end
* of the waiting queue.
*/
s_list_push_tail(&pTxQ->waitTxDescQ, &pTxPkt->lm_pkt.link);
pTxQ->txWait++;
/*
* If there appears to be a sufficient number of BDs available then make a
* quick attempt to send as many waiting packets as possible.
*/
if ((pLmTxChain->bd_chain.bd_left >= BNXE_MAX_DMA_FRAGS_PER_PKT) &&
(BnxeTxSendWaitingPkt(pUM, idx) == BNXE_TX_GOODXMIT))
{
BNXE_LOCK_EXIT_TX(pUM, idx);
return BNXE_TX_GOODXMIT;
}
/* Couldn't send anything! */
atomic_or_32(&pTxQ->noTxCredits, BNXE_TX_RESOURCES_NO_CREDIT);
pTxQ->txBlocked++;
BNXE_LOCK_EXIT_TX(pUM, idx);
return BNXE_TX_DEFERPKT;
BnxeTxSendMblk_fail:
pTxQ->txDiscards++;
ASSERT(pTxPkt != NULL);
if (pTxPkt->pMblk)
{
freemsg(pTxPkt->pMblk);
pTxPkt->pMblk = NULL;
}
BNXE_LOCK_ENTER_FREETX(pUM, idx);
s_list_push_tail(&pTxQ->freeTxDescQ, &pTxPkt->lm_pkt.link);
BNXE_LOCK_EXIT_FREETX(pUM, idx);
/*
* Yes GOODXMIT since mblk was free'd here and this triggers caller to
* try and send the next packet in its chain.
*/
return BNXE_TX_GOODXMIT;
}
static void BnxeTxPktsAbortIdx(um_device_t * pUM,
int idx)
{
s_list_t tmpList;
BNXE_LOCK_ENTER_TX(pUM, idx);
lm_abort(&pUM->lm_dev, ABORT_OP_INDICATE_TX_CHAIN, idx);
tmpList = pUM->txq[idx].waitTxDescQ;
s_list_clear(&pUM->txq[idx].waitTxDescQ);
BNXE_LOCK_EXIT_TX(pUM, idx);
BnxeTxPktsReclaim(pUM, idx, &tmpList);
}
void BnxeTxPktsAbort(um_device_t * pUM,
int cliIdx)
{
int idx;
switch (cliIdx)
{
case LM_CLI_IDX_FCOE:
BnxeTxPktsAbortIdx(pUM, FCOE_CID(&pUM->lm_dev));
break;
case LM_CLI_IDX_NDIS:
LM_FOREACH_TSS_IDX(&pUM->lm_dev, idx)
{
BnxeTxPktsAbortIdx(pUM, idx);
}
break;
default:
BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeTxPktsAbort (%d)", cliIdx);
break;
}
}
static um_txpacket_t * BnxeTxPktAlloc(um_device_t * pUM,
size_t size)
{
um_txpacket_t * pTxPkt;
ddi_dma_cookie_t cookie;
u32_t count;
size_t length;
int rc, j;
if ((pTxPkt = kmem_zalloc(sizeof(um_txpacket_t), KM_NOSLEEP)) == NULL)
{
return NULL;
}
pTxPkt->lm_pkt.l2pkt_tx_info = &pTxPkt->tx_info;
if ((rc = ddi_dma_alloc_handle(pUM->pDev,
&bnxeTxCbDmaAttrib,
DDI_DMA_DONTWAIT,
NULL,
&pTxPkt->cbDmaHandle)) != DDI_SUCCESS)
{
BnxeLogWarn(pUM, "Failed to alloc DMA handle for Tx Desc (%d)", rc);
kmem_free(pTxPkt, sizeof(um_txpacket_t));
return NULL;
}
if ((rc = ddi_dma_mem_alloc(pTxPkt->cbDmaHandle,
size,
&bnxeAccessAttribBUF,
DDI_DMA_STREAMING,
DDI_DMA_DONTWAIT,
NULL,
&pTxPkt->pCbBuf,
&length,
&pTxPkt->cbDmaAccHandle)) != DDI_SUCCESS)
{
BnxeLogWarn(pUM, "Failed to alloc DMA memory for Tx Desc (%d)", rc);
ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
kmem_free(pTxPkt, sizeof(um_txpacket_t));
return NULL;
}
if ((rc = ddi_dma_addr_bind_handle(pTxPkt->cbDmaHandle,
NULL,
pTxPkt->pCbBuf,
length,
DDI_DMA_WRITE | DDI_DMA_STREAMING,
DDI_DMA_DONTWAIT,
NULL,
&cookie,
&count)) != DDI_DMA_MAPPED)
{
BnxeLogWarn(pUM, "Failed to bind DMA address for Tx Desc (%d)", rc);
ddi_dma_mem_free(&pTxPkt->cbDmaAccHandle);
ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
kmem_free(pTxPkt, sizeof(um_txpacket_t));
return NULL;
}
pTxPkt->cbPhysAddr.as_u64 = cookie.dmac_laddress;
for (j = 0; j < BNXE_MAX_DMA_HANDLES_PER_PKT; j++)
{
if ((rc = ddi_dma_alloc_handle(pUM->pDev,
&bnxeTxDmaAttrib,
DDI_DMA_DONTWAIT,
NULL,
&pTxPkt->dmaHandles[j])) !=
DDI_SUCCESS)
{
BnxeLogWarn(pUM, "Failed to alloc DMA handles for Tx Pkt %d (%d)",
j, rc);
for(--j; j >= 0; j--) /* unwind */
{
ddi_dma_free_handle(&pTxPkt->dmaHandles[j]);
}
ddi_dma_unbind_handle(pTxPkt->cbDmaHandle);
ddi_dma_mem_free(&pTxPkt->cbDmaAccHandle);
ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
kmem_free(pTxPkt, sizeof(um_txpacket_t));
return NULL;
}
}
ASSERT(pTxPkt->pMblk == NULL);
ASSERT(pTxPkt->num_handles == 0);
ASSERT(pTxPkt->frag_list.cnt == 0);
pTxPkt->cbLength = size;
return pTxPkt;
}
static int BnxeTxPktsInitIdx(um_device_t * pUM,
int idx)
{
lm_device_t * pLM = &pUM->lm_dev;
TxQueue * pTxQ;
um_txpacket_t * pTxPkt;
s_list_t tmpList;
int i;
pTxQ = &pUM->txq[idx];
s_list_clear(&pTxQ->sentTxQ);
s_list_clear(&pTxQ->freeTxDescQ);
s_list_clear(&pTxQ->waitTxDescQ);
pTxQ->desc_cnt = pUM->devParams.numTxDesc[LM_CHAIN_IDX_CLI(pLM, idx)];
pTxQ->txLowWater = pUM->devParams.numTxDesc[LM_CHAIN_IDX_CLI(pLM, idx)];
pTxQ->thresh_pdwm = BNXE_PDWM_THRESHOLD;
pTxQ->txFailed = 0;
pTxQ->txDiscards = 0;
pTxQ->txRecycle = 0;
pTxQ->txCopied = 0;
pTxQ->txBlocked = 0;
pTxQ->txWait = 0;
if (pUM->devParams.lsoEnable)
{
for (i = 0; i < pTxQ->desc_cnt; i++)
{
pTxPkt = BnxeTxPktAlloc(pUM,
(BNXE_IP_MAXLEN +
sizeof(struct ether_vlan_header)));
if (pTxPkt == NULL)
{
BnxeLogWarn(pUM, "Failed to allocate all Tx Descs for LSO (%d/%d allocated), LSO is disabled",
i, pTxQ->desc_cnt);
/* free existing in freeTxDescQ... */
BNXE_LOCK_ENTER_FREETX(pUM, idx);
tmpList = pTxQ->freeTxDescQ;
s_list_clear(&pTxQ->freeTxDescQ);
BNXE_LOCK_EXIT_FREETX(pUM, idx);
BnxeTxPktsFreeList(&tmpList);
pUM->devParams.lsoEnable = 0; /* Disabling LSO! */
break;
}
BNXE_LOCK_ENTER_FREETX(pUM, idx);
s_list_push_tail(&pTxQ->freeTxDescQ, &pTxPkt->lm_pkt.link);
BNXE_LOCK_EXIT_FREETX(pUM, idx);
}
}
if (!pUM->devParams.lsoEnable)
{
for (i = 0; i < pTxQ->desc_cnt; i++)
{
pTxPkt = BnxeTxPktAlloc(pUM,
(pUM->devParams.mtu[LM_CHAIN_IDX_CLI(pLM, idx)] +
sizeof(struct ether_vlan_header)));
if (pTxPkt == NULL)
{
BnxeLogWarn(pUM, "Failed to allocate all Tx Descs (%d/%d allocated)",
i, pTxQ->desc_cnt);
/* free existing in freeTxDescQ... */
BNXE_LOCK_ENTER_FREETX(pUM, idx);
tmpList = pTxQ->freeTxDescQ;
s_list_clear(&pTxQ->freeTxDescQ);
BNXE_LOCK_EXIT_FREETX(pUM, idx);
BnxeTxPktsFreeList(&tmpList);
return -1;
}
BNXE_LOCK_ENTER_FREETX(pUM, idx);
s_list_push_tail(&pTxQ->freeTxDescQ, &pTxPkt->lm_pkt.link);
BNXE_LOCK_EXIT_FREETX(pUM, idx);
}
}
return 0;
}
int BnxeTxPktsInit(um_device_t * pUM,
int cliIdx)
{
int idx, rc;
switch (cliIdx)
{
case LM_CLI_IDX_FCOE:
rc = BnxeTxPktsInitIdx(pUM, FCOE_CID(&pUM->lm_dev));
break;
case LM_CLI_IDX_NDIS:
LM_FOREACH_TSS_IDX(&pUM->lm_dev, idx)
{
if ((rc = BnxeTxPktsInitIdx(pUM, idx)) < 0)
{
break;
}
}
break;
default:
BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeTxPktsFini (%d)", cliIdx);
rc = -1;
break;
}
return rc;
}
static void BnxeTxPktsFiniIdx(um_device_t * pUM,
int idx)
{
lm_device_t * pLM = &pUM->lm_dev;
TxQueue * pTxQ;
s_list_t tmpList;
pTxQ = &pUM->txq[idx];
BNXE_LOCK_ENTER_FREETX(pUM, idx);
tmpList = pTxQ->freeTxDescQ;
s_list_clear(&pTxQ->freeTxDescQ);
BNXE_LOCK_EXIT_FREETX(pUM, idx);
BNXE_LOCK_ENTER_TX(pUM, idx);
s_list_add_tail(&tmpList, &pTxQ->sentTxQ);
s_list_clear(&pTxQ->sentTxQ);
BNXE_LOCK_EXIT_TX(pUM, idx);
/* there could be more than originally allocated but less is bad */
if (s_list_entry_cnt(&tmpList) <
pUM->devParams.numTxDesc[LM_CHAIN_IDX_CLI(pLM, idx)])
{
BnxeLogWarn(pUM, "Missing TX descriptors (%lu / %d) (TxFail: %d)",
s_list_entry_cnt(&tmpList), pUM->devParams.numTxDesc,
pTxQ->txFailed);
}
BnxeTxPktsFreeList(&tmpList);
}
void BnxeTxPktsFini(um_device_t * pUM,
int cliIdx)
{
int idx;
switch (cliIdx)
{
case LM_CLI_IDX_FCOE:
BnxeTxPktsFiniIdx(pUM, FCOE_CID(&pUM->lm_dev));
break;
case LM_CLI_IDX_NDIS:
LM_FOREACH_TSS_IDX(&pUM->lm_dev, idx)
{
BnxeTxPktsFiniIdx(pUM, idx);
}
break;
default:
BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeTxPktsFini (%d)", cliIdx);
break;
}
}