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 /*$FreeBSD$*/ 32 33 /** 34 * @file iavf_vc_iflib.c 35 * @brief iflib-specific Virtchnl interface functions 36 * 37 * Contains functions implementing the virtchnl interface for communicating 38 * with the PF driver. This file contains definitions specific to the iflib 39 * driver implementation. 40 */ 41 42 #include "iavf_iflib.h" 43 #include "iavf_vc_common.h" 44 45 /** 46 * iavf_configure_queues - Configure queues 47 * @sc: device softc 48 * 49 * Request that the PF set up our queues. 50 * 51 * @returns zero on success, or an error code on failure. 52 */ 53 int 54 iavf_configure_queues(struct iavf_sc *sc) 55 { 56 device_t dev = sc->dev; 57 struct iavf_vsi *vsi = &sc->vsi; 58 if_softc_ctx_t scctx = iflib_get_softc_ctx(vsi->ctx); 59 struct iavf_tx_queue *tx_que = vsi->tx_queues; 60 struct iavf_rx_queue *rx_que = vsi->rx_queues; 61 struct tx_ring *txr; 62 struct rx_ring *rxr; 63 int len, pairs; 64 65 struct virtchnl_vsi_queue_config_info *vqci; 66 struct virtchnl_queue_pair_info *vqpi; 67 68 /* XXX: Linux PF driver wants matching ids in each tx/rx struct, so both TX/RX 69 * queues of a pair need to be configured */ 70 pairs = max(vsi->num_tx_queues, vsi->num_rx_queues); 71 len = sizeof(struct virtchnl_vsi_queue_config_info) + 72 (sizeof(struct virtchnl_queue_pair_info) * pairs); 73 vqci = malloc(len, M_IAVF, M_NOWAIT | M_ZERO); 74 if (!vqci) { 75 device_printf(dev, "%s: unable to allocate memory\n", __func__); 76 return (ENOMEM); 77 } 78 vqci->vsi_id = sc->vsi_res->vsi_id; 79 vqci->num_queue_pairs = pairs; 80 vqpi = vqci->qpair; 81 /* Size check is not needed here - HW max is 16 queue pairs, and we 82 * can fit info for 31 of them into the AQ buffer before it overflows. 83 */ 84 // TODO: the above is wrong now; X722 VFs can have 256 queues 85 for (int i = 0; i < pairs; i++, tx_que++, rx_que++, vqpi++) { 86 txr = &tx_que->txr; 87 rxr = &rx_que->rxr; 88 89 vqpi->txq.vsi_id = vqci->vsi_id; 90 vqpi->txq.queue_id = i; 91 vqpi->txq.ring_len = scctx->isc_ntxd[0]; 92 vqpi->txq.dma_ring_addr = txr->tx_paddr; 93 /* Enable Head writeback */ 94 if (!vsi->enable_head_writeback) { 95 vqpi->txq.headwb_enabled = 0; 96 vqpi->txq.dma_headwb_addr = 0; 97 } else { 98 vqpi->txq.headwb_enabled = 1; 99 vqpi->txq.dma_headwb_addr = txr->tx_paddr + 100 sizeof(struct iavf_tx_desc) * scctx->isc_ntxd[0]; 101 } 102 103 vqpi->rxq.vsi_id = vqci->vsi_id; 104 vqpi->rxq.queue_id = i; 105 vqpi->rxq.ring_len = scctx->isc_nrxd[0]; 106 vqpi->rxq.dma_ring_addr = rxr->rx_paddr; 107 vqpi->rxq.max_pkt_size = scctx->isc_max_frame_size; 108 vqpi->rxq.databuffer_size = rxr->mbuf_sz; 109 vqpi->rxq.splithdr_enabled = 0; 110 } 111 112 iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_VSI_QUEUES, 113 (u8 *)vqci, len); 114 free(vqci, M_IAVF); 115 116 return (0); 117 } 118 119 /** 120 * iavf_map_queues - Map queues to interrupt vectors 121 * @sc: device softc 122 * 123 * Request that the PF map queues to interrupt vectors. Misc causes, including 124 * admin queue, are always mapped to vector 0. 125 * 126 * @returns zero on success, or an error code on failure. 127 */ 128 int 129 iavf_map_queues(struct iavf_sc *sc) 130 { 131 struct virtchnl_irq_map_info *vm; 132 int i, q, len; 133 struct iavf_vsi *vsi = &sc->vsi; 134 struct iavf_rx_queue *rx_que = vsi->rx_queues; 135 if_softc_ctx_t scctx = vsi->shared; 136 device_t dev = sc->dev; 137 138 // XXX: What happens if we only get 1 MSI-X vector? 139 MPASS(scctx->isc_vectors > 1); 140 141 /* How many queue vectors, adminq uses one */ 142 // XXX: How do we know how many interrupt vectors we have? 143 q = scctx->isc_vectors - 1; 144 145 len = sizeof(struct virtchnl_irq_map_info) + 146 (scctx->isc_vectors * sizeof(struct virtchnl_vector_map)); 147 vm = malloc(len, M_IAVF, M_NOWAIT); 148 if (!vm) { 149 device_printf(dev, "%s: unable to allocate memory\n", __func__); 150 return (ENOMEM); 151 } 152 153 vm->num_vectors = scctx->isc_vectors; 154 /* Queue vectors first */ 155 for (i = 0; i < q; i++, rx_que++) { 156 vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id; 157 vm->vecmap[i].vector_id = i + 1; /* first is adminq */ 158 // TODO: Re-examine this 159 vm->vecmap[i].txq_map = (1 << rx_que->rxr.me); 160 vm->vecmap[i].rxq_map = (1 << rx_que->rxr.me); 161 vm->vecmap[i].rxitr_idx = 0; 162 vm->vecmap[i].txitr_idx = 1; 163 } 164 165 /* Misc vector last - this is only for AdminQ messages */ 166 vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id; 167 vm->vecmap[i].vector_id = 0; 168 vm->vecmap[i].txq_map = 0; 169 vm->vecmap[i].rxq_map = 0; 170 vm->vecmap[i].rxitr_idx = 0; 171 vm->vecmap[i].txitr_idx = 0; 172 173 iavf_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_IRQ_MAP, 174 (u8 *)vm, len); 175 free(vm, M_IAVF); 176 177 return (0); 178 } 179