144c0947bSAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause 2638bddc9SAndrew Rybchenko * 3a0147be5SAndrew Rybchenko * Copyright(c) 2019-2020 Xilinx, Inc. 4a0147be5SAndrew Rybchenko * Copyright(c) 2016-2019 Solarflare Communications Inc. 5638bddc9SAndrew Rybchenko * 6638bddc9SAndrew Rybchenko * This software was jointly developed between OKTET Labs (under contract 7638bddc9SAndrew Rybchenko * for Solarflare) and Solarflare Communications, Inc. 8638bddc9SAndrew Rybchenko */ 9638bddc9SAndrew Rybchenko 10638bddc9SAndrew Rybchenko /* EF10 native datapath implementation */ 11638bddc9SAndrew Rybchenko 12638bddc9SAndrew Rybchenko #include <stdbool.h> 13638bddc9SAndrew Rybchenko 14638bddc9SAndrew Rybchenko #include <rte_byteorder.h> 15638bddc9SAndrew Rybchenko #include <rte_mbuf_ptype.h> 16638bddc9SAndrew Rybchenko #include <rte_mbuf.h> 17638bddc9SAndrew Rybchenko #include <rte_io.h> 18638bddc9SAndrew Rybchenko 19638bddc9SAndrew Rybchenko #include "efx.h" 20638bddc9SAndrew Rybchenko #include "efx_types.h" 21638bddc9SAndrew Rybchenko #include "efx_regs.h" 22638bddc9SAndrew Rybchenko #include "efx_regs_ef10.h" 23638bddc9SAndrew Rybchenko 241b0236e2SAndrew Rybchenko #include "sfc_debug.h" 25638bddc9SAndrew Rybchenko #include "sfc_tweak.h" 26638bddc9SAndrew Rybchenko #include "sfc_dp_rx.h" 27638bddc9SAndrew Rybchenko #include "sfc_kvargs.h" 28638bddc9SAndrew Rybchenko #include "sfc_ef10.h" 297ee7e57cSAndrew Rybchenko 307ee7e57cSAndrew Rybchenko #define SFC_EF10_RX_EV_ENCAP_SUPPORT 1 31c121f008SAndrew Rybchenko #include "sfc_ef10_rx_ev.h" 32638bddc9SAndrew Rybchenko 33638bddc9SAndrew Rybchenko #define sfc_ef10_rx_err(dpq, ...) \ 34638bddc9SAndrew Rybchenko SFC_DP_LOG(SFC_KVARG_DATAPATH_EF10, ERR, dpq, __VA_ARGS__) 35638bddc9SAndrew Rybchenko 36e7fbf6f5SAndrew Rybchenko #define sfc_ef10_rx_info(dpq, ...) \ 37e7fbf6f5SAndrew Rybchenko SFC_DP_LOG(SFC_KVARG_DATAPATH_EF10, INFO, dpq, __VA_ARGS__) 38e7fbf6f5SAndrew Rybchenko 39638bddc9SAndrew Rybchenko /** 40638bddc9SAndrew Rybchenko * Maximum number of descriptors/buffers in the Rx ring. 41638bddc9SAndrew Rybchenko * It should guarantee that corresponding event queue never overfill. 42638bddc9SAndrew Rybchenko * EF10 native datapath uses event queue of the same size as Rx queue. 43638bddc9SAndrew Rybchenko * Maximum number of events on datapath can be estimated as number of 44638bddc9SAndrew Rybchenko * Rx queue entries (one event per Rx buffer in the worst case) plus 45638bddc9SAndrew Rybchenko * Rx error and flush events. 46638bddc9SAndrew Rybchenko */ 47638bddc9SAndrew Rybchenko #define SFC_EF10_RXQ_LIMIT(_ndesc) \ 48638bddc9SAndrew Rybchenko ((_ndesc) - 1 /* head must not step on tail */ - \ 49638bddc9SAndrew Rybchenko (SFC_EF10_EV_PER_CACHE_LINE - 1) /* max unused EvQ entries */ - \ 50638bddc9SAndrew Rybchenko 1 /* Rx error */ - 1 /* flush */) 51638bddc9SAndrew Rybchenko 52638bddc9SAndrew Rybchenko struct sfc_ef10_rx_sw_desc { 53638bddc9SAndrew Rybchenko struct rte_mbuf *mbuf; 54638bddc9SAndrew Rybchenko }; 55638bddc9SAndrew Rybchenko 56638bddc9SAndrew Rybchenko struct sfc_ef10_rxq { 57638bddc9SAndrew Rybchenko /* Used on data path */ 58638bddc9SAndrew Rybchenko unsigned int flags; 59638bddc9SAndrew Rybchenko #define SFC_EF10_RXQ_STARTED 0x1 60638bddc9SAndrew Rybchenko #define SFC_EF10_RXQ_NOT_RUNNING 0x2 61638bddc9SAndrew Rybchenko #define SFC_EF10_RXQ_EXCEPTION 0x4 62638bddc9SAndrew Rybchenko #define SFC_EF10_RXQ_RSS_HASH 0x8 631245e3faSGeorgiy Levashov #define SFC_EF10_RXQ_FLAG_INTR_EN 0x10 64638bddc9SAndrew Rybchenko unsigned int ptr_mask; 653be22684SAndrew Rybchenko unsigned int pending; 66638bddc9SAndrew Rybchenko unsigned int completed; 67638bddc9SAndrew Rybchenko unsigned int evq_read_ptr; 681245e3faSGeorgiy Levashov unsigned int evq_read_ptr_primed; 69638bddc9SAndrew Rybchenko efx_qword_t *evq_hw_ring; 70638bddc9SAndrew Rybchenko struct sfc_ef10_rx_sw_desc *sw_ring; 71638bddc9SAndrew Rybchenko uint64_t rearm_data; 7252e10cb0SAndrew Rybchenko struct rte_mbuf *scatter_pkt; 731245e3faSGeorgiy Levashov volatile void *evq_prime; 74638bddc9SAndrew Rybchenko uint16_t prefix_size; 75638bddc9SAndrew Rybchenko 76638bddc9SAndrew Rybchenko /* Used on refill */ 77638bddc9SAndrew Rybchenko uint16_t buf_size; 78638bddc9SAndrew Rybchenko unsigned int added; 79e5595ee2SAndrew Rybchenko unsigned int max_fill_level; 80638bddc9SAndrew Rybchenko unsigned int refill_threshold; 81638bddc9SAndrew Rybchenko struct rte_mempool *refill_mb_pool; 82638bddc9SAndrew Rybchenko efx_qword_t *rxq_hw_ring; 83638bddc9SAndrew Rybchenko volatile void *doorbell; 84638bddc9SAndrew Rybchenko 85638bddc9SAndrew Rybchenko /* Datapath receive queue anchor */ 86638bddc9SAndrew Rybchenko struct sfc_dp_rxq dp; 87638bddc9SAndrew Rybchenko }; 88638bddc9SAndrew Rybchenko 89638bddc9SAndrew Rybchenko static inline struct sfc_ef10_rxq * 90638bddc9SAndrew Rybchenko sfc_ef10_rxq_by_dp_rxq(struct sfc_dp_rxq *dp_rxq) 91638bddc9SAndrew Rybchenko { 92638bddc9SAndrew Rybchenko return container_of(dp_rxq, struct sfc_ef10_rxq, dp); 93638bddc9SAndrew Rybchenko } 94638bddc9SAndrew Rybchenko 95638bddc9SAndrew Rybchenko static void 961245e3faSGeorgiy Levashov sfc_ef10_rx_qprime(struct sfc_ef10_rxq *rxq) 971245e3faSGeorgiy Levashov { 981245e3faSGeorgiy Levashov sfc_ef10_ev_qprime(rxq->evq_prime, rxq->evq_read_ptr, rxq->ptr_mask); 991245e3faSGeorgiy Levashov rxq->evq_read_ptr_primed = rxq->evq_read_ptr; 1001245e3faSGeorgiy Levashov } 1011245e3faSGeorgiy Levashov 1021245e3faSGeorgiy Levashov static void 103638bddc9SAndrew Rybchenko sfc_ef10_rx_qrefill(struct sfc_ef10_rxq *rxq) 104638bddc9SAndrew Rybchenko { 105638bddc9SAndrew Rybchenko const unsigned int ptr_mask = rxq->ptr_mask; 106638bddc9SAndrew Rybchenko const uint32_t buf_size = rxq->buf_size; 107638bddc9SAndrew Rybchenko unsigned int free_space; 108638bddc9SAndrew Rybchenko unsigned int bulks; 109638bddc9SAndrew Rybchenko void *objs[SFC_RX_REFILL_BULK]; 110638bddc9SAndrew Rybchenko unsigned int added = rxq->added; 111638bddc9SAndrew Rybchenko 112a2443fdfSAndrew Rybchenko RTE_BUILD_BUG_ON(SFC_RX_REFILL_BULK % SFC_EF10_RX_WPTR_ALIGN != 0); 113a2443fdfSAndrew Rybchenko 114e5595ee2SAndrew Rybchenko free_space = rxq->max_fill_level - (added - rxq->completed); 115638bddc9SAndrew Rybchenko 116638bddc9SAndrew Rybchenko if (free_space < rxq->refill_threshold) 117638bddc9SAndrew Rybchenko return; 118638bddc9SAndrew Rybchenko 119638bddc9SAndrew Rybchenko bulks = free_space / RTE_DIM(objs); 120638bddc9SAndrew Rybchenko /* refill_threshold guarantees that bulks is positive */ 121638bddc9SAndrew Rybchenko SFC_ASSERT(bulks > 0); 122638bddc9SAndrew Rybchenko 123638bddc9SAndrew Rybchenko do { 124638bddc9SAndrew Rybchenko unsigned int id; 125638bddc9SAndrew Rybchenko unsigned int i; 126638bddc9SAndrew Rybchenko 127638bddc9SAndrew Rybchenko if (unlikely(rte_mempool_get_bulk(rxq->refill_mb_pool, objs, 128638bddc9SAndrew Rybchenko RTE_DIM(objs)) < 0)) { 129638bddc9SAndrew Rybchenko struct rte_eth_dev_data *dev_data = 130638bddc9SAndrew Rybchenko rte_eth_devices[rxq->dp.dpq.port_id].data; 131638bddc9SAndrew Rybchenko 132638bddc9SAndrew Rybchenko /* 133638bddc9SAndrew Rybchenko * It is hardly a safe way to increment counter 134638bddc9SAndrew Rybchenko * from different contexts, but all PMDs do it. 135638bddc9SAndrew Rybchenko */ 136638bddc9SAndrew Rybchenko dev_data->rx_mbuf_alloc_failed += RTE_DIM(objs); 137638bddc9SAndrew Rybchenko /* Return if we have posted nothing yet */ 138638bddc9SAndrew Rybchenko if (added == rxq->added) 139638bddc9SAndrew Rybchenko return; 140638bddc9SAndrew Rybchenko /* Push posted */ 141638bddc9SAndrew Rybchenko break; 142638bddc9SAndrew Rybchenko } 143638bddc9SAndrew Rybchenko 144638bddc9SAndrew Rybchenko for (i = 0, id = added & ptr_mask; 145638bddc9SAndrew Rybchenko i < RTE_DIM(objs); 146638bddc9SAndrew Rybchenko ++i, ++id) { 147638bddc9SAndrew Rybchenko struct rte_mbuf *m = objs[i]; 148638bddc9SAndrew Rybchenko struct sfc_ef10_rx_sw_desc *rxd; 149df6e0a06SSantosh Shukla rte_iova_t phys_addr; 150638bddc9SAndrew Rybchenko 151*3a35c1c0SMorten Brørup __rte_mbuf_raw_sanity_check(m); 152f3a5fa85SAndrew Rybchenko 153638bddc9SAndrew Rybchenko SFC_ASSERT((id & ~ptr_mask) == 0); 154638bddc9SAndrew Rybchenko rxd = &rxq->sw_ring[id]; 155638bddc9SAndrew Rybchenko rxd->mbuf = m; 156638bddc9SAndrew Rybchenko 157638bddc9SAndrew Rybchenko /* 158638bddc9SAndrew Rybchenko * Avoid writing to mbuf. It is cheaper to do it 159638bddc9SAndrew Rybchenko * when we receive packet and fill in nearby 160638bddc9SAndrew Rybchenko * structure members. 161638bddc9SAndrew Rybchenko */ 162638bddc9SAndrew Rybchenko 163bfa9a8a4SThomas Monjalon phys_addr = rte_mbuf_data_iova_default(m); 164638bddc9SAndrew Rybchenko EFX_POPULATE_QWORD_2(rxq->rxq_hw_ring[id], 165638bddc9SAndrew Rybchenko ESF_DZ_RX_KER_BYTE_CNT, buf_size, 166638bddc9SAndrew Rybchenko ESF_DZ_RX_KER_BUF_ADDR, phys_addr); 167638bddc9SAndrew Rybchenko } 168638bddc9SAndrew Rybchenko 169638bddc9SAndrew Rybchenko added += RTE_DIM(objs); 170638bddc9SAndrew Rybchenko } while (--bulks > 0); 171638bddc9SAndrew Rybchenko 172638bddc9SAndrew Rybchenko SFC_ASSERT(rxq->added != added); 173638bddc9SAndrew Rybchenko rxq->added = added; 174a2443fdfSAndrew Rybchenko sfc_ef10_rx_qpush(rxq->doorbell, added, ptr_mask); 175638bddc9SAndrew Rybchenko } 176638bddc9SAndrew Rybchenko 177638bddc9SAndrew Rybchenko static void 178638bddc9SAndrew Rybchenko sfc_ef10_rx_prefetch_next(struct sfc_ef10_rxq *rxq, unsigned int next_id) 179638bddc9SAndrew Rybchenko { 180638bddc9SAndrew Rybchenko struct rte_mbuf *next_mbuf; 181638bddc9SAndrew Rybchenko 182638bddc9SAndrew Rybchenko /* Prefetch next bunch of software descriptors */ 183638bddc9SAndrew Rybchenko if ((next_id % (RTE_CACHE_LINE_SIZE / sizeof(rxq->sw_ring[0]))) == 0) 184638bddc9SAndrew Rybchenko rte_prefetch0(&rxq->sw_ring[next_id]); 185638bddc9SAndrew Rybchenko 186638bddc9SAndrew Rybchenko /* 187638bddc9SAndrew Rybchenko * It looks strange to prefetch depending on previous prefetch 188638bddc9SAndrew Rybchenko * data, but measurements show that it is really efficient and 189638bddc9SAndrew Rybchenko * increases packet rate. 190638bddc9SAndrew Rybchenko */ 191638bddc9SAndrew Rybchenko next_mbuf = rxq->sw_ring[next_id].mbuf; 192638bddc9SAndrew Rybchenko if (likely(next_mbuf != NULL)) { 193638bddc9SAndrew Rybchenko /* Prefetch the next mbuf structure */ 194638bddc9SAndrew Rybchenko rte_mbuf_prefetch_part1(next_mbuf); 195638bddc9SAndrew Rybchenko 196638bddc9SAndrew Rybchenko /* Prefetch pseudo header of the next packet */ 197638bddc9SAndrew Rybchenko /* data_off is not filled in yet */ 198638bddc9SAndrew Rybchenko /* Yes, data could be not ready yet, but we hope */ 199638bddc9SAndrew Rybchenko rte_prefetch0((uint8_t *)next_mbuf->buf_addr + 200638bddc9SAndrew Rybchenko RTE_PKTMBUF_HEADROOM); 201638bddc9SAndrew Rybchenko } 202638bddc9SAndrew Rybchenko } 203638bddc9SAndrew Rybchenko 20484b63b5cSAndrew Rybchenko static struct rte_mbuf ** 2053be22684SAndrew Rybchenko sfc_ef10_rx_pending(struct sfc_ef10_rxq *rxq, struct rte_mbuf **rx_pkts, 206638bddc9SAndrew Rybchenko uint16_t nb_pkts) 207638bddc9SAndrew Rybchenko { 2083be22684SAndrew Rybchenko uint16_t n_rx_pkts = RTE_MIN(nb_pkts, rxq->pending - rxq->completed); 2093ac6ddd4SAndrew Rybchenko 21052e10cb0SAndrew Rybchenko SFC_ASSERT(rxq->pending == rxq->completed || rxq->scatter_pkt == NULL); 21152e10cb0SAndrew Rybchenko 2123ac6ddd4SAndrew Rybchenko if (n_rx_pkts != 0) { 213638bddc9SAndrew Rybchenko unsigned int completed = rxq->completed; 214638bddc9SAndrew Rybchenko 215638bddc9SAndrew Rybchenko rxq->completed = completed + n_rx_pkts; 216638bddc9SAndrew Rybchenko 2173ac6ddd4SAndrew Rybchenko do { 2183ac6ddd4SAndrew Rybchenko *rx_pkts++ = 2193ac6ddd4SAndrew Rybchenko rxq->sw_ring[completed++ & rxq->ptr_mask].mbuf; 2203ac6ddd4SAndrew Rybchenko } while (completed != rxq->completed); 2213ac6ddd4SAndrew Rybchenko } 222638bddc9SAndrew Rybchenko 22384b63b5cSAndrew Rybchenko return rx_pkts; 224638bddc9SAndrew Rybchenko } 225638bddc9SAndrew Rybchenko 226c6845644SAndrew Rybchenko /* 227c6845644SAndrew Rybchenko * Below Rx pseudo-header (aka Rx prefix) accessors rely on the 228c6845644SAndrew Rybchenko * following fields layout. 229c6845644SAndrew Rybchenko */ 230c6845644SAndrew Rybchenko static const efx_rx_prefix_layout_t sfc_ef10_rx_prefix_layout = { 231c6845644SAndrew Rybchenko .erpl_fields = { 232c6845644SAndrew Rybchenko [EFX_RX_PREFIX_FIELD_RSS_HASH] = 233c6845644SAndrew Rybchenko { 0, sizeof(uint32_t) * CHAR_BIT, B_FALSE }, 234c6845644SAndrew Rybchenko [EFX_RX_PREFIX_FIELD_LENGTH] = 235c6845644SAndrew Rybchenko { 8 * CHAR_BIT, sizeof(uint16_t) * CHAR_BIT, B_FALSE }, 236c6845644SAndrew Rybchenko } 237c6845644SAndrew Rybchenko }; 238638bddc9SAndrew Rybchenko static uint16_t 239638bddc9SAndrew Rybchenko sfc_ef10_rx_pseudo_hdr_get_len(const uint8_t *pseudo_hdr) 240638bddc9SAndrew Rybchenko { 241638bddc9SAndrew Rybchenko return rte_le_to_cpu_16(*(const uint16_t *)&pseudo_hdr[8]); 242638bddc9SAndrew Rybchenko } 243638bddc9SAndrew Rybchenko 244638bddc9SAndrew Rybchenko static uint32_t 245638bddc9SAndrew Rybchenko sfc_ef10_rx_pseudo_hdr_get_hash(const uint8_t *pseudo_hdr) 246638bddc9SAndrew Rybchenko { 247638bddc9SAndrew Rybchenko return rte_le_to_cpu_32(*(const uint32_t *)pseudo_hdr); 248638bddc9SAndrew Rybchenko } 249638bddc9SAndrew Rybchenko 25084b63b5cSAndrew Rybchenko static struct rte_mbuf ** 251638bddc9SAndrew Rybchenko sfc_ef10_rx_process_event(struct sfc_ef10_rxq *rxq, efx_qword_t rx_ev, 25284b63b5cSAndrew Rybchenko struct rte_mbuf **rx_pkts, 25384b63b5cSAndrew Rybchenko struct rte_mbuf ** const rx_pkts_end) 254638bddc9SAndrew Rybchenko { 255638bddc9SAndrew Rybchenko const unsigned int ptr_mask = rxq->ptr_mask; 2563be22684SAndrew Rybchenko unsigned int pending = rxq->pending; 257638bddc9SAndrew Rybchenko unsigned int ready; 258638bddc9SAndrew Rybchenko struct sfc_ef10_rx_sw_desc *rxd; 259638bddc9SAndrew Rybchenko struct rte_mbuf *m; 260638bddc9SAndrew Rybchenko struct rte_mbuf *m0; 261638bddc9SAndrew Rybchenko const uint8_t *pseudo_hdr; 262c4753858SAndrew Rybchenko uint16_t seg_len; 263638bddc9SAndrew Rybchenko 2643be22684SAndrew Rybchenko ready = (EFX_QWORD_FIELD(rx_ev, ESF_DZ_RX_DSC_PTR_LBITS) - pending) & 265638bddc9SAndrew Rybchenko EFX_MASK32(ESF_DZ_RX_DSC_PTR_LBITS); 26652e10cb0SAndrew Rybchenko 26752e10cb0SAndrew Rybchenko if (ready == 0) { 26852e10cb0SAndrew Rybchenko /* Rx abort - it was no enough descriptors for Rx packet */ 26952e10cb0SAndrew Rybchenko rte_pktmbuf_free(rxq->scatter_pkt); 27052e10cb0SAndrew Rybchenko rxq->scatter_pkt = NULL; 27152e10cb0SAndrew Rybchenko return rx_pkts; 27252e10cb0SAndrew Rybchenko } 273638bddc9SAndrew Rybchenko 2743be22684SAndrew Rybchenko rxq->pending = pending + ready; 2753be22684SAndrew Rybchenko 276638bddc9SAndrew Rybchenko if (rx_ev.eq_u64[0] & 277638bddc9SAndrew Rybchenko rte_cpu_to_le_64((1ull << ESF_DZ_RX_ECC_ERR_LBN) | 278638bddc9SAndrew Rybchenko (1ull << ESF_DZ_RX_ECRC_ERR_LBN))) { 2793be22684SAndrew Rybchenko SFC_ASSERT(rxq->completed == pending); 2803be22684SAndrew Rybchenko do { 2813be22684SAndrew Rybchenko rxd = &rxq->sw_ring[pending++ & ptr_mask]; 28266e10b8dSAndrew Rybchenko rte_mbuf_raw_free(rxd->mbuf); 2833be22684SAndrew Rybchenko } while (pending != rxq->pending); 2843be22684SAndrew Rybchenko rxq->completed = pending; 28584b63b5cSAndrew Rybchenko return rx_pkts; 286638bddc9SAndrew Rybchenko } 287638bddc9SAndrew Rybchenko 28852e10cb0SAndrew Rybchenko /* If scattered packet is in progress */ 28952e10cb0SAndrew Rybchenko if (rxq->scatter_pkt != NULL) { 29052e10cb0SAndrew Rybchenko /* Events for scattered packet frags are not merged */ 29152e10cb0SAndrew Rybchenko SFC_ASSERT(ready == 1); 29252e10cb0SAndrew Rybchenko SFC_ASSERT(rxq->completed == pending); 29352e10cb0SAndrew Rybchenko 29452e10cb0SAndrew Rybchenko /* There is no pseudo-header in scatter segments. */ 29552e10cb0SAndrew Rybchenko seg_len = EFX_QWORD_FIELD(rx_ev, ESF_DZ_RX_BYTES); 29652e10cb0SAndrew Rybchenko 29752e10cb0SAndrew Rybchenko rxd = &rxq->sw_ring[pending++ & ptr_mask]; 29852e10cb0SAndrew Rybchenko m = rxd->mbuf; 29952e10cb0SAndrew Rybchenko 300*3a35c1c0SMorten Brørup __rte_mbuf_raw_sanity_check(m); 30152e10cb0SAndrew Rybchenko 30252e10cb0SAndrew Rybchenko m->data_off = RTE_PKTMBUF_HEADROOM; 30352e10cb0SAndrew Rybchenko rte_pktmbuf_data_len(m) = seg_len; 30452e10cb0SAndrew Rybchenko rte_pktmbuf_pkt_len(m) = seg_len; 30552e10cb0SAndrew Rybchenko 30652e10cb0SAndrew Rybchenko rxq->scatter_pkt->nb_segs++; 30752e10cb0SAndrew Rybchenko rte_pktmbuf_pkt_len(rxq->scatter_pkt) += seg_len; 30852e10cb0SAndrew Rybchenko rte_pktmbuf_lastseg(rxq->scatter_pkt)->next = m; 30952e10cb0SAndrew Rybchenko 31052e10cb0SAndrew Rybchenko if (~rx_ev.eq_u64[0] & 31152e10cb0SAndrew Rybchenko rte_cpu_to_le_64(1ull << ESF_DZ_RX_CONT_LBN)) { 31252e10cb0SAndrew Rybchenko *rx_pkts++ = rxq->scatter_pkt; 31352e10cb0SAndrew Rybchenko rxq->scatter_pkt = NULL; 31452e10cb0SAndrew Rybchenko } 31552e10cb0SAndrew Rybchenko rxq->completed = pending; 31652e10cb0SAndrew Rybchenko return rx_pkts; 31752e10cb0SAndrew Rybchenko } 31852e10cb0SAndrew Rybchenko 3193be22684SAndrew Rybchenko rxd = &rxq->sw_ring[pending++ & ptr_mask]; 320638bddc9SAndrew Rybchenko 3213be22684SAndrew Rybchenko sfc_ef10_rx_prefetch_next(rxq, pending & ptr_mask); 322638bddc9SAndrew Rybchenko 323638bddc9SAndrew Rybchenko m = rxd->mbuf; 324638bddc9SAndrew Rybchenko 32568de5f6cSAndrew Rybchenko RTE_BUILD_BUG_ON(sizeof(m->rearm_data[0]) != sizeof(rxq->rearm_data)); 32668de5f6cSAndrew Rybchenko m->rearm_data[0] = rxq->rearm_data; 327638bddc9SAndrew Rybchenko 328638bddc9SAndrew Rybchenko /* Classify packet based on Rx event */ 329a6539283SAndrew Rybchenko /* Mask RSS hash offload flag if RSS is not enabled */ 330a6539283SAndrew Rybchenko sfc_ef10_rx_ev_to_offloads(rx_ev, m, 331a6539283SAndrew Rybchenko (rxq->flags & SFC_EF10_RXQ_RSS_HASH) ? 332a6539283SAndrew Rybchenko ~0ull : ~PKT_RX_RSS_HASH); 333638bddc9SAndrew Rybchenko 334638bddc9SAndrew Rybchenko /* data_off already moved past pseudo header */ 335638bddc9SAndrew Rybchenko pseudo_hdr = (uint8_t *)m->buf_addr + RTE_PKTMBUF_HEADROOM; 336638bddc9SAndrew Rybchenko 337638bddc9SAndrew Rybchenko /* 338638bddc9SAndrew Rybchenko * Always get RSS hash from pseudo header to avoid 339638bddc9SAndrew Rybchenko * condition/branching. If it is valid or not depends on 340638bddc9SAndrew Rybchenko * PKT_RX_RSS_HASH in m->ol_flags. 341638bddc9SAndrew Rybchenko */ 342638bddc9SAndrew Rybchenko m->hash.rss = sfc_ef10_rx_pseudo_hdr_get_hash(pseudo_hdr); 343638bddc9SAndrew Rybchenko 344638bddc9SAndrew Rybchenko if (ready == 1) 345c4753858SAndrew Rybchenko seg_len = EFX_QWORD_FIELD(rx_ev, ESF_DZ_RX_BYTES) - 346638bddc9SAndrew Rybchenko rxq->prefix_size; 347638bddc9SAndrew Rybchenko else 348c4753858SAndrew Rybchenko seg_len = sfc_ef10_rx_pseudo_hdr_get_len(pseudo_hdr); 349c4753858SAndrew Rybchenko SFC_ASSERT(seg_len > 0); 350c4753858SAndrew Rybchenko rte_pktmbuf_data_len(m) = seg_len; 351c4753858SAndrew Rybchenko rte_pktmbuf_pkt_len(m) = seg_len; 352638bddc9SAndrew Rybchenko 35368de5f6cSAndrew Rybchenko SFC_ASSERT(m->next == NULL); 354638bddc9SAndrew Rybchenko 35552e10cb0SAndrew Rybchenko if (~rx_ev.eq_u64[0] & rte_cpu_to_le_64(1ull << ESF_DZ_RX_CONT_LBN)) { 35652e10cb0SAndrew Rybchenko *rx_pkts++ = m; 35752e10cb0SAndrew Rybchenko rxq->completed = pending; 35852e10cb0SAndrew Rybchenko } else { 35952e10cb0SAndrew Rybchenko /* Events with CONT bit are not merged */ 36052e10cb0SAndrew Rybchenko SFC_ASSERT(ready == 1); 36152e10cb0SAndrew Rybchenko rxq->scatter_pkt = m; 36252e10cb0SAndrew Rybchenko rxq->completed = pending; 36352e10cb0SAndrew Rybchenko return rx_pkts; 36452e10cb0SAndrew Rybchenko } 36552e10cb0SAndrew Rybchenko 366638bddc9SAndrew Rybchenko /* Remember mbuf to copy offload flags and packet type from */ 367638bddc9SAndrew Rybchenko m0 = m; 3683be22684SAndrew Rybchenko while (pending != rxq->pending) { 3693be22684SAndrew Rybchenko rxd = &rxq->sw_ring[pending++ & ptr_mask]; 370638bddc9SAndrew Rybchenko 3713be22684SAndrew Rybchenko sfc_ef10_rx_prefetch_next(rxq, pending & ptr_mask); 372638bddc9SAndrew Rybchenko 373638bddc9SAndrew Rybchenko m = rxd->mbuf; 374638bddc9SAndrew Rybchenko 3753be22684SAndrew Rybchenko if (rx_pkts != rx_pkts_end) { 376638bddc9SAndrew Rybchenko *rx_pkts++ = m; 3773be22684SAndrew Rybchenko rxq->completed = pending; 3783be22684SAndrew Rybchenko } 379638bddc9SAndrew Rybchenko 38068de5f6cSAndrew Rybchenko RTE_BUILD_BUG_ON(sizeof(m->rearm_data[0]) != 38168de5f6cSAndrew Rybchenko sizeof(rxq->rearm_data)); 38268de5f6cSAndrew Rybchenko m->rearm_data[0] = rxq->rearm_data; 383638bddc9SAndrew Rybchenko 384638bddc9SAndrew Rybchenko /* Event-dependent information is the same */ 385638bddc9SAndrew Rybchenko m->ol_flags = m0->ol_flags; 386638bddc9SAndrew Rybchenko m->packet_type = m0->packet_type; 387638bddc9SAndrew Rybchenko 388638bddc9SAndrew Rybchenko /* data_off already moved past pseudo header */ 389638bddc9SAndrew Rybchenko pseudo_hdr = (uint8_t *)m->buf_addr + RTE_PKTMBUF_HEADROOM; 390638bddc9SAndrew Rybchenko 391638bddc9SAndrew Rybchenko /* 392638bddc9SAndrew Rybchenko * Always get RSS hash from pseudo header to avoid 393638bddc9SAndrew Rybchenko * condition/branching. If it is valid or not depends on 394638bddc9SAndrew Rybchenko * PKT_RX_RSS_HASH in m->ol_flags. 395638bddc9SAndrew Rybchenko */ 396638bddc9SAndrew Rybchenko m->hash.rss = sfc_ef10_rx_pseudo_hdr_get_hash(pseudo_hdr); 397638bddc9SAndrew Rybchenko 398c4753858SAndrew Rybchenko seg_len = sfc_ef10_rx_pseudo_hdr_get_len(pseudo_hdr); 399c4753858SAndrew Rybchenko SFC_ASSERT(seg_len > 0); 400c4753858SAndrew Rybchenko rte_pktmbuf_data_len(m) = seg_len; 401c4753858SAndrew Rybchenko rte_pktmbuf_pkt_len(m) = seg_len; 402638bddc9SAndrew Rybchenko 40368de5f6cSAndrew Rybchenko SFC_ASSERT(m->next == NULL); 404638bddc9SAndrew Rybchenko } 405638bddc9SAndrew Rybchenko 40684b63b5cSAndrew Rybchenko return rx_pkts; 407638bddc9SAndrew Rybchenko } 408638bddc9SAndrew Rybchenko 409638bddc9SAndrew Rybchenko static bool 410638bddc9SAndrew Rybchenko sfc_ef10_rx_get_event(struct sfc_ef10_rxq *rxq, efx_qword_t *rx_ev) 411638bddc9SAndrew Rybchenko { 412638bddc9SAndrew Rybchenko *rx_ev = rxq->evq_hw_ring[rxq->evq_read_ptr & rxq->ptr_mask]; 413638bddc9SAndrew Rybchenko 414638bddc9SAndrew Rybchenko if (!sfc_ef10_ev_present(*rx_ev)) 415638bddc9SAndrew Rybchenko return false; 416638bddc9SAndrew Rybchenko 417638bddc9SAndrew Rybchenko if (unlikely(EFX_QWORD_FIELD(*rx_ev, FSF_AZ_EV_CODE) != 418638bddc9SAndrew Rybchenko FSE_AZ_EV_CODE_RX_EV)) { 419638bddc9SAndrew Rybchenko /* 420638bddc9SAndrew Rybchenko * Do not move read_ptr to keep the event for exception 421638bddc9SAndrew Rybchenko * handling by the control path. 422638bddc9SAndrew Rybchenko */ 423638bddc9SAndrew Rybchenko rxq->flags |= SFC_EF10_RXQ_EXCEPTION; 424638bddc9SAndrew Rybchenko sfc_ef10_rx_err(&rxq->dp.dpq, 425638bddc9SAndrew Rybchenko "RxQ exception at EvQ read ptr %#x", 426638bddc9SAndrew Rybchenko rxq->evq_read_ptr); 427638bddc9SAndrew Rybchenko return false; 428638bddc9SAndrew Rybchenko } 429638bddc9SAndrew Rybchenko 430638bddc9SAndrew Rybchenko rxq->evq_read_ptr++; 431638bddc9SAndrew Rybchenko return true; 432638bddc9SAndrew Rybchenko } 433638bddc9SAndrew Rybchenko 434638bddc9SAndrew Rybchenko static uint16_t 435638bddc9SAndrew Rybchenko sfc_ef10_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) 436638bddc9SAndrew Rybchenko { 437638bddc9SAndrew Rybchenko struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(rx_queue); 43884b63b5cSAndrew Rybchenko struct rte_mbuf ** const rx_pkts_end = &rx_pkts[nb_pkts]; 439638bddc9SAndrew Rybchenko unsigned int evq_old_read_ptr; 440638bddc9SAndrew Rybchenko efx_qword_t rx_ev; 441638bddc9SAndrew Rybchenko 4423be22684SAndrew Rybchenko rx_pkts = sfc_ef10_rx_pending(rxq, rx_pkts, nb_pkts); 443f609ee3fSAndrew Rybchenko 444638bddc9SAndrew Rybchenko if (unlikely(rxq->flags & 445638bddc9SAndrew Rybchenko (SFC_EF10_RXQ_NOT_RUNNING | SFC_EF10_RXQ_EXCEPTION))) 446f609ee3fSAndrew Rybchenko goto done; 447638bddc9SAndrew Rybchenko 448638bddc9SAndrew Rybchenko evq_old_read_ptr = rxq->evq_read_ptr; 44984b63b5cSAndrew Rybchenko while (rx_pkts != rx_pkts_end && sfc_ef10_rx_get_event(rxq, &rx_ev)) { 450638bddc9SAndrew Rybchenko /* 451638bddc9SAndrew Rybchenko * DROP_EVENT is an internal to the NIC, software should 452638bddc9SAndrew Rybchenko * never see it and, therefore, may ignore it. 453638bddc9SAndrew Rybchenko */ 454638bddc9SAndrew Rybchenko 45584b63b5cSAndrew Rybchenko rx_pkts = sfc_ef10_rx_process_event(rxq, rx_ev, 45684b63b5cSAndrew Rybchenko rx_pkts, rx_pkts_end); 457638bddc9SAndrew Rybchenko } 458638bddc9SAndrew Rybchenko 459638bddc9SAndrew Rybchenko sfc_ef10_ev_qclear(rxq->evq_hw_ring, rxq->ptr_mask, evq_old_read_ptr, 460638bddc9SAndrew Rybchenko rxq->evq_read_ptr); 461638bddc9SAndrew Rybchenko 462638bddc9SAndrew Rybchenko /* It is not a problem if we refill in the case of exception */ 463638bddc9SAndrew Rybchenko sfc_ef10_rx_qrefill(rxq); 464638bddc9SAndrew Rybchenko 4651245e3faSGeorgiy Levashov if ((rxq->flags & SFC_EF10_RXQ_FLAG_INTR_EN) && 4661245e3faSGeorgiy Levashov rxq->evq_read_ptr_primed != rxq->evq_read_ptr) 4671245e3faSGeorgiy Levashov sfc_ef10_rx_qprime(rxq); 4681245e3faSGeorgiy Levashov 469f609ee3fSAndrew Rybchenko done: 47084b63b5cSAndrew Rybchenko return nb_pkts - (rx_pkts_end - rx_pkts); 471638bddc9SAndrew Rybchenko } 472638bddc9SAndrew Rybchenko 473390f9b8dSAndrew Rybchenko const uint32_t * 474591cbbb1SAndrew Rybchenko sfc_ef10_supported_ptypes_get(uint32_t tunnel_encaps) 475638bddc9SAndrew Rybchenko { 476638bddc9SAndrew Rybchenko static const uint32_t ef10_native_ptypes[] = { 477638bddc9SAndrew Rybchenko RTE_PTYPE_L2_ETHER, 478638bddc9SAndrew Rybchenko RTE_PTYPE_L2_ETHER_ARP, 479638bddc9SAndrew Rybchenko RTE_PTYPE_L2_ETHER_VLAN, 480638bddc9SAndrew Rybchenko RTE_PTYPE_L2_ETHER_QINQ, 481638bddc9SAndrew Rybchenko RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 482638bddc9SAndrew Rybchenko RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 483638bddc9SAndrew Rybchenko RTE_PTYPE_L4_FRAG, 484638bddc9SAndrew Rybchenko RTE_PTYPE_L4_TCP, 485638bddc9SAndrew Rybchenko RTE_PTYPE_L4_UDP, 486638bddc9SAndrew Rybchenko RTE_PTYPE_UNKNOWN 487638bddc9SAndrew Rybchenko }; 488591cbbb1SAndrew Rybchenko static const uint32_t ef10_overlay_ptypes[] = { 489591cbbb1SAndrew Rybchenko RTE_PTYPE_L2_ETHER, 490591cbbb1SAndrew Rybchenko RTE_PTYPE_L2_ETHER_ARP, 491591cbbb1SAndrew Rybchenko RTE_PTYPE_L2_ETHER_VLAN, 492591cbbb1SAndrew Rybchenko RTE_PTYPE_L2_ETHER_QINQ, 493591cbbb1SAndrew Rybchenko RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 494591cbbb1SAndrew Rybchenko RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 495591cbbb1SAndrew Rybchenko RTE_PTYPE_L4_FRAG, 496591cbbb1SAndrew Rybchenko RTE_PTYPE_L4_TCP, 497591cbbb1SAndrew Rybchenko RTE_PTYPE_L4_UDP, 498591cbbb1SAndrew Rybchenko RTE_PTYPE_TUNNEL_VXLAN, 499591cbbb1SAndrew Rybchenko RTE_PTYPE_TUNNEL_NVGRE, 500591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L2_ETHER, 501591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L2_ETHER_VLAN, 502591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L2_ETHER_QINQ, 503591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, 504591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, 505591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L4_FRAG, 506591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L4_TCP, 507591cbbb1SAndrew Rybchenko RTE_PTYPE_INNER_L4_UDP, 508591cbbb1SAndrew Rybchenko RTE_PTYPE_UNKNOWN 509591cbbb1SAndrew Rybchenko }; 510638bddc9SAndrew Rybchenko 511591cbbb1SAndrew Rybchenko /* 512591cbbb1SAndrew Rybchenko * The function returns static set of supported packet types, 513591cbbb1SAndrew Rybchenko * so we can't build it dynamically based on supported tunnel 514591cbbb1SAndrew Rybchenko * encapsulations and should limit to known sets. 515591cbbb1SAndrew Rybchenko */ 516591cbbb1SAndrew Rybchenko switch (tunnel_encaps) { 517591cbbb1SAndrew Rybchenko case (1u << EFX_TUNNEL_PROTOCOL_VXLAN | 518591cbbb1SAndrew Rybchenko 1u << EFX_TUNNEL_PROTOCOL_GENEVE | 519591cbbb1SAndrew Rybchenko 1u << EFX_TUNNEL_PROTOCOL_NVGRE): 520591cbbb1SAndrew Rybchenko return ef10_overlay_ptypes; 521591cbbb1SAndrew Rybchenko default: 522fdceb100SIvan Malov SFC_GENERIC_LOG(ERR, 523fdceb100SIvan Malov "Unexpected set of supported tunnel encapsulations: %#x", 524591cbbb1SAndrew Rybchenko tunnel_encaps); 525591cbbb1SAndrew Rybchenko /* FALLTHROUGH */ 526591cbbb1SAndrew Rybchenko case 0: 527638bddc9SAndrew Rybchenko return ef10_native_ptypes; 528638bddc9SAndrew Rybchenko } 529591cbbb1SAndrew Rybchenko } 530638bddc9SAndrew Rybchenko 531638bddc9SAndrew Rybchenko static sfc_dp_rx_qdesc_npending_t sfc_ef10_rx_qdesc_npending; 532638bddc9SAndrew Rybchenko static unsigned int 5331a9d944fSIgor Romanov sfc_ef10_rx_qdesc_npending(struct sfc_dp_rxq *dp_rxq) 534638bddc9SAndrew Rybchenko { 5351a9d944fSIgor Romanov struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 5361a9d944fSIgor Romanov efx_qword_t rx_ev; 5371a9d944fSIgor Romanov const unsigned int evq_old_read_ptr = rxq->evq_read_ptr; 5381a9d944fSIgor Romanov unsigned int pending = rxq->pending; 5391a9d944fSIgor Romanov unsigned int ready; 5401a9d944fSIgor Romanov 5411a9d944fSIgor Romanov if (unlikely(rxq->flags & 5421a9d944fSIgor Romanov (SFC_EF10_RXQ_NOT_RUNNING | SFC_EF10_RXQ_EXCEPTION))) 5431a9d944fSIgor Romanov goto done; 5441a9d944fSIgor Romanov 5451a9d944fSIgor Romanov while (sfc_ef10_rx_get_event(rxq, &rx_ev)) { 5461a9d944fSIgor Romanov ready = (EFX_QWORD_FIELD(rx_ev, ESF_DZ_RX_DSC_PTR_LBITS) - 5471a9d944fSIgor Romanov pending) & 5481a9d944fSIgor Romanov EFX_MASK32(ESF_DZ_RX_DSC_PTR_LBITS); 5491a9d944fSIgor Romanov pending += ready; 5501a9d944fSIgor Romanov } 5511a9d944fSIgor Romanov 552638bddc9SAndrew Rybchenko /* 5531a9d944fSIgor Romanov * The function does not process events, so return event queue read 5541a9d944fSIgor Romanov * pointer to the original position to allow the events that were 5551a9d944fSIgor Romanov * read to be processed later 556638bddc9SAndrew Rybchenko */ 5571a9d944fSIgor Romanov rxq->evq_read_ptr = evq_old_read_ptr; 5581a9d944fSIgor Romanov 5591a9d944fSIgor Romanov done: 5601a9d944fSIgor Romanov return pending - rxq->completed; 561638bddc9SAndrew Rybchenko } 562638bddc9SAndrew Rybchenko 5631d8f3a80SIvan Malov static sfc_dp_rx_qdesc_status_t sfc_ef10_rx_qdesc_status; 5641d8f3a80SIvan Malov static int 5651a9d944fSIgor Romanov sfc_ef10_rx_qdesc_status(struct sfc_dp_rxq *dp_rxq, uint16_t offset) 5661d8f3a80SIvan Malov { 5671a9d944fSIgor Romanov struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 5681a9d944fSIgor Romanov unsigned int npending = sfc_ef10_rx_qdesc_npending(dp_rxq); 5691a9d944fSIgor Romanov 5701a9d944fSIgor Romanov if (unlikely(offset > rxq->ptr_mask)) 5711a9d944fSIgor Romanov return -EINVAL; 5721a9d944fSIgor Romanov 5731a9d944fSIgor Romanov if (offset < npending) 5741a9d944fSIgor Romanov return RTE_ETH_RX_DESC_DONE; 5751a9d944fSIgor Romanov 5761a9d944fSIgor Romanov if (offset < (rxq->added - rxq->completed)) 5771a9d944fSIgor Romanov return RTE_ETH_RX_DESC_AVAIL; 5781a9d944fSIgor Romanov 5791a9d944fSIgor Romanov return RTE_ETH_RX_DESC_UNAVAIL; 5801d8f3a80SIvan Malov } 5811d8f3a80SIvan Malov 582638bddc9SAndrew Rybchenko 5833c335b7fSAndrew Rybchenko static sfc_dp_rx_get_dev_info_t sfc_ef10_rx_get_dev_info; 5843c335b7fSAndrew Rybchenko static void 5853c335b7fSAndrew Rybchenko sfc_ef10_rx_get_dev_info(struct rte_eth_dev_info *dev_info) 5863c335b7fSAndrew Rybchenko { 5873c335b7fSAndrew Rybchenko /* 5883c335b7fSAndrew Rybchenko * Number of descriptors just defines maximum number of pushed 5893c335b7fSAndrew Rybchenko * descriptors (fill level). 5903c335b7fSAndrew Rybchenko */ 5913c335b7fSAndrew Rybchenko dev_info->rx_desc_lim.nb_min = SFC_RX_REFILL_BULK; 5923c335b7fSAndrew Rybchenko dev_info->rx_desc_lim.nb_align = SFC_RX_REFILL_BULK; 5933c335b7fSAndrew Rybchenko } 5943c335b7fSAndrew Rybchenko 5953c335b7fSAndrew Rybchenko 596f7da270aSAndrew Rybchenko static sfc_dp_rx_qsize_up_rings_t sfc_ef10_rx_qsize_up_rings; 597f7da270aSAndrew Rybchenko static int 598f7da270aSAndrew Rybchenko sfc_ef10_rx_qsize_up_rings(uint16_t nb_rx_desc, 599048a0d1aSIgor Romanov struct sfc_dp_rx_hw_limits *limits, 600d101da1bSAndrew Rybchenko __rte_unused struct rte_mempool *mb_pool, 601f7da270aSAndrew Rybchenko unsigned int *rxq_entries, 602f7da270aSAndrew Rybchenko unsigned int *evq_entries, 603f7da270aSAndrew Rybchenko unsigned int *rxq_max_fill_level) 604f7da270aSAndrew Rybchenko { 6053c335b7fSAndrew Rybchenko /* 6063c335b7fSAndrew Rybchenko * rte_ethdev API guarantees that the number meets min, max and 6073c335b7fSAndrew Rybchenko * alignment requirements. 6083c335b7fSAndrew Rybchenko */ 609048a0d1aSIgor Romanov if (nb_rx_desc <= limits->rxq_min_entries) 610048a0d1aSIgor Romanov *rxq_entries = limits->rxq_min_entries; 6113c335b7fSAndrew Rybchenko else 6123c335b7fSAndrew Rybchenko *rxq_entries = rte_align32pow2(nb_rx_desc); 6133c335b7fSAndrew Rybchenko 6143c335b7fSAndrew Rybchenko *evq_entries = *rxq_entries; 6153c335b7fSAndrew Rybchenko 6163c335b7fSAndrew Rybchenko *rxq_max_fill_level = RTE_MIN(nb_rx_desc, 6173c335b7fSAndrew Rybchenko SFC_EF10_RXQ_LIMIT(*evq_entries)); 618f7da270aSAndrew Rybchenko return 0; 619f7da270aSAndrew Rybchenko } 620f7da270aSAndrew Rybchenko 621f7da270aSAndrew Rybchenko 622638bddc9SAndrew Rybchenko static uint64_t 623638bddc9SAndrew Rybchenko sfc_ef10_mk_mbuf_rearm_data(uint16_t port_id, uint16_t prefix_size) 624638bddc9SAndrew Rybchenko { 625638bddc9SAndrew Rybchenko struct rte_mbuf m; 626638bddc9SAndrew Rybchenko 627638bddc9SAndrew Rybchenko memset(&m, 0, sizeof(m)); 628638bddc9SAndrew Rybchenko 629638bddc9SAndrew Rybchenko rte_mbuf_refcnt_set(&m, 1); 630638bddc9SAndrew Rybchenko m.data_off = RTE_PKTMBUF_HEADROOM + prefix_size; 631638bddc9SAndrew Rybchenko m.nb_segs = 1; 632638bddc9SAndrew Rybchenko m.port = port_id; 633638bddc9SAndrew Rybchenko 634638bddc9SAndrew Rybchenko /* rearm_data covers structure members filled in above */ 635638bddc9SAndrew Rybchenko rte_compiler_barrier(); 63668de5f6cSAndrew Rybchenko RTE_BUILD_BUG_ON(sizeof(m.rearm_data[0]) != sizeof(uint64_t)); 63768de5f6cSAndrew Rybchenko return m.rearm_data[0]; 638638bddc9SAndrew Rybchenko } 639638bddc9SAndrew Rybchenko 640638bddc9SAndrew Rybchenko static sfc_dp_rx_qcreate_t sfc_ef10_rx_qcreate; 641638bddc9SAndrew Rybchenko static int 642638bddc9SAndrew Rybchenko sfc_ef10_rx_qcreate(uint16_t port_id, uint16_t queue_id, 643638bddc9SAndrew Rybchenko const struct rte_pci_addr *pci_addr, int socket_id, 644638bddc9SAndrew Rybchenko const struct sfc_dp_rx_qcreate_info *info, 645638bddc9SAndrew Rybchenko struct sfc_dp_rxq **dp_rxqp) 646638bddc9SAndrew Rybchenko { 647638bddc9SAndrew Rybchenko struct sfc_ef10_rxq *rxq; 648638bddc9SAndrew Rybchenko int rc; 649638bddc9SAndrew Rybchenko 650638bddc9SAndrew Rybchenko rc = EINVAL; 651638bddc9SAndrew Rybchenko if (info->rxq_entries != info->evq_entries) 652638bddc9SAndrew Rybchenko goto fail_rxq_args; 653638bddc9SAndrew Rybchenko 654638bddc9SAndrew Rybchenko rc = ENOMEM; 655638bddc9SAndrew Rybchenko rxq = rte_zmalloc_socket("sfc-ef10-rxq", sizeof(*rxq), 656638bddc9SAndrew Rybchenko RTE_CACHE_LINE_SIZE, socket_id); 657638bddc9SAndrew Rybchenko if (rxq == NULL) 658638bddc9SAndrew Rybchenko goto fail_rxq_alloc; 659638bddc9SAndrew Rybchenko 660638bddc9SAndrew Rybchenko sfc_dp_queue_init(&rxq->dp.dpq, port_id, queue_id, pci_addr); 661638bddc9SAndrew Rybchenko 662638bddc9SAndrew Rybchenko rc = ENOMEM; 663638bddc9SAndrew Rybchenko rxq->sw_ring = rte_calloc_socket("sfc-ef10-rxq-sw_ring", 664638bddc9SAndrew Rybchenko info->rxq_entries, 665638bddc9SAndrew Rybchenko sizeof(*rxq->sw_ring), 666638bddc9SAndrew Rybchenko RTE_CACHE_LINE_SIZE, socket_id); 667638bddc9SAndrew Rybchenko if (rxq->sw_ring == NULL) 668638bddc9SAndrew Rybchenko goto fail_desc_alloc; 669638bddc9SAndrew Rybchenko 670638bddc9SAndrew Rybchenko rxq->flags |= SFC_EF10_RXQ_NOT_RUNNING; 671638bddc9SAndrew Rybchenko if (info->flags & SFC_RXQ_FLAG_RSS_HASH) 672638bddc9SAndrew Rybchenko rxq->flags |= SFC_EF10_RXQ_RSS_HASH; 673638bddc9SAndrew Rybchenko rxq->ptr_mask = info->rxq_entries - 1; 674638bddc9SAndrew Rybchenko rxq->evq_hw_ring = info->evq_hw_ring; 675e5595ee2SAndrew Rybchenko rxq->max_fill_level = info->max_fill_level; 676638bddc9SAndrew Rybchenko rxq->refill_threshold = info->refill_threshold; 677638bddc9SAndrew Rybchenko rxq->rearm_data = 678638bddc9SAndrew Rybchenko sfc_ef10_mk_mbuf_rearm_data(port_id, info->prefix_size); 679638bddc9SAndrew Rybchenko rxq->prefix_size = info->prefix_size; 680638bddc9SAndrew Rybchenko rxq->buf_size = info->buf_size; 681638bddc9SAndrew Rybchenko rxq->refill_mb_pool = info->refill_mb_pool; 682638bddc9SAndrew Rybchenko rxq->rxq_hw_ring = info->rxq_hw_ring; 683638bddc9SAndrew Rybchenko rxq->doorbell = (volatile uint8_t *)info->mem_bar + 684638bddc9SAndrew Rybchenko ER_DZ_RX_DESC_UPD_REG_OFST + 685714bff55SAndrew Rybchenko (info->hw_index << info->vi_window_shift); 6861245e3faSGeorgiy Levashov rxq->evq_prime = (volatile uint8_t *)info->mem_bar + 6871245e3faSGeorgiy Levashov ER_DZ_EVQ_RPTR_REG_OFST + 6881245e3faSGeorgiy Levashov (info->evq_hw_index << info->vi_window_shift); 689638bddc9SAndrew Rybchenko 690e7fbf6f5SAndrew Rybchenko sfc_ef10_rx_info(&rxq->dp.dpq, "RxQ doorbell is %p", rxq->doorbell); 691e7fbf6f5SAndrew Rybchenko 692638bddc9SAndrew Rybchenko *dp_rxqp = &rxq->dp; 693638bddc9SAndrew Rybchenko return 0; 694638bddc9SAndrew Rybchenko 695638bddc9SAndrew Rybchenko fail_desc_alloc: 696638bddc9SAndrew Rybchenko rte_free(rxq); 697638bddc9SAndrew Rybchenko 698638bddc9SAndrew Rybchenko fail_rxq_alloc: 699638bddc9SAndrew Rybchenko fail_rxq_args: 700638bddc9SAndrew Rybchenko return rc; 701638bddc9SAndrew Rybchenko } 702638bddc9SAndrew Rybchenko 703638bddc9SAndrew Rybchenko static sfc_dp_rx_qdestroy_t sfc_ef10_rx_qdestroy; 704638bddc9SAndrew Rybchenko static void 705638bddc9SAndrew Rybchenko sfc_ef10_rx_qdestroy(struct sfc_dp_rxq *dp_rxq) 706638bddc9SAndrew Rybchenko { 707638bddc9SAndrew Rybchenko struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 708638bddc9SAndrew Rybchenko 709638bddc9SAndrew Rybchenko rte_free(rxq->sw_ring); 710638bddc9SAndrew Rybchenko rte_free(rxq); 711638bddc9SAndrew Rybchenko } 712638bddc9SAndrew Rybchenko 713638bddc9SAndrew Rybchenko static sfc_dp_rx_qstart_t sfc_ef10_rx_qstart; 714638bddc9SAndrew Rybchenko static int 715c6845644SAndrew Rybchenko sfc_ef10_rx_qstart(struct sfc_dp_rxq *dp_rxq, unsigned int evq_read_ptr, 716c6845644SAndrew Rybchenko const efx_rx_prefix_layout_t *pinfo) 717638bddc9SAndrew Rybchenko { 718638bddc9SAndrew Rybchenko struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 719638bddc9SAndrew Rybchenko 720f609ee3fSAndrew Rybchenko SFC_ASSERT(rxq->completed == 0); 7213be22684SAndrew Rybchenko SFC_ASSERT(rxq->pending == 0); 722f609ee3fSAndrew Rybchenko SFC_ASSERT(rxq->added == 0); 723638bddc9SAndrew Rybchenko 724c6845644SAndrew Rybchenko if (pinfo->erpl_length != rxq->prefix_size || 725c6845644SAndrew Rybchenko efx_rx_prefix_layout_check(pinfo, &sfc_ef10_rx_prefix_layout) != 0) 726c6845644SAndrew Rybchenko return ENOTSUP; 727c6845644SAndrew Rybchenko 728638bddc9SAndrew Rybchenko sfc_ef10_rx_qrefill(rxq); 729638bddc9SAndrew Rybchenko 730638bddc9SAndrew Rybchenko rxq->evq_read_ptr = evq_read_ptr; 731638bddc9SAndrew Rybchenko 732638bddc9SAndrew Rybchenko rxq->flags |= SFC_EF10_RXQ_STARTED; 733638bddc9SAndrew Rybchenko rxq->flags &= ~(SFC_EF10_RXQ_NOT_RUNNING | SFC_EF10_RXQ_EXCEPTION); 734638bddc9SAndrew Rybchenko 7351245e3faSGeorgiy Levashov if (rxq->flags & SFC_EF10_RXQ_FLAG_INTR_EN) 7361245e3faSGeorgiy Levashov sfc_ef10_rx_qprime(rxq); 7371245e3faSGeorgiy Levashov 738638bddc9SAndrew Rybchenko return 0; 739638bddc9SAndrew Rybchenko } 740638bddc9SAndrew Rybchenko 741638bddc9SAndrew Rybchenko static sfc_dp_rx_qstop_t sfc_ef10_rx_qstop; 742638bddc9SAndrew Rybchenko static void 743638bddc9SAndrew Rybchenko sfc_ef10_rx_qstop(struct sfc_dp_rxq *dp_rxq, unsigned int *evq_read_ptr) 744638bddc9SAndrew Rybchenko { 745638bddc9SAndrew Rybchenko struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 746638bddc9SAndrew Rybchenko 747638bddc9SAndrew Rybchenko rxq->flags |= SFC_EF10_RXQ_NOT_RUNNING; 748638bddc9SAndrew Rybchenko 749638bddc9SAndrew Rybchenko *evq_read_ptr = rxq->evq_read_ptr; 750638bddc9SAndrew Rybchenko } 751638bddc9SAndrew Rybchenko 752638bddc9SAndrew Rybchenko static sfc_dp_rx_qrx_ev_t sfc_ef10_rx_qrx_ev; 753638bddc9SAndrew Rybchenko static bool 754638bddc9SAndrew Rybchenko sfc_ef10_rx_qrx_ev(struct sfc_dp_rxq *dp_rxq, __rte_unused unsigned int id) 755638bddc9SAndrew Rybchenko { 756638bddc9SAndrew Rybchenko __rte_unused struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 757638bddc9SAndrew Rybchenko 758638bddc9SAndrew Rybchenko SFC_ASSERT(rxq->flags & SFC_EF10_RXQ_NOT_RUNNING); 759638bddc9SAndrew Rybchenko 760638bddc9SAndrew Rybchenko /* 761638bddc9SAndrew Rybchenko * It is safe to ignore Rx event since we free all mbufs on 762638bddc9SAndrew Rybchenko * queue purge anyway. 763638bddc9SAndrew Rybchenko */ 764638bddc9SAndrew Rybchenko 765638bddc9SAndrew Rybchenko return false; 766638bddc9SAndrew Rybchenko } 767638bddc9SAndrew Rybchenko 768638bddc9SAndrew Rybchenko static sfc_dp_rx_qpurge_t sfc_ef10_rx_qpurge; 769638bddc9SAndrew Rybchenko static void 770638bddc9SAndrew Rybchenko sfc_ef10_rx_qpurge(struct sfc_dp_rxq *dp_rxq) 771638bddc9SAndrew Rybchenko { 772638bddc9SAndrew Rybchenko struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 773638bddc9SAndrew Rybchenko unsigned int i; 774638bddc9SAndrew Rybchenko struct sfc_ef10_rx_sw_desc *rxd; 775638bddc9SAndrew Rybchenko 77652e10cb0SAndrew Rybchenko rte_pktmbuf_free(rxq->scatter_pkt); 77752e10cb0SAndrew Rybchenko rxq->scatter_pkt = NULL; 77852e10cb0SAndrew Rybchenko 779638bddc9SAndrew Rybchenko for (i = rxq->completed; i != rxq->added; ++i) { 780638bddc9SAndrew Rybchenko rxd = &rxq->sw_ring[i & rxq->ptr_mask]; 78166e10b8dSAndrew Rybchenko rte_mbuf_raw_free(rxd->mbuf); 782638bddc9SAndrew Rybchenko rxd->mbuf = NULL; 783638bddc9SAndrew Rybchenko } 784638bddc9SAndrew Rybchenko 7853be22684SAndrew Rybchenko rxq->completed = rxq->pending = rxq->added = 0; 786f609ee3fSAndrew Rybchenko 787638bddc9SAndrew Rybchenko rxq->flags &= ~SFC_EF10_RXQ_STARTED; 788638bddc9SAndrew Rybchenko } 789638bddc9SAndrew Rybchenko 7901245e3faSGeorgiy Levashov static sfc_dp_rx_intr_enable_t sfc_ef10_rx_intr_enable; 7911245e3faSGeorgiy Levashov static int 7921245e3faSGeorgiy Levashov sfc_ef10_rx_intr_enable(struct sfc_dp_rxq *dp_rxq) 7931245e3faSGeorgiy Levashov { 7941245e3faSGeorgiy Levashov struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 7951245e3faSGeorgiy Levashov 7961245e3faSGeorgiy Levashov rxq->flags |= SFC_EF10_RXQ_FLAG_INTR_EN; 7971245e3faSGeorgiy Levashov if (rxq->flags & SFC_EF10_RXQ_STARTED) 7981245e3faSGeorgiy Levashov sfc_ef10_rx_qprime(rxq); 7991245e3faSGeorgiy Levashov return 0; 8001245e3faSGeorgiy Levashov } 8011245e3faSGeorgiy Levashov 8021245e3faSGeorgiy Levashov static sfc_dp_rx_intr_disable_t sfc_ef10_rx_intr_disable; 8031245e3faSGeorgiy Levashov static int 8041245e3faSGeorgiy Levashov sfc_ef10_rx_intr_disable(struct sfc_dp_rxq *dp_rxq) 8051245e3faSGeorgiy Levashov { 8061245e3faSGeorgiy Levashov struct sfc_ef10_rxq *rxq = sfc_ef10_rxq_by_dp_rxq(dp_rxq); 8071245e3faSGeorgiy Levashov 8081245e3faSGeorgiy Levashov /* Cannot disarm, just disable rearm */ 8091245e3faSGeorgiy Levashov rxq->flags &= ~SFC_EF10_RXQ_FLAG_INTR_EN; 8101245e3faSGeorgiy Levashov return 0; 8111245e3faSGeorgiy Levashov } 8121245e3faSGeorgiy Levashov 813638bddc9SAndrew Rybchenko struct sfc_dp_rx sfc_ef10_rx = { 814638bddc9SAndrew Rybchenko .dp = { 815638bddc9SAndrew Rybchenko .name = SFC_KVARG_DATAPATH_EF10, 816638bddc9SAndrew Rybchenko .type = SFC_DP_RX, 817638bddc9SAndrew Rybchenko .hw_fw_caps = SFC_DP_HW_FW_CAP_EF10, 818638bddc9SAndrew Rybchenko }, 8191245e3faSGeorgiy Levashov .features = SFC_DP_RX_FEAT_MULTI_PROCESS | 8201245e3faSGeorgiy Levashov SFC_DP_RX_FEAT_INTR, 821f08d113dSAndrew Rybchenko .dev_offload_capa = DEV_RX_OFFLOAD_CHECKSUM | 8228b945a7fSPavan Nikhilesh DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM | 8238b945a7fSPavan Nikhilesh DEV_RX_OFFLOAD_RSS_HASH, 824f08d113dSAndrew Rybchenko .queue_offload_capa = DEV_RX_OFFLOAD_SCATTER, 8253c335b7fSAndrew Rybchenko .get_dev_info = sfc_ef10_rx_get_dev_info, 826f7da270aSAndrew Rybchenko .qsize_up_rings = sfc_ef10_rx_qsize_up_rings, 827638bddc9SAndrew Rybchenko .qcreate = sfc_ef10_rx_qcreate, 828638bddc9SAndrew Rybchenko .qdestroy = sfc_ef10_rx_qdestroy, 829638bddc9SAndrew Rybchenko .qstart = sfc_ef10_rx_qstart, 830638bddc9SAndrew Rybchenko .qstop = sfc_ef10_rx_qstop, 831638bddc9SAndrew Rybchenko .qrx_ev = sfc_ef10_rx_qrx_ev, 832638bddc9SAndrew Rybchenko .qpurge = sfc_ef10_rx_qpurge, 833638bddc9SAndrew Rybchenko .supported_ptypes_get = sfc_ef10_supported_ptypes_get, 834638bddc9SAndrew Rybchenko .qdesc_npending = sfc_ef10_rx_qdesc_npending, 8351d8f3a80SIvan Malov .qdesc_status = sfc_ef10_rx_qdesc_status, 8361245e3faSGeorgiy Levashov .intr_enable = sfc_ef10_rx_intr_enable, 8371245e3faSGeorgiy Levashov .intr_disable = sfc_ef10_rx_intr_disable, 838638bddc9SAndrew Rybchenko .pkt_burst = sfc_ef10_recv_pkts, 839638bddc9SAndrew Rybchenko }; 840