Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2024 Intel Corporation
3 : : */
4 : :
5 : : #ifndef _COMMON_INTEL_TX_H_
6 : : #define _COMMON_INTEL_TX_H_
7 : :
8 : : #include <stdint.h>
9 : : #include <rte_mbuf.h>
10 : : #include <rte_ethdev.h>
11 : :
12 : : /* forward declaration of the common intel (ci) queue structure */
13 : : struct ci_tx_queue;
14 : :
15 : : /**
16 : : * Structure associated with each descriptor of the TX ring of a TX queue.
17 : : */
18 : : struct ci_tx_entry {
19 : : struct rte_mbuf *mbuf; /* mbuf associated with TX desc, if any. */
20 : : uint16_t next_id; /* Index of next descriptor in ring. */
21 : : uint16_t last_id; /* Index of last scattered descriptor. */
22 : : };
23 : :
24 : : /**
25 : : * Structure associated with each descriptor of the TX ring of a TX queue in vector Tx.
26 : : */
27 : : struct ci_tx_entry_vec {
28 : : struct rte_mbuf *mbuf; /* mbuf associated with TX desc, if any. */
29 : : };
30 : :
31 : : typedef void (*ice_tx_release_mbufs_t)(struct ci_tx_queue *txq);
32 : :
33 : : struct ci_tx_queue {
34 : : union { /* TX ring virtual address */
35 : : volatile struct i40e_tx_desc *i40e_tx_ring;
36 : : volatile struct iavf_tx_desc *iavf_tx_ring;
37 : : volatile struct ice_tx_desc *ice_tx_ring;
38 : : volatile struct idpf_base_tx_desc *idpf_tx_ring;
39 : : volatile union ixgbe_adv_tx_desc *ixgbe_tx_ring;
40 : : };
41 : : volatile uint8_t *qtx_tail; /* register address of tail */
42 : : union {
43 : : struct ci_tx_entry *sw_ring; /* virtual address of SW ring */
44 : : struct ci_tx_entry_vec *sw_ring_vec;
45 : : };
46 : : uint16_t nb_tx_desc; /* number of TX descriptors */
47 : : uint16_t tx_tail; /* current value of tail register */
48 : : uint16_t nb_tx_used; /* number of TX desc used since RS bit set */
49 : : /* index to last TX descriptor to have been cleaned */
50 : : uint16_t last_desc_cleaned;
51 : : /* Total number of TX descriptors ready to be allocated. */
52 : : uint16_t nb_tx_free;
53 : : /* Start freeing TX buffers if there are less free descriptors than
54 : : * this value.
55 : : */
56 : : uint16_t tx_free_thresh;
57 : : /* Number of TX descriptors to use before RS bit is set. */
58 : : uint16_t tx_rs_thresh;
59 : : uint16_t port_id; /* Device port identifier. */
60 : : uint16_t queue_id; /* TX queue index. */
61 : : uint16_t reg_idx;
62 : : uint16_t tx_next_dd;
63 : : uint16_t tx_next_rs;
64 : : uint64_t offloads;
65 : : uint64_t mbuf_errors;
66 : : rte_iova_t tx_ring_dma; /* TX ring DMA address */
67 : : bool tx_deferred_start; /* don't start this queue in dev start */
68 : : bool q_set; /* indicate if tx queue has been configured */
69 : : bool vector_tx; /* port is using vector TX */
70 : : union { /* the VSI this queue belongs to */
71 : : struct i40e_vsi *i40e_vsi;
72 : : struct iavf_vsi *iavf_vsi;
73 : : struct ice_vsi *ice_vsi;
74 : : };
75 : : const struct rte_memzone *mz;
76 : :
77 : : union {
78 : : struct { /* ICE driver specific values */
79 : : struct ice_txtime *tsq; /* Tx Time based queue */
80 : : uint32_t q_teid; /* TX schedule node id. */
81 : : };
82 : : struct { /* I40E driver specific values */
83 : : uint8_t dcb_tc;
84 : : };
85 : : struct { /* iavf driver specific values */
86 : : uint16_t ipsec_crypto_pkt_md_offset;
87 : : uint8_t rel_mbufs_type;
88 : : #define IAVF_TX_FLAGS_VLAN_TAG_LOC_L2TAG1 BIT(0)
89 : : #define IAVF_TX_FLAGS_VLAN_TAG_LOC_L2TAG2 BIT(1)
90 : : uint8_t vlan_flag;
91 : : uint8_t tc;
92 : : bool use_ctx; /* with ctx info, each pkt needs two descriptors */
93 : : };
94 : : struct { /* ixgbe specific values */
95 : : const struct ixgbe_txq_ops *ops;
96 : : struct ixgbe_advctx_info *ctx_cache;
97 : : uint32_t ctx_curr;
98 : : uint8_t pthresh; /**< Prefetch threshold register. */
99 : : uint8_t hthresh; /**< Host threshold register. */
100 : : uint8_t wthresh; /**< Write-back threshold reg. */
101 : : uint8_t using_ipsec; /**< indicates that IPsec TX feature is in use */
102 : : uint8_t is_vf; /**< indicates that this is a VF queue */
103 : : uint8_t vf_ctx_initialized; /**< VF context descriptors initialized */
104 : : };
105 : : struct { /* idpf specific values */
106 : : volatile union {
107 : : struct idpf_flex_tx_sched_desc *desc_ring;
108 : : struct idpf_splitq_tx_compl_desc *compl_ring;
109 : : };
110 : : struct ci_tx_queue *complq;
111 : : void **txqs; /*only valid for split queue mode*/
112 : : uint32_t tx_start_qid;
113 : : uint16_t sw_nb_desc;
114 : : uint16_t sw_tail;
115 : : uint16_t rs_compl_count;
116 : : uint8_t expected_gen_id;
117 : : };
118 : : };
119 : : };
120 : :
121 : : static __rte_always_inline void
122 : : ci_tx_backlog_entry(struct ci_tx_entry *txep, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
123 : : {
124 : : for (uint16_t i = 0; i < (int)nb_pkts; ++i)
125 : : txep[i].mbuf = tx_pkts[i];
126 : : }
127 : :
128 : : static __rte_always_inline void
129 : : ci_tx_backlog_entry_vec(struct ci_tx_entry_vec *txep, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
130 : : {
131 [ # # # # : 0 : for (uint16_t i = 0; i < nb_pkts; ++i)
# # # # ]
132 : 0 : txep[i].mbuf = tx_pkts[i];
133 : : }
134 : :
135 : : #define IETH_VPMD_TX_MAX_FREE_BUF 64
136 : :
137 : : typedef int (*ci_desc_done_fn)(struct ci_tx_queue *txq, uint16_t idx);
138 : :
139 : : static __rte_always_inline int
140 : : ci_tx_free_bufs_vec(struct ci_tx_queue *txq, ci_desc_done_fn desc_done, bool ctx_descs)
141 : : {
142 : : int nb_free = 0;
143 : : struct rte_mbuf *free[IETH_VPMD_TX_MAX_FREE_BUF];
144 : : struct rte_mbuf *m;
145 : :
146 : : /* check DD bits on threshold descriptor */
147 [ # # # # : 0 : if (!desc_done(txq, txq->tx_next_dd))
# # # # ]
148 : : return 0;
149 : :
150 : 0 : const uint32_t n = txq->tx_rs_thresh >> ctx_descs;
151 : :
152 : : /* first buffer to free from S/W ring is at index
153 : : * tx_next_dd - (tx_rs_thresh - 1)
154 : : */
155 : 0 : struct ci_tx_entry_vec *txep = txq->sw_ring_vec;
156 : 0 : txep += (txq->tx_next_dd >> ctx_descs) - (n - 1);
157 : :
158 [ # # # # : 0 : if (txq->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE && (n & 31) == 0) {
# # # # #
# # # # #
# # ]
159 [ # # # # : 0 : struct rte_mempool *mp = txep[0].mbuf->pool;
# # # # ]
160 : : void **cache_objs;
161 : : struct rte_mempool_cache *cache = rte_mempool_default_cache(mp, rte_lcore_id());
162 : :
163 [ # # # # : 0 : if (cache == NULL)
# # # # ]
164 : 0 : goto normal;
165 : :
166 : 0 : cache_objs = &cache->objs[cache->len];
167 : :
168 [ # # # # : 0 : if (n > RTE_MEMPOOL_CACHE_MAX_SIZE) {
# # # # ]
169 : : rte_mempool_ops_enqueue_bulk(mp, (void *)txep, n);
170 : 0 : goto done;
171 : : }
172 : :
173 : : /* The cache follows the following algorithm
174 : : * 1. Add the objects to the cache
175 : : * 2. Anything greater than the cache min value (if it
176 : : * crosses the cache flush threshold) is flushed to the ring.
177 : : */
178 : : /* Add elements back into the cache */
179 : : uint32_t copied = 0;
180 : : /* n is multiple of 32 */
181 [ # # # # : 0 : while (copied < n) {
# # # # ]
182 : 0 : memcpy(&cache_objs[copied], &txep[copied], 32 * sizeof(void *));
183 : 0 : copied += 32;
184 : : }
185 : 0 : cache->len += n;
186 : :
187 [ # # # # : 0 : if (cache->len >= cache->flushthresh) {
# # # # ]
188 : 0 : rte_mempool_ops_enqueue_bulk(mp, &cache->objs[cache->size],
189 : 0 : cache->len - cache->size);
190 : 0 : cache->len = cache->size;
191 : : }
192 : 0 : goto done;
193 : : }
194 : :
195 : 0 : normal:
196 [ # # # # : 0 : m = rte_pktmbuf_prefree_seg(txep[0].mbuf);
# # # # ]
197 [ # # # # : 0 : if (likely(m)) {
# # # # ]
198 : 0 : free[0] = m;
199 : : nb_free = 1;
200 [ # # # # : 0 : for (uint32_t i = 1; i < n; i++) {
# # # # ]
201 [ # # # # : 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
# # # # ]
202 [ # # # # : 0 : if (likely(m)) {
# # # # ]
203 [ # # # # : 0 : if (likely(m->pool == free[0]->pool)) {
# # # # ]
204 : 0 : free[nb_free++] = m;
205 : : } else {
206 [ # # # # : 0 : rte_mempool_put_bulk(free[0]->pool, (void *)free, nb_free);
# # # # ]
207 : 0 : free[0] = m;
208 : : nb_free = 1;
209 : : }
210 : : }
211 : : }
212 [ # # # # : 0 : rte_mempool_put_bulk(free[0]->pool, (void **)free, nb_free);
# # # # ]
213 : : } else {
214 [ # # # # : 0 : for (uint32_t i = 1; i < n; i++) {
# # # # ]
215 [ # # # # : 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
# # # # ]
216 [ # # # # : 0 : if (m)
# # # # ]
217 [ # # # # : 0 : rte_mempool_put(m->pool, m);
# # # # ]
218 : : }
219 : : }
220 : :
221 : 0 : done:
222 : : /* buffers were freed, update counters */
223 : 0 : txq->nb_tx_free = (uint16_t)(txq->nb_tx_free + txq->tx_rs_thresh);
224 : 0 : txq->tx_next_dd = (uint16_t)(txq->tx_next_dd + txq->tx_rs_thresh);
225 [ # # # # : 0 : if (txq->tx_next_dd >= txq->nb_tx_desc)
# # # # ]
226 : 0 : txq->tx_next_dd = (uint16_t)(txq->tx_rs_thresh - 1);
227 : :
228 : 0 : return txq->tx_rs_thresh;
229 : : }
230 : :
231 : : static inline void
232 : 0 : ci_txq_release_all_mbufs(struct ci_tx_queue *txq, bool use_ctx)
233 : : {
234 [ # # # # ]: 0 : if (unlikely(!txq || !txq->sw_ring))
235 : : return;
236 : :
237 [ # # ]: 0 : if (!txq->vector_tx) {
238 [ # # ]: 0 : for (uint16_t i = 0; i < txq->nb_tx_desc; i++) {
239 [ # # ]: 0 : if (txq->sw_ring[i].mbuf != NULL) {
240 : : rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
241 : 0 : txq->sw_ring[i].mbuf = NULL;
242 : : }
243 : : }
244 : : return;
245 : : }
246 : :
247 : : /**
248 : : * vPMD tx will not set sw_ring's mbuf to NULL after free,
249 : : * so determining buffers to free is a little more complex.
250 : : */
251 : 0 : const uint16_t start = (txq->tx_next_dd - txq->tx_rs_thresh + 1) >> use_ctx;
252 : 0 : const uint16_t nb_desc = txq->nb_tx_desc >> use_ctx;
253 : 0 : const uint16_t end = txq->tx_tail >> use_ctx;
254 : :
255 : : uint16_t i = start;
256 [ # # ]: 0 : if (end < i) {
257 [ # # ]: 0 : for (; i < nb_desc; i++)
258 : 0 : rte_pktmbuf_free_seg(txq->sw_ring_vec[i].mbuf);
259 : : i = 0;
260 : : }
261 [ # # ]: 0 : for (; i < end; i++)
262 : 0 : rte_pktmbuf_free_seg(txq->sw_ring_vec[i].mbuf);
263 : 0 : memset(txq->sw_ring_vec, 0, sizeof(txq->sw_ring_vec[0]) * nb_desc);
264 : : }
265 : :
266 : : #endif /* _COMMON_INTEL_TX_H_ */
|