1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright (c) 2020, 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 ice_iflib_txrx.c 35 * @brief iflib Tx/Rx hotpath 36 * 37 * Main location for the iflib Tx/Rx hotpath implementation. 38 * 39 * Contains the implementation for the iflib function callbacks and the 40 * if_txrx ops structure. 41 */ 42 43 #include "ice_iflib.h" 44 45 /* Tx/Rx hotpath utility functions */ 46 #include "ice_common_txrx.h" 47 48 /* 49 * iflib txrx method declarations 50 */ 51 static int ice_ift_txd_encap(void *arg, if_pkt_info_t pi); 52 static int ice_ift_rxd_pkt_get(void *arg, if_rxd_info_t ri); 53 static void ice_ift_txd_flush(void *arg, uint16_t txqid, qidx_t pidx); 54 static int ice_ift_txd_credits_update(void *arg, uint16_t txqid, bool clear); 55 static int ice_ift_rxd_available(void *arg, uint16_t rxqid, qidx_t pidx, qidx_t budget); 56 static void ice_ift_rxd_flush(void *arg, uint16_t rxqid, uint8_t flidx, qidx_t pidx); 57 static void ice_ift_rxd_refill(void *arg, if_rxd_update_t iru); 58 59 /* Macro to help extract the NIC mode flexible Rx descriptor fields from the 60 * advanced 32byte Rx descriptors. 61 */ 62 #define RX_FLEX_NIC(desc, field) \ 63 (((struct ice_32b_rx_flex_desc_nic *)desc)->field) 64 65 /** 66 * @var ice_txrx 67 * @brief Tx/Rx operations for the iflib stack 68 * 69 * Structure defining the Tx and Rx related operations that iflib can request 70 * the driver to perform. These are the main entry points for the hot path of 71 * the transmit and receive paths in the iflib driver. 72 */ 73 struct if_txrx ice_txrx = { 74 .ift_txd_encap = ice_ift_txd_encap, 75 .ift_txd_flush = ice_ift_txd_flush, 76 .ift_txd_credits_update = ice_ift_txd_credits_update, 77 .ift_rxd_available = ice_ift_rxd_available, 78 .ift_rxd_pkt_get = ice_ift_rxd_pkt_get, 79 .ift_rxd_refill = ice_ift_rxd_refill, 80 .ift_rxd_flush = ice_ift_rxd_flush, 81 }; 82 83 /** 84 * ice_ift_txd_encap - prepare Tx descriptors for a packet 85 * @arg: the iflib softc structure pointer 86 * @pi: packet info 87 * 88 * Prepares and encapsulates the given packet into into Tx descriptors, in 89 * preparation for sending to the transmit engine. Sets the necessary context 90 * descriptors for TSO and other offloads, and prepares the last descriptor 91 * for the writeback status. 92 * 93 * Return 0 on success, non-zero error code on failure. 94 */ 95 static int 96 ice_ift_txd_encap(void *arg, if_pkt_info_t pi) 97 { 98 struct ice_softc *sc = (struct ice_softc *)arg; 99 struct ice_tx_queue *txq = &sc->pf_vsi.tx_queues[pi->ipi_qsidx]; 100 int nsegs = pi->ipi_nsegs; 101 bus_dma_segment_t *segs = pi->ipi_segs; 102 struct ice_tx_desc *txd = NULL; 103 int i, j, mask, pidx_last; 104 u32 cmd, off; 105 106 cmd = off = 0; 107 i = pi->ipi_pidx; 108 109 /* Set up the TSO/CSUM offload */ 110 if (pi->ipi_csum_flags & ICE_CSUM_OFFLOAD) { 111 /* Set up the TSO context descriptor if required */ 112 if (pi->ipi_csum_flags & CSUM_TSO) { 113 if (ice_tso_detect_sparse(pi)) 114 return (EFBIG); 115 i = ice_tso_setup(txq, pi); 116 } 117 ice_tx_setup_offload(txq, pi, &cmd, &off); 118 } 119 if (pi->ipi_mflags & M_VLANTAG) 120 cmd |= ICE_TX_DESC_CMD_IL2TAG1; 121 122 mask = txq->desc_count - 1; 123 for (j = 0; j < nsegs; j++) { 124 bus_size_t seglen; 125 126 txd = &txq->tx_base[i]; 127 seglen = segs[j].ds_len; 128 129 txd->buf_addr = htole64(segs[j].ds_addr); 130 txd->cmd_type_offset_bsz = 131 htole64(ICE_TX_DESC_DTYPE_DATA 132 | ((u64)cmd << ICE_TXD_QW1_CMD_S) 133 | ((u64)off << ICE_TXD_QW1_OFFSET_S) 134 | ((u64)seglen << ICE_TXD_QW1_TX_BUF_SZ_S) 135 | ((u64)htole16(pi->ipi_vtag) << ICE_TXD_QW1_L2TAG1_S)); 136 137 txq->stats.tx_bytes += seglen; 138 pidx_last = i; 139 i = (i+1) & mask; 140 } 141 142 /* Set the last descriptor for report */ 143 #define ICE_TXD_CMD (ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS) 144 txd->cmd_type_offset_bsz |= 145 htole64(((u64)ICE_TXD_CMD << ICE_TXD_QW1_CMD_S)); 146 147 /* Add to report status array */ 148 txq->tx_rsq[txq->tx_rs_pidx] = pidx_last; 149 txq->tx_rs_pidx = (txq->tx_rs_pidx+1) & mask; 150 MPASS(txq->tx_rs_pidx != txq->tx_rs_cidx); 151 152 pi->ipi_new_pidx = i; 153 154 ++txq->stats.tx_packets; 155 return (0); 156 } 157 158 /** 159 * ice_ift_txd_flush - Flush Tx descriptors to hardware 160 * @arg: device specific softc pointer 161 * @txqid: the Tx queue to flush 162 * @pidx: descriptor index to advance tail to 163 * 164 * Advance the Transmit Descriptor Tail (TDT). This indicates to hardware that 165 * frames are available for transmit. 166 */ 167 static void 168 ice_ift_txd_flush(void *arg, uint16_t txqid, qidx_t pidx) 169 { 170 struct ice_softc *sc = (struct ice_softc *)arg; 171 struct ice_tx_queue *txq = &sc->pf_vsi.tx_queues[txqid]; 172 struct ice_hw *hw = &sc->hw; 173 174 wr32(hw, txq->tail, pidx); 175 } 176 177 /** 178 * ice_ift_txd_credits_update - cleanup Tx descriptors 179 * @arg: device private softc 180 * @txqid: the Tx queue to update 181 * @clear: if false, only report, do not actually clean 182 * 183 * If clear is false, iflib is asking if we *could* clean up any Tx 184 * descriptors. 185 * 186 * If clear is true, iflib is requesting to cleanup and reclaim used Tx 187 * descriptors. 188 */ 189 static int 190 ice_ift_txd_credits_update(void *arg, uint16_t txqid, bool clear) 191 { 192 struct ice_softc *sc = (struct ice_softc *)arg; 193 struct ice_tx_queue *txq = &sc->pf_vsi.tx_queues[txqid]; 194 195 qidx_t processed = 0; 196 qidx_t cur, prev, ntxd, rs_cidx; 197 int32_t delta; 198 bool is_done; 199 200 rs_cidx = txq->tx_rs_cidx; 201 if (rs_cidx == txq->tx_rs_pidx) 202 return (0); 203 cur = txq->tx_rsq[rs_cidx]; 204 MPASS(cur != QIDX_INVALID); 205 is_done = ice_is_tx_desc_done(&txq->tx_base[cur]); 206 207 if (!is_done) 208 return (0); 209 else if (clear == false) 210 return (1); 211 212 prev = txq->tx_cidx_processed; 213 ntxd = txq->desc_count; 214 do { 215 MPASS(prev != cur); 216 delta = (int32_t)cur - (int32_t)prev; 217 if (delta < 0) 218 delta += ntxd; 219 MPASS(delta > 0); 220 processed += delta; 221 prev = cur; 222 rs_cidx = (rs_cidx + 1) & (ntxd-1); 223 if (rs_cidx == txq->tx_rs_pidx) 224 break; 225 cur = txq->tx_rsq[rs_cidx]; 226 MPASS(cur != QIDX_INVALID); 227 is_done = ice_is_tx_desc_done(&txq->tx_base[cur]); 228 } while (is_done); 229 230 txq->tx_rs_cidx = rs_cidx; 231 txq->tx_cidx_processed = prev; 232 233 return (processed); 234 } 235 236 /** 237 * ice_ift_rxd_available - Return number of available Rx packets 238 * @arg: device private softc 239 * @rxqid: the Rx queue id 240 * @pidx: descriptor start point 241 * @budget: maximum Rx budget 242 * 243 * Determines how many Rx packets are available on the queue, up to a maximum 244 * of the given budget. 245 */ 246 static int 247 ice_ift_rxd_available(void *arg, uint16_t rxqid, qidx_t pidx, qidx_t budget) 248 { 249 struct ice_softc *sc = (struct ice_softc *)arg; 250 struct ice_rx_queue *rxq = &sc->pf_vsi.rx_queues[rxqid]; 251 union ice_32b_rx_flex_desc *rxd; 252 uint16_t status0; 253 int cnt, i, nrxd; 254 255 nrxd = rxq->desc_count; 256 257 for (cnt = 0, i = pidx; cnt < nrxd - 1 && cnt < budget;) { 258 rxd = &rxq->rx_base[i]; 259 status0 = le16toh(rxd->wb.status_error0); 260 261 if ((status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S)) == 0) 262 break; 263 if (++i == nrxd) 264 i = 0; 265 if (status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S)) 266 cnt++; 267 } 268 269 return (cnt); 270 } 271 272 /** 273 * ice_ift_rxd_pkt_get - Called by iflib to send data to upper layer 274 * @arg: device specific softc 275 * @ri: receive packet info 276 * 277 * This function is called by iflib, and executes in ithread context. It is 278 * called by iflib to obtain data which has been DMA'ed into host memory. 279 * Returns zero on success, and an error code on failure. 280 */ 281 static int 282 ice_ift_rxd_pkt_get(void *arg, if_rxd_info_t ri) 283 { 284 struct ice_softc *sc = (struct ice_softc *)arg; 285 struct ice_rx_queue *rxq = &sc->pf_vsi.rx_queues[ri->iri_qsidx]; 286 union ice_32b_rx_flex_desc *cur; 287 u16 status0, plen, vtag, ptype; 288 bool eop; 289 size_t cidx; 290 int i; 291 292 cidx = ri->iri_cidx; 293 i = 0; 294 do { 295 /* 5 descriptor receive limit */ 296 MPASS(i < ICE_MAX_RX_SEGS); 297 298 cur = &rxq->rx_base[cidx]; 299 status0 = le16toh(cur->wb.status_error0); 300 plen = le16toh(cur->wb.pkt_len) & 301 ICE_RX_FLX_DESC_PKT_LEN_M; 302 ptype = le16toh(cur->wb.ptype_flex_flags0) & 303 ICE_RX_FLEX_DESC_PTYPE_M; 304 305 /* we should never be called without a valid descriptor */ 306 MPASS((status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S)) != 0); 307 308 ri->iri_len += plen; 309 310 cur->wb.status_error0 = 0; 311 eop = (status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S)); 312 if (status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_L2TAG1P_S)) 313 vtag = le16toh(cur->wb.l2tag1); 314 else 315 vtag = 0; 316 317 /* 318 * Make sure packets with bad L2 values are discarded. 319 * NOTE: Only the EOP descriptor has valid error results. 320 */ 321 if (eop && (status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_RXE_S))) { 322 rxq->stats.desc_errs++; 323 return (EBADMSG); 324 } 325 ri->iri_frags[i].irf_flid = 0; 326 ri->iri_frags[i].irf_idx = cidx; 327 ri->iri_frags[i].irf_len = plen; 328 if (++cidx == rxq->desc_count) 329 cidx = 0; 330 i++; 331 } while (!eop); 332 333 /* capture soft statistics for this Rx queue */ 334 rxq->stats.rx_packets++; 335 rxq->stats.rx_bytes += ri->iri_len; 336 337 if ((iflib_get_ifp(sc->ctx)->if_capenable & IFCAP_RXCSUM) != 0) 338 ice_rx_checksum(rxq, &ri->iri_csum_flags, 339 &ri->iri_csum_data, status0, ptype); 340 ri->iri_flowid = le32toh(RX_FLEX_NIC(&cur->wb, rss_hash)); 341 ri->iri_rsstype = ice_ptype_to_hash(ptype); 342 ri->iri_vtag = vtag; 343 ri->iri_nfrags = i; 344 if (vtag) 345 ri->iri_flags |= M_VLANTAG; 346 return (0); 347 } 348 349 /** 350 * ice_ift_rxd_refill - Prepare Rx descriptors for re-use by hardware 351 * @arg: device specific softc structure 352 * @iru: the Rx descriptor update structure 353 * 354 * Update the Rx descriptor indices for a given queue, assigning new physical 355 * addresses to the descriptors, preparing them for re-use by the hardware. 356 */ 357 static void 358 ice_ift_rxd_refill(void *arg, if_rxd_update_t iru) 359 { 360 struct ice_softc *sc = (struct ice_softc *)arg; 361 struct ice_rx_queue *rxq; 362 uint32_t next_pidx; 363 int i; 364 uint64_t *paddrs; 365 uint32_t pidx; 366 uint16_t qsidx, count; 367 368 paddrs = iru->iru_paddrs; 369 pidx = iru->iru_pidx; 370 qsidx = iru->iru_qsidx; 371 count = iru->iru_count; 372 373 rxq = &(sc->pf_vsi.rx_queues[qsidx]); 374 375 for (i = 0, next_pidx = pidx; i < count; i++) { 376 rxq->rx_base[next_pidx].read.pkt_addr = htole64(paddrs[i]); 377 if (++next_pidx == (uint32_t)rxq->desc_count) 378 next_pidx = 0; 379 } 380 } 381 382 /** 383 * ice_ift_rxd_flush - Flush Rx descriptors to hardware 384 * @arg: device specific softc pointer 385 * @rxqid: the Rx queue to flush 386 * @flidx: unused parameter 387 * @pidx: descriptor index to advance tail to 388 * 389 * Advance the Receive Descriptor Tail (RDT). This indicates to hardware that 390 * software is done with the descriptor and it can be recycled. 391 */ 392 static void 393 ice_ift_rxd_flush(void *arg, uint16_t rxqid, uint8_t flidx __unused, 394 qidx_t pidx) 395 { 396 struct ice_softc *sc = (struct ice_softc *)arg; 397 struct ice_rx_queue *rxq = &sc->pf_vsi.rx_queues[rxqid]; 398 struct ice_hw *hw = &sc->hw; 399 400 wr32(hw, rxq->tail, pidx); 401 } 402