1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright (c) 2021, Intel Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the Intel Corporation nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /** 33 * @file iavf_vc_iflib.c 34 * @brief iflib-specific Virtchnl interface functions 35 * 36 * Contains functions implementing the virtchnl interface for communicating 37 * with the PF driver. This file contains definitions specific to the iflib 38 * driver implementation. 39 */ 40 41 #include "iavf_iflib.h" 42 #include "iavf_vc_common.h" 43 44 /** 45 * iavf_configure_queues - Configure queues 46 * @sc: device softc 47 * 48 * Request that the PF set up our queues. 49 * 50 * @returns zero on success, or an error code on failure. 51 */ 52 int 53 iavf_configure_queues(struct iavf_sc *sc) 54 { 55 device_t dev = sc->dev; 56 struct iavf_vsi *vsi = &sc->vsi; 57 if_softc_ctx_t scctx = iflib_get_softc_ctx(vsi->ctx); 58 struct iavf_tx_queue *tx_que = vsi->tx_queues; 59 struct iavf_rx_queue *rx_que = vsi->rx_queues; 60 struct tx_ring *txr; 61 struct rx_ring *rxr; 62 int len, pairs; 63 64 struct virtchnl_vsi_queue_config_info *vqci; 65 struct virtchnl_queue_pair_info *vqpi; 66 67 /* XXX: Linux PF driver wants matching ids in each tx/rx struct, so both TX/RX 68 * queues of a pair need to be configured */ 69 pairs = max(vsi->num_tx_queues, vsi->num_rx_queues); 70 len = sizeof(struct virtchnl_vsi_queue_config_info) + 71 (sizeof(struct virtchnl_queue_pair_info) * pairs); 72 vqci = malloc(len, M_IAVF, M_NOWAIT | M_ZERO); 73 if (!vqci) { 74 device_printf(dev, "%s: unable to allocate memory\n", __func__); 75 return (ENOMEM); 76 } 77 vqci->vsi_id = sc->vsi_res->vsi_id; 78 vqci->num_queue_pairs = pairs; 79 vqpi = vqci->qpair; 80 /* Size check is not needed here - HW max is 16 queue pairs, and we 81 * can fit info for 31 of them into the AQ buffer before it overflows. 82 */ 83 // TODO: the above is wrong now; X722 VFs can have 256 queues 84 for (int i = 0; i < pairs; i++, tx_que++, rx_que++, vqpi++) { 85 txr = &tx_que->txr; 86 rxr = &rx_que->rxr; 87 88 vqpi->txq.vsi_id = vqci->vsi_id; 89 vqpi->txq.queue_id = i; 90 vqpi->txq.ring_len = scctx->isc_ntxd[0]; 91 vqpi->txq.dma_ring_addr = txr->tx_paddr; 92 /* Enable Head writeback */ 93 if (!vsi->enable_head_writeback) { 94 vqpi->txq.headwb_enabled = 0; 95 vqpi->txq.dma_headwb_addr = 0; 96 } else { 97 vqpi->txq.headwb_enabled = 1; 98 vqpi->txq.dma_headwb_addr = txr->tx_paddr + 99 sizeof(struct iavf_tx_desc) * scctx->isc_ntxd[0]; 100 } 101 102 vqpi->rxq.vsi_id = vqci->vsi_id; 103 vqpi->rxq.queue_id = i; 104 vqpi->rxq.ring_len = scctx->isc_nrxd[0]; 105 vqpi->rxq.dma_ring_addr = rxr->rx_paddr; 106 vqpi->rxq.max_pkt_size = scctx->isc_max_frame_size; 107 vqpi->rxq.databuffer_size = rxr->mbuf_sz; 108 vqpi->rxq.splithdr_enabled = 0; 109 } 110 111 iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_VSI_QUEUES, 112 (u8 *)vqci, len); 113 free(vqci, M_IAVF); 114 115 return (0); 116 } 117 118 /** 119 * iavf_map_queues - Map queues to interrupt vectors 120 * @sc: device softc 121 * 122 * Request that the PF map queues to interrupt vectors. Misc causes, including 123 * admin queue, are always mapped to vector 0. 124 * 125 * @returns zero on success, or an error code on failure. 126 */ 127 int 128 iavf_map_queues(struct iavf_sc *sc) 129 { 130 struct virtchnl_irq_map_info *vm; 131 int i, q, len; 132 struct iavf_vsi *vsi = &sc->vsi; 133 struct iavf_rx_queue *rx_que = vsi->rx_queues; 134 if_softc_ctx_t scctx = vsi->shared; 135 device_t dev = sc->dev; 136 137 // XXX: What happens if we only get 1 MSI-X vector? 138 MPASS(scctx->isc_vectors > 1); 139 140 /* How many queue vectors, adminq uses one */ 141 // XXX: How do we know how many interrupt vectors we have? 142 q = scctx->isc_vectors - 1; 143 144 len = sizeof(struct virtchnl_irq_map_info) + 145 (scctx->isc_vectors * sizeof(struct virtchnl_vector_map)); 146 vm = malloc(len, M_IAVF, M_NOWAIT); 147 if (!vm) { 148 device_printf(dev, "%s: unable to allocate memory\n", __func__); 149 return (ENOMEM); 150 } 151 152 vm->num_vectors = scctx->isc_vectors; 153 /* Queue vectors first */ 154 for (i = 0; i < q; i++, rx_que++) { 155 vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id; 156 vm->vecmap[i].vector_id = i + 1; /* first is adminq */ 157 // TODO: Re-examine this 158 vm->vecmap[i].txq_map = (1 << rx_que->rxr.me); 159 vm->vecmap[i].rxq_map = (1 << rx_que->rxr.me); 160 vm->vecmap[i].rxitr_idx = 0; 161 vm->vecmap[i].txitr_idx = 1; 162 } 163 164 /* Misc vector last - this is only for AdminQ messages */ 165 vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id; 166 vm->vecmap[i].vector_id = 0; 167 vm->vecmap[i].txq_map = 0; 168 vm->vecmap[i].rxq_map = 0; 169 vm->vecmap[i].rxitr_idx = 0; 170 vm->vecmap[i].txitr_idx = 0; 171 172 iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_IRQ_MAP, 173 (u8 *)vm, len); 174 free(vm, M_IAVF); 175 176 return (0); 177 } 178