oce_tx.c revision 5b9d3151a4426af9ad6ef2c2a178f13476b884b3
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * CDDL HEADER START
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * The contents of this file are subject to the terms of the
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * Common Development and Distribution License (the "License").
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * You may not use this file except in compliance with the License.
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * or http://www.opensolaris.org/os/licensing.
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * See the License for the specific language governing permissions
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * and limitations under the License.
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * When distributing Covered Code, include this CDDL HEADER in each
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * If applicable, add the following below this CDDL HEADER, with the
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * fields enclosed by brackets "[]" replaced with your own identifying
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * information: Portions Copyright [yyyy] [name of copyright owner]
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * CDDL HEADER END
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
80e2ca8596e3435bc3b76f3c597833ea0a87f85e * Copyright 2010 Emulex. All rights reserved.
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * Use is subject to license terms.
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * Source file containing the implementation of the Transmit
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * Path
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner#include <oce_impl.h>
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_free_wqed(struct oce_wq *wq, oce_wqe_desc_t *wqed);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic int oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner mblk_t *mp, uint32_t pkt_len);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic int oce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner uint32_t pkt_len);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
80e2ca8596e3435bc3b76f3c597833ea0a87f85estatic int oce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner size_t size, int flags);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic inline oce_wq_bdesc_t *oce_wqb_alloc(struct oce_wq *wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic oce_wq_mdesc_t *oce_wqm_alloc(struct oce_wq *wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic int oce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_remove_vtag(mblk_t *mp);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void oce_insert_vtag(mblk_t *mp, uint16_t vlan_tag);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic inline int oce_process_tx_compl(struct oce_wq *wq, boolean_t rearm);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic ddi_dma_attr_t tx_map_dma_attr = {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner DMA_ATTR_V0, /* version number */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x0000000000000000ull, /* low address */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0xFFFFFFFFFFFFFFFFull, /* high address */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x0000000000010000ull, /* dma counter max */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_TXMAP_ALIGN, /* alignment */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x7FF, /* burst sizes */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x00000001, /* minimum transfer size */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x00000000FFFFFFFFull, /* maximum transfer size */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_MAX_TXDMA_COOKIES, /* scatter/gather list length */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x00000001, /* granularity */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner DDI_DMA_FLAGERR /* dma_attr_flags */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner};
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerddi_dma_attr_t oce_tx_dma_buf_attr = {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner DMA_ATTR_V0, /* version number */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x0000000000000000ull, /* low address */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0xFFFFFFFFFFFFFFFFull, /* high address */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x00000000FFFFFFFFull, /* dma counter max */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_DMA_ALIGNMENT, /* alignment */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x000007FF, /* burst sizes */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x00000001, /* minimum transfer size */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x00000000FFFFFFFFull, /* maximum transfer size */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0xFFFFFFFFFFFFFFFFull, /* maximum segment size */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 1, /* scatter/gather list length */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner 0x00000001, /* granularity */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner DDI_DMA_FLAGERR /* dma_attr_flags */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner};
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * WQ map handle destructor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - Pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqmd - pointer to WQE mapping handle descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner _NOTE(ARGUNUSED(wq));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* Free the DMA handle */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (wqmd->dma_handle != NULL)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner (void) ddi_dma_free_handle(&(wqmd->dma_handle));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqmd->dma_handle = NULL;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner} /* oce_wqm_dtor */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * WQ map handles contructor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqmd - pointer to WQE mapping handle descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - Pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return DDI_SUCCESS=>success, DDI_FAILURE=>error
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic int
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_dev *dev;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int ret;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner dev = wq->parent;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* Allocate DMA handle */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner ret = ddi_dma_alloc_handle(dev->dip, &tx_map_dma_attr,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner DDI_DMA_DONTWAIT, NULL, &wqmd->dma_handle);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (ret);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner} /* oce_wqm_ctor */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to create WQ mapping handles cache
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return DDI_SUCCESS=>success, DDI_FAILURE=>error
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerint
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqm_cache_create(struct oce_wq *wq)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_dev *dev = wq->parent;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int size;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int cnt;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int ret;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner size = wq->cfg.nhdl * sizeof (oce_wq_mdesc_t);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wq->wq_mdesc_array = kmem_zalloc(size, KM_NOSLEEP);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (wq->wq_mdesc_array == NULL) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (DDI_FAILURE);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* Create the free buffer list */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_LIST_CREATE(&wq->wq_mdesc_list, DDI_INTR_PRI(dev->intr_pri));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner for (cnt = 0; cnt < wq->cfg.nhdl; cnt++) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner ret = oce_wqm_ctor(&wq->wq_mdesc_array[cnt], wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (ret != DDI_SUCCESS) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner goto wqm_fail;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_LIST_INSERT_TAIL(&wq->wq_mdesc_list,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner &wq->wq_mdesc_array[cnt]);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (DDI_SUCCESS);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerwqm_fail:
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wqm_cache_destroy(wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (DDI_FAILURE);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to destroy WQ mapping handles cache
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknervoid
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqm_cache_destroy(struct oce_wq *wq)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wq_mdesc_t *wqmd;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner while ((wqmd = OCE_LIST_REM_HEAD(&wq->wq_mdesc_list)) != NULL) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wqm_dtor(wq, wqmd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner kmem_free(wq->wq_mdesc_array,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wq->cfg.nhdl * sizeof (oce_wq_mdesc_t));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_LIST_DESTROY(&wq->wq_mdesc_list);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to create WQ buffer cache
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * buf_size - size of the buffer
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return DDI_SUCCESS=>success, DDI_FAILURE=>error
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerint
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqb_cache_create(struct oce_wq *wq, size_t buf_size)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_dev *dev = wq->parent;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int size;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int cnt;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int ret;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner size = wq->cfg.nbufs * sizeof (oce_wq_bdesc_t);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wq->wq_bdesc_array = kmem_zalloc(size, KM_NOSLEEP);
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner if (wq->wq_bdesc_array == NULL) {
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner return (DDI_FAILURE);
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner }
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner /* Create the free buffer list */
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner OCE_LIST_CREATE(&wq->wq_buf_list, DDI_INTR_PRI(dev->intr_pri));
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner for (cnt = 0; cnt < wq->cfg.nbufs; cnt++) {
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner ret = oce_wqb_ctor(&wq->wq_bdesc_array[cnt],
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner wq, buf_size, DDI_DMA_STREAMING);
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner if (ret != DDI_SUCCESS) {
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner goto wqb_fail;
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner }
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner OCE_LIST_INSERT_TAIL(&wq->wq_buf_list,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner &wq->wq_bdesc_array[cnt]);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner return (DDI_SUCCESS);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerwqb_fail:
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner oce_wqb_cache_destroy(wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (DDI_FAILURE);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to destroy WQ buffer cache
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknervoid
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqb_cache_destroy(struct oce_wq *wq)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wq_bdesc_t *wqbd;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner while ((wqbd = OCE_LIST_REM_HEAD(&wq->wq_buf_list)) != NULL) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wqb_dtor(wq, wqbd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner kmem_free(wq->wq_bdesc_array,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wq->cfg.nbufs * sizeof (oce_wq_bdesc_t));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_LIST_DESTROY(&wq->wq_buf_list);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * WQ buffer constructor
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner *
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * wqbd - pointer to WQ buffer descriptor
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * wq - pointer to WQ structure
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * size - size of the buffer
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * flags - KM_SLEEP or KM_NOSLEEP
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner *
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * return DDI_SUCCESS=>success, DDI_FAILURE=>error
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner */
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulknerstatic int
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkneroce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq, size_t size, int flags)
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner{
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner struct oce_dev *dev;
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner dev = wq->parent;
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner wqbd->wqb = oce_alloc_dma_buffer(dev, size, &oce_tx_dma_buf_attr,
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner flags);
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner if (wqbd->wqb == NULL) {
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner return (DDI_FAILURE);
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner }
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner wqbd->frag_addr.dw.addr_lo = ADDR_LO(wqbd->wqb->addr);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqbd->frag_addr.dw.addr_hi = ADDR_HI(wqbd->wqb->addr);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (DDI_SUCCESS);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * WQ buffer destructor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqbd - pointer to WQ buffer descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_free_dma_buffer(wq->parent, wqbd->wqb);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to alloc WQE buffer descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return pointer to WQE buffer descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic inline oce_wq_bdesc_t *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqb_alloc(struct oce_wq *wq)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (OCE_LIST_REM_HEAD(&wq->wq_buf_list));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to free WQE buffer descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqbd - pointer to WQ buffer descriptor
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner *
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * return none
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner */
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulknerstatic inline void
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkneroce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd)
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner{
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner OCE_LIST_INSERT_TAIL(&wq->wq_buf_list, wqbd);
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner} /* oce_wqb_free */
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner/*
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * function to allocate WQE mapping descriptor
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner *
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner * wq - pointer to WQ structure
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return pointer to WQE mapping descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic inline oce_wq_mdesc_t *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqm_alloc(struct oce_wq *wq)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (OCE_LIST_REM_HEAD(&wq->wq_mdesc_list));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner} /* oce_wqm_alloc */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to insert WQE mapping descriptor to the list
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqmd - Pointer to WQ mapping descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic inline void
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner OCE_LIST_INSERT_TAIL(&wq->wq_mdesc_list, wqmd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to free WQE mapping descriptor
80e2ca8596e3435bc3b76f3c597833ea0a87f85e *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ structure
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqmd - Pointer to WQ mapping descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (wqmd == NULL) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner (void) ddi_dma_unbind_handle(wqmd->dma_handle);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wqm_free(wq, wqmd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * WQED kmem_cache constructor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * buf - pointer to WQE descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return DDI_SUCCESS
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
80e2ca8596e3435bc3b76f3c597833ea0a87f85eint
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqe_desc_ctor(void *buf, void *arg, int kmflags)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner _NOTE(ARGUNUSED(buf));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner _NOTE(ARGUNUSED(arg));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner _NOTE(ARGUNUSED(kmflags));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (DDI_SUCCESS);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * WQED kmem_cache destructor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * buf - pointer to WQE descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknervoid
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_wqe_desc_dtor(void *buf, void *arg)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner _NOTE(ARGUNUSED(buf));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner _NOTE(ARGUNUSED(arg));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner}
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
80e2ca8596e3435bc3b76f3c597833ea0a87f85e/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to choose a WQ given a mblk depending on priority, flowID etc.
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * dev - software handle to device
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * mp - the mblk to send
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return pointer to the WQ selected
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic uint8_t oce_tx_hash_policy = 0x4;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstruct oce_wq *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_get_wq(struct oce_dev *dev, mblk_t *mp)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_wq *wq;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int qidx = 0;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (dev->nwqs > 1) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner qidx = mac_pkt_hash(DL_ETHER, mp, oce_tx_hash_policy, B_TRUE);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner qidx = qidx % dev->nwqs;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner } else {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner qidx = 0;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wq = dev->wq[qidx];
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* for the time being hardcode */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner} /* oce_get_wq */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to populate the single WQE
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to wq
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqed - pointer to WQ entry descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return none
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner#pragma inline(oce_fill_ring_descs)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic void
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_nic_frag_wqe *wqe;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int i;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* Copy the precreate WQE descs to the ring desc */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner for (i = 0; i < wqed->wqe_cnt; i++) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqe = RING_GET_PRODUCER_ITEM_VA(wq->ring,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_nic_frag_wqe);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner bcopy(&wqed->frag[i], wqe, NIC_WQE_SIZE);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner RING_PUT(wq->ring, 1);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner} /* oce_fill_ring_descs */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to copy the packet to preallocated Tx buffer
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqed - Pointer to WQE descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * mp - Pointer to packet chain
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * pktlen - Size of the packet
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return 0=>success, error code otherwise
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic int
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner uint32_t pkt_len)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wq_bdesc_t *wqbd;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner caddr_t buf_va;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_dev *dev = wq->parent;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int len = 0;
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner
794f0adb050e571bbfde4d2a19b9f88b852079ddRoger A. Faulkner wqbd = oce_wqb_alloc(wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (wqbd == NULL) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner atomic_inc_32(&dev->tx_noxmtbuf);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_log(dev, CE_WARN, MOD_TX, "%s",
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner "wqb pool empty");
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (ENOMEM);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* create a fragment wqe for the packet */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi = wqbd->frag_addr.dw.addr_hi;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo = wqbd->frag_addr.dw.addr_lo;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner buf_va = DBUF_VA(wqbd->wqb);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* copy pkt into buffer */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner for (len = 0; mp != NULL && len < pkt_len; mp = mp->b_cont) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner bcopy(mp->b_rptr, buf_va, MBLKL(mp));
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner buf_va += MBLKL(mp);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner len += MBLKL(mp);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner (void) ddi_dma_sync(DBUF_DHDL(wqbd->wqb), 0, pkt_len,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner DDI_DMA_SYNC_FORDEV);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (oce_fm_check_dma_handle(dev, DBUF_DHDL(wqbd->wqb))) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner /* Free the buffer */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wqb_free(wq, wqbd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (EIO);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->frag[wqed->frag_idx].u0.s.frag_len = pkt_len;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->hdesc[wqed->nhdl].hdl = (void *)(wqbd);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->hdesc[wqed->nhdl].type = COPY_WQE;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->frag_cnt++;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->frag_idx++;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqed->nhdl++;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (0);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner} /* oce_bcopy_wqe */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner/*
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * function to copy the packet or dma map on the fly depending on size
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wq - pointer to WQ
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * wqed - Pointer to WQE descriptor
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * mp - Pointer to packet chain
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner *
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner * return DDI_SUCCESS=>success, DDI_FAILURE=>error
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner */
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulknerstatic int
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkneroce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner uint32_t pkt_len)
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner{
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner ddi_dma_cookie_t cookie;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_wq_mdesc_t *wqmd;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner uint32_t ncookies;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner int ret;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner struct oce_dev *dev = wq->parent;
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner wqmd = oce_wqm_alloc(wq);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner if (wqmd == NULL) {
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner oce_log(dev, CE_WARN, MOD_TX, "%s",
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner "wqm pool empty");
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner return (ENOMEM);
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner }
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner ret = ddi_dma_addr_bind_handle(wqmd->dma_handle,
8fd04b8338ed5093ec2d1e668fa620b7de44c177Roger A. Faulkner (struct as *)0, (caddr_t)mp->b_rptr,
pkt_len, DDI_DMA_WRITE | DDI_DMA_STREAMING,
DDI_DMA_DONTWAIT, NULL, &cookie, &ncookies);
if (ret != DDI_DMA_MAPPED) {
oce_log(dev, CE_WARN, MOD_TX, "MAP FAILED %d",
ret);
/* free the last one */
oce_wqm_free(wq, wqmd);
return (ENOMEM);
}
do {
wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi =
ADDR_HI(cookie.dmac_laddress);
wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo =
ADDR_LO(cookie.dmac_laddress);
wqed->frag[wqed->frag_idx].u0.s.frag_len =
(uint32_t)cookie.dmac_size;
wqed->frag_cnt++;
wqed->frag_idx++;
if (--ncookies > 0)
ddi_dma_nextcookie(wqmd->dma_handle,
&cookie);
else break;
} while (ncookies > 0);
wqed->hdesc[wqed->nhdl].hdl = (void *)wqmd;
wqed->hdesc[wqed->nhdl].type = MAPPED_WQE;
wqed->nhdl++;
return (0);
} /* oce_map_wqe */
static inline int
oce_process_tx_compl(struct oce_wq *wq, boolean_t rearm)
{
struct oce_nic_tx_cqe *cqe;
uint16_t num_cqe = 0;
struct oce_cq *cq;
oce_wqe_desc_t *wqed;
int wqe_freed = 0;
struct oce_dev *dev;
cq = wq->cq;
dev = wq->parent;
(void) ddi_dma_sync(cq->ring->dbuf->dma_handle, 0, 0,
DDI_DMA_SYNC_FORKERNEL);
mutex_enter(&wq->txc_lock);
cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
while (WQ_CQE_VALID(cqe)) {
DW_SWAP(u32ptr(cqe), sizeof (struct oce_nic_tx_cqe));
/* update stats */
if (cqe->u0.s.status != 0) {
atomic_inc_32(&dev->tx_errors);
}
/* complete the WQEs */
wqed = OCE_LIST_REM_HEAD(&wq->wqe_desc_list);
wqe_freed = wqed->wqe_cnt;
oce_free_wqed(wq, wqed);
RING_GET(wq->ring, wqe_freed);
atomic_add_32(&wq->wq_free, wqe_freed);
/* clear the valid bit and progress cqe */
WQ_CQE_INVALIDATE(cqe);
RING_GET(cq->ring, 1);
cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring,
struct oce_nic_tx_cqe);
num_cqe++;
} /* for all valid CQE */
mutex_exit(&wq->txc_lock);
if (num_cqe)
oce_arm_cq(wq->parent, cq->cq_id, num_cqe, rearm);
return (num_cqe);
} /* oce_process_tx_completion */
/*
* function to drain a TxCQ and process its CQEs
*
* dev - software handle to the device
* cq - pointer to the cq to drain
*
* return the number of CQEs processed
*/
uint16_t
oce_drain_wq_cq(void *arg)
{
uint16_t num_cqe = 0;
struct oce_dev *dev;
struct oce_wq *wq;
wq = (struct oce_wq *)arg;
dev = wq->parent;
/* do while we do not reach a cqe that is not valid */
num_cqe = oce_process_tx_compl(wq, B_FALSE);
/* check if we need to restart Tx */
if (wq->resched && num_cqe) {
wq->resched = B_FALSE;
mac_tx_update(dev->mac_handle);
}
return (num_cqe);
} /* oce_process_wq_cqe */
/*
* function to insert vtag to packet
*
* mp - mblk pointer
* vlan_tag - tag to be inserted
*
* return none
*/
static inline void
oce_insert_vtag(mblk_t *mp, uint16_t vlan_tag)
{
struct ether_vlan_header *evh;
(void) memmove(mp->b_rptr - VLAN_TAGSZ,
mp->b_rptr, 2 * ETHERADDRL);
mp->b_rptr -= VLAN_TAGSZ;
evh = (struct ether_vlan_header *)(void *)mp->b_rptr;
evh->ether_tpid = htons(VLAN_TPID);
evh->ether_tci = htons(vlan_tag);
}
/*
* function to strip vtag from packet
*
* mp - mblk pointer
*
* return none
*/
static inline void
oce_remove_vtag(mblk_t *mp)
{
(void) memmove(mp->b_rptr + VLAN_TAGSZ, mp->b_rptr,
ETHERADDRL * 2);
mp->b_rptr += VLAN_TAGSZ;
}
/*
* function to xmit Single packet over the wire
*
* wq - pointer to WQ
* mp - Pointer to packet chain
*
* return pointer to the packet
*/
mblk_t *
oce_send_packet(struct oce_wq *wq, mblk_t *mp)
{
struct oce_nic_hdr_wqe *wqeh;
struct oce_dev *dev;
struct ether_header *eh;
struct ether_vlan_header *evh;
int32_t num_wqes;
uint16_t etype;
uint32_t ip_offset;
uint32_t csum_flags = 0;
boolean_t use_copy = B_FALSE;
boolean_t tagged = B_FALSE;
uint16_t vlan_tag;
uint32_t reg_value = 0;
oce_wqe_desc_t *wqed = NULL;
mblk_t *nmp = NULL;
mblk_t *tmp = NULL;
uint32_t pkt_len = 0;
int num_mblks = 0;
int ret = 0;
uint32_t mss = 0;
uint32_t flags = 0;
int len = 0;
/* retrieve the adap priv struct ptr */
dev = wq->parent;
/* check if we have enough free slots */
if (wq->wq_free < dev->tx_reclaim_threshold) {
(void) oce_process_tx_compl(wq, B_FALSE);
}
if (wq->wq_free < OCE_MAX_TX_HDL) {
return (mp);
}
/* check if we should copy */
for (tmp = mp; tmp != NULL; tmp = tmp->b_cont) {
pkt_len += MBLKL(tmp);
num_mblks++;
}
if (pkt_len == 0 || num_mblks == 0) {
freemsg(mp);
return (NULL);
}
/* retrieve LSO information */
mac_lso_get(mp, &mss, &flags);
/* get the offload flags */
mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &csum_flags);
/* restrict the mapped segment to wat we support */
if (num_mblks > OCE_MAX_TX_HDL) {
nmp = msgpullup(mp, -1);
if (nmp == NULL) {
atomic_inc_32(&wq->pkt_drops);
freemsg(mp);
return (NULL);
}
/* Reset it to new collapsed mp */
freemsg(mp);
mp = nmp;
}
/* Get the packet descriptor for Tx */
wqed = kmem_cache_alloc(wq->wqed_cache, KM_NOSLEEP);
if (wqed == NULL) {
atomic_inc_32(&wq->pkt_drops);
freemsg(mp);
return (NULL);
}
eh = (struct ether_header *)(void *)mp->b_rptr;
if (ntohs(eh->ether_type) == VLAN_TPID) {
evh = (struct ether_vlan_header *)(void *)mp->b_rptr;
tagged = B_TRUE;
etype = ntohs(evh->ether_type);
ip_offset = sizeof (struct ether_vlan_header);
pkt_len -= VLAN_TAGSZ;
vlan_tag = ntohs(evh->ether_tci);
oce_remove_vtag(mp);
} else {
etype = ntohs(eh->ether_type);
ip_offset = sizeof (struct ether_header);
}
/* Save the WQ pointer */
wqed->wq = wq;
wqed->frag_idx = 1; /* index zero is always header */
wqed->frag_cnt = 0;
wqed->nhdl = 0;
wqed->mp = NULL;
OCE_LIST_LINK_INIT(&wqed->link);
/* If entire packet is less than the copy limit just do copy */
if (pkt_len < dev->tx_bcopy_limit) {
use_copy = B_TRUE;
ret = oce_bcopy_wqe(wq, wqed, mp, pkt_len);
} else {
/* copy or dma map the individual fragments */
for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) {
len = MBLKL(nmp);
if (len == 0) {
continue;
}
if (len < dev->tx_bcopy_limit) {
ret = oce_bcopy_wqe(wq, wqed, nmp, len);
} else {
ret = oce_map_wqe(wq, wqed, nmp, len);
}
if (ret != 0)
break;
}
}
/*
* Any failure other than insufficient Q entries
* drop the packet
*/
if (ret != 0) {
oce_free_wqed(wq, wqed);
atomic_inc_32(&wq->pkt_drops);
freemsg(mp);
return (NULL);
}
wqeh = (struct oce_nic_hdr_wqe *)&wqed->frag[0];
bzero(wqeh, sizeof (struct oce_nic_hdr_wqe));
/* fill rest of wqe header fields based on packet */
if (flags & HW_LSO) {
wqeh->u0.s.lso = B_TRUE;
wqeh->u0.s.lso_mss = mss;
}
if (csum_flags & HCK_FULLCKSUM) {
uint8_t *proto;
if (etype == ETHERTYPE_IP) {
proto = (uint8_t *)(void *)
(mp->b_rptr + ip_offset);
if (proto[9] == 6)
/* IPPROTO_TCP */
wqeh->u0.s.tcpcs = B_TRUE;
else if (proto[9] == 17)
/* IPPROTO_UDP */
wqeh->u0.s.udpcs = B_TRUE;
}
}
if (csum_flags & HCK_IPV4_HDRCKSUM)
wqeh->u0.s.ipcs = B_TRUE;
if (tagged) {
wqeh->u0.s.vlan = B_TRUE;
wqeh->u0.s.vlan_tag = vlan_tag;
}
wqeh->u0.s.complete = B_TRUE;
wqeh->u0.s.event = B_TRUE;
wqeh->u0.s.crc = B_TRUE;
wqeh->u0.s.total_length = pkt_len;
num_wqes = wqed->frag_cnt + 1;
/* h/w expects even no. of WQEs */
if (num_wqes & 0x1) {
bzero(&wqed->frag[num_wqes], sizeof (struct oce_nic_frag_wqe));
num_wqes++;
}
wqed->wqe_cnt = (uint16_t)num_wqes;
wqeh->u0.s.num_wqe = num_wqes;
DW_SWAP(u32ptr(&wqed->frag[0]), (wqed->wqe_cnt * NIC_WQE_SIZE));
mutex_enter(&wq->tx_lock);
if (num_wqes > wq->wq_free) {
atomic_inc_32(&wq->tx_deferd);
mutex_exit(&wq->tx_lock);
goto wqe_fail;
}
atomic_add_32(&wq->wq_free, -num_wqes);
/* fill the wq for adapter */
oce_fill_ring_descs(wq, wqed);
/* Add the packet desc to list to be retrieved during cmpl */
OCE_LIST_INSERT_TAIL(&wq->wqe_desc_list, wqed);
(void) ddi_dma_sync(wq->ring->dbuf->dma_handle, 0, 0,
DDI_DMA_SYNC_FORDEV);
/* ring tx doorbell */
reg_value = (num_wqes << 16) | wq->wq_id;
/* Ring the door bell */
OCE_DB_WRITE32(dev, PD_TXULP_DB, reg_value);
mutex_exit(&wq->tx_lock);
if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
}
/* free mp if copied or packet chain collapsed */
if (use_copy == B_TRUE) {
freemsg(mp);
} else
wqed->mp = mp;
return (NULL);
wqe_fail:
if (tagged) {
oce_insert_vtag(mp, vlan_tag);
}
oce_free_wqed(wq, wqed);
return (mp);
} /* oce_send_packet */
/*
* function to free the WQE descriptor
*
* wq - pointer to WQ
* wqed - Pointer to WQE descriptor
*
* return none
*/
#pragma inline(oce_free_wqed)
static void
oce_free_wqed(struct oce_wq *wq, oce_wqe_desc_t *wqed)
{
int i = 0;
if (wqed == NULL) {
return;
}
for (i = 0; i < wqed->nhdl; i++) {
if (wqed->hdesc[i].type == COPY_WQE) {
oce_wqb_free(wq, wqed->hdesc[i].hdl);
} else if (wqed->hdesc[i].type == MAPPED_WQE) {
oce_wqmd_free(wq, wqed->hdesc[i].hdl);
}
}
if (wqed->mp)
freemsg(wqed->mp);
kmem_cache_free(wq->wqed_cache, wqed);
} /* oce_free_wqed */
/*
* function to start the WQ
*
* wq - pointer to WQ
*
* return DDI_SUCCESS
*/
int
oce_start_wq(struct oce_wq *wq)
{
_NOTE(ARGUNUSED(wq));
return (DDI_SUCCESS);
} /* oce_start_wq */
/*
* function to stop the WQ
*
* wq - pointer to WQ
*
* return none
*/
void
oce_clean_wq(struct oce_wq *wq)
{
oce_wqe_desc_t *wqed;
int ti;
/* Wait for already posted Tx to complete */
for (ti = 0; ti < DEFAULT_DRAIN_TIME; ti++) {
(void) oce_process_tx_compl(wq, B_FALSE);
OCE_MSDELAY(1);
}
/* Free the remaining descriptors */
while ((wqed = OCE_LIST_REM_HEAD(&wq->wqe_desc_list)) != NULL) {
atomic_add_32(&wq->wq_free, wqed->wqe_cnt);
oce_free_wqed(wq, wqed);
}
oce_drain_eq(wq->cq->eq);
} /* oce_stop_wq */
/*
* function to set the tx mapping handle fma attr
*
* fm_caps - capability flags
*
* return none
*/
void
oce_set_tx_map_dma_fma_flags(int fm_caps)
{
if (fm_caps == DDI_FM_NOT_CAPABLE) {
return;
}
if (DDI_FM_DMA_ERR_CAP(fm_caps)) {
tx_map_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
} else {
tx_map_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
}
} /* oce_set_tx_map_dma_fma_flags */