/* SPDX-License-Identifier: BSD-3-Clause */ /* Copyright (c) 2021, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @file iavf_vc_iflib.c * @brief iflib-specific Virtchnl interface functions * * Contains functions implementing the virtchnl interface for communicating * with the PF driver. This file contains definitions specific to the iflib * driver implementation. */ #include "iavf_iflib.h" #include "iavf_vc_common.h" /** * iavf_configure_queues - Configure queues * @sc: device softc * * Request that the PF set up our queues. * * @returns zero on success, or an error code on failure. */ int iavf_configure_queues(struct iavf_sc *sc) { device_t dev = sc->dev; struct iavf_vsi *vsi = &sc->vsi; if_softc_ctx_t scctx = iflib_get_softc_ctx(vsi->ctx); struct iavf_tx_queue *tx_que = vsi->tx_queues; struct iavf_rx_queue *rx_que = vsi->rx_queues; struct tx_ring *txr; struct rx_ring *rxr; int len, pairs; struct virtchnl_vsi_queue_config_info *vqci; struct virtchnl_queue_pair_info *vqpi; /* XXX: Linux PF driver wants matching ids in each tx/rx struct, so both TX/RX * queues of a pair need to be configured */ pairs = max(vsi->num_tx_queues, vsi->num_rx_queues); len = sizeof(struct virtchnl_vsi_queue_config_info) + (sizeof(struct virtchnl_queue_pair_info) * pairs); vqci = malloc(len, M_IAVF, M_NOWAIT | M_ZERO); if (!vqci) { device_printf(dev, "%s: unable to allocate memory\n", __func__); return (ENOMEM); } vqci->vsi_id = sc->vsi_res->vsi_id; vqci->num_queue_pairs = pairs; vqpi = vqci->qpair; /* Size check is not needed here - HW max is 16 queue pairs, and we * can fit info for 31 of them into the AQ buffer before it overflows. */ // TODO: the above is wrong now; X722 VFs can have 256 queues for (int i = 0; i < pairs; i++, tx_que++, rx_que++, vqpi++) { txr = &tx_que->txr; rxr = &rx_que->rxr; vqpi->txq.vsi_id = vqci->vsi_id; vqpi->txq.queue_id = i; vqpi->txq.ring_len = scctx->isc_ntxd[0]; vqpi->txq.dma_ring_addr = txr->tx_paddr; /* Enable Head writeback */ if (!vsi->enable_head_writeback) { vqpi->txq.headwb_enabled = 0; vqpi->txq.dma_headwb_addr = 0; } else { vqpi->txq.headwb_enabled = 1; vqpi->txq.dma_headwb_addr = txr->tx_paddr + sizeof(struct iavf_tx_desc) * scctx->isc_ntxd[0]; } vqpi->rxq.vsi_id = vqci->vsi_id; vqpi->rxq.queue_id = i; vqpi->rxq.ring_len = scctx->isc_nrxd[0]; vqpi->rxq.dma_ring_addr = rxr->rx_paddr; vqpi->rxq.max_pkt_size = scctx->isc_max_frame_size; vqpi->rxq.databuffer_size = rxr->mbuf_sz; vqpi->rxq.splithdr_enabled = 0; } iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_VSI_QUEUES, (u8 *)vqci, len); free(vqci, M_IAVF); return (0); } /** * iavf_map_queues - Map queues to interrupt vectors * @sc: device softc * * Request that the PF map queues to interrupt vectors. Misc causes, including * admin queue, are always mapped to vector 0. * * @returns zero on success, or an error code on failure. */ int iavf_map_queues(struct iavf_sc *sc) { struct virtchnl_irq_map_info *vm; int i, q, len; struct iavf_vsi *vsi = &sc->vsi; struct iavf_rx_queue *rx_que = vsi->rx_queues; if_softc_ctx_t scctx = vsi->shared; device_t dev = sc->dev; // XXX: What happens if we only get 1 MSI-X vector? MPASS(scctx->isc_vectors > 1); /* How many queue vectors, adminq uses one */ // XXX: How do we know how many interrupt vectors we have? q = scctx->isc_vectors - 1; len = sizeof(struct virtchnl_irq_map_info) + (scctx->isc_vectors * sizeof(struct virtchnl_vector_map)); vm = malloc(len, M_IAVF, M_NOWAIT); if (!vm) { device_printf(dev, "%s: unable to allocate memory\n", __func__); return (ENOMEM); } vm->num_vectors = scctx->isc_vectors; /* Queue vectors first */ for (i = 0; i < q; i++, rx_que++) { vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id; vm->vecmap[i].vector_id = i + 1; /* first is adminq */ // TODO: Re-examine this vm->vecmap[i].txq_map = (1 << rx_que->rxr.me); vm->vecmap[i].rxq_map = (1 << rx_que->rxr.me); vm->vecmap[i].rxitr_idx = 0; vm->vecmap[i].txitr_idx = 1; } /* Misc vector last - this is only for AdminQ messages */ vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id; vm->vecmap[i].vector_id = 0; vm->vecmap[i].txq_map = 0; vm->vecmap[i].rxq_map = 0; vm->vecmap[i].rxitr_idx = 0; vm->vecmap[i].txitr_idx = 0; iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_IRQ_MAP, (u8 *)vm, len); free(vm, M_IAVF); return (0); }