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 : : #include <rte_vect.h>
12 : :
13 : : /* Common TX Descriptor QW1 Field Definitions */
14 : : #define CI_TXD_QW1_DTYPE_S 0
15 : : #define CI_TXD_QW1_DTYPE_M (0xFUL << CI_TXD_QW1_DTYPE_S)
16 : : #define CI_TXD_QW1_CMD_S 4
17 : : #define CI_TXD_QW1_CMD_M (0xFFFUL << CI_TXD_QW1_CMD_S)
18 : : #define CI_TXD_QW1_OFFSET_S 16
19 : : #define CI_TXD_QW1_OFFSET_M (0x3FFFFULL << CI_TXD_QW1_OFFSET_S)
20 : : #define CI_TXD_QW1_TX_BUF_SZ_S 34
21 : : #define CI_TXD_QW1_TX_BUF_SZ_M (0x3FFFULL << CI_TXD_QW1_TX_BUF_SZ_S)
22 : : #define CI_TXD_QW1_L2TAG1_S 48
23 : : #define CI_TXD_QW1_L2TAG1_M (0xFFFFULL << CI_TXD_QW1_L2TAG1_S)
24 : :
25 : : /* Common Descriptor Types */
26 : : #define CI_TX_DESC_DTYPE_DATA 0x0
27 : : #define CI_TX_DESC_DTYPE_CTX 0x1
28 : : #define CI_TX_DESC_DTYPE_DESC_DONE 0xF
29 : :
30 : : /* Common TX Descriptor Command Flags */
31 : : #define CI_TX_DESC_CMD_EOP 0x0001
32 : : #define CI_TX_DESC_CMD_RS 0x0002
33 : : #define CI_TX_DESC_CMD_ICRC 0x0004
34 : : #define CI_TX_DESC_CMD_IL2TAG1 0x0008
35 : : #define CI_TX_DESC_CMD_DUMMY 0x0010
36 : : #define CI_TX_DESC_CMD_IIPT_IPV6 0x0020
37 : : #define CI_TX_DESC_CMD_IIPT_IPV4 0x0040
38 : : #define CI_TX_DESC_CMD_IIPT_IPV4_CSUM 0x0060
39 : : #define CI_TX_DESC_CMD_L4T_EOFT_TCP 0x0100
40 : : #define CI_TX_DESC_CMD_L4T_EOFT_SCTP 0x0200
41 : : #define CI_TX_DESC_CMD_L4T_EOFT_UDP 0x0300
42 : :
43 : : /* Common TX Context Descriptor Commands */
44 : : #define CI_TX_CTX_DESC_TSO 0x01
45 : : #define CI_TX_CTX_DESC_TSYN 0x02
46 : : #define CI_TX_CTX_DESC_IL2TAG2 0x04
47 : :
48 : : /**
49 : : * L2TAG1 Field Source Selection
50 : : * Specifies which mbuf VLAN field to use for the L2TAG1 field in data descriptors.
51 : : * Context descriptor VLAN handling (L2TAG2) is managed by driver-specific callbacks.
52 : : */
53 : : enum ci_tx_l2tag1_field {
54 : : /** For VLAN (not QinQ), use L2Tag1 field in data desc */
55 : : CI_VLAN_IN_L2TAG1,
56 : :
57 : : /** For VLAN (not QinQ), use L2Tag2 field in ctx desc.
58 : : * NOTE: When set, drivers must set the VLAN tag in the context
59 : : * descriptor callback function, rather than relying on the
60 : : * common Tx code to insert it.
61 : : */
62 : : CI_VLAN_IN_L2TAG2,
63 : : };
64 : :
65 : : /* Common TX Descriptor Length Field Shifts */
66 : : #define CI_TX_DESC_LEN_MACLEN_S 0 /* 7 BITS */
67 : : #define CI_TX_DESC_LEN_IPLEN_S 7 /* 7 BITS */
68 : : #define CI_TX_DESC_LEN_L4_LEN_S 14 /* 4 BITS */
69 : :
70 : : /* Common maximum data per TX descriptor */
71 : : #define CI_MAX_DATA_PER_TXD (CI_TXD_QW1_TX_BUF_SZ_M >> CI_TXD_QW1_TX_BUF_SZ_S)
72 : :
73 : : /* Common TX maximum burst size for chunked transmission in simple paths */
74 : : #define CI_TX_MAX_BURST 32
75 : :
76 : : /* Common TX maximum free buffer size for batched bulk freeing */
77 : : #define CI_TX_MAX_FREE_BUF_SZ 64
78 : :
79 : : /* Common TX descriptor command flags for simple transmit */
80 : : #define CI_TX_DESC_CMD_DEFAULT (CI_TX_DESC_CMD_ICRC | CI_TX_DESC_CMD_EOP)
81 : :
82 : : /* Checksum offload mask to identify packets requesting offload */
83 : : #define CI_TX_CKSUM_OFFLOAD_MASK (RTE_MBUF_F_TX_IP_CKSUM | \
84 : : RTE_MBUF_F_TX_L4_MASK | \
85 : : RTE_MBUF_F_TX_TCP_SEG | \
86 : : RTE_MBUF_F_TX_UDP_SEG | \
87 : : RTE_MBUF_F_TX_OUTER_IP_CKSUM | \
88 : : RTE_MBUF_F_TX_OUTER_UDP_CKSUM)
89 : :
90 : : /**
91 : : * Common TX offload union for Intel drivers.
92 : : * Supports both basic offloads (l2_len, l3_len, l4_len, tso_segsz) and
93 : : * extended offloads (outer_l2_len, outer_l3_len) for tunneling support.
94 : : */
95 : : union ci_tx_offload {
96 : : uint64_t data;
97 : : struct {
98 : : uint64_t l2_len:7; /**< L2 (MAC) Header Length. */
99 : : uint64_t l3_len:9; /**< L3 (IP) Header Length. */
100 : : uint64_t l4_len:8; /**< L4 Header Length. */
101 : : uint64_t tso_segsz:16; /**< TCP TSO segment size */
102 : : uint64_t outer_l2_len:8; /**< outer L2 Header Length */
103 : : uint64_t outer_l3_len:16; /**< outer L3 Header Length */
104 : : };
105 : : };
106 : :
107 : : /*
108 : : * Structure of a 16-byte Tx descriptor common across i40e, ice, iavf and idpf drivers
109 : : */
110 : : struct ci_tx_desc {
111 : : uint64_t buffer_addr; /* Address of descriptor's data buf */
112 : : uint64_t cmd_type_offset_bsz;
113 : : };
114 : :
115 : : /* forward declaration of the common intel (ci) queue structure */
116 : : struct ci_tx_queue;
117 : :
118 : : /**
119 : : * Structure associated with each descriptor of the TX ring of a TX queue.
120 : : */
121 : : struct ci_tx_entry {
122 : : struct rte_mbuf *mbuf; /* mbuf associated with TX desc, if any. */
123 : : uint16_t next_id; /* Index of next descriptor in ring. */
124 : : };
125 : :
126 : : /**
127 : : * Structure associated with each descriptor of the TX ring of a TX queue in vector Tx.
128 : : */
129 : : struct ci_tx_entry_vec {
130 : : struct rte_mbuf *mbuf; /* mbuf associated with TX desc, if any. */
131 : : };
132 : :
133 : : typedef void (*ice_tx_release_mbufs_t)(struct ci_tx_queue *txq);
134 : :
135 : : struct ci_tx_queue {
136 : : union { /* TX ring virtual address */
137 : : volatile struct ci_tx_desc *ci_tx_ring;
138 : : volatile union ixgbe_adv_tx_desc *ixgbe_tx_ring;
139 : : };
140 : : volatile uint8_t *qtx_tail; /* register address of tail */
141 : : union {
142 : : struct ci_tx_entry *sw_ring; /* virtual address of SW ring */
143 : : struct ci_tx_entry_vec *sw_ring_vec;
144 : : };
145 : : /* Scalar TX path: Array tracking last_id at each RS threshold boundary */
146 : : uint16_t *rs_last_id;
147 : : uint16_t nb_tx_desc; /* number of TX descriptors */
148 : : uint16_t tx_tail; /* current value of tail register */
149 : : /* index to last TX descriptor to have been cleaned */
150 : : uint16_t last_desc_cleaned;
151 : : /* Total number of TX descriptors ready to be allocated. */
152 : : uint16_t nb_tx_free;
153 : : /* Start freeing TX buffers if there are less free descriptors than
154 : : * this value.
155 : : */
156 : : uint16_t tx_free_thresh;
157 : : /* Number of TX descriptors to use before RS bit is set. */
158 : : uint16_t tx_rs_thresh;
159 : : /* Scalar TX path: log2 of tx_rs_thresh for efficient bit operations */
160 : : uint8_t log2_rs_thresh;
161 : : uint16_t port_id; /* Device port identifier. */
162 : : uint16_t queue_id; /* TX queue index. */
163 : : uint16_t reg_idx;
164 : : uint16_t tx_next_dd;
165 : : uint16_t tx_next_rs;
166 : : /* Mempool pointer for fast release of mbufs.
167 : : * NULL if disabled, UINTPTR_MAX if enabled and not yet known.
168 : : * Set at first use (if enabled and not yet known).
169 : : */
170 : : struct rte_mempool *fast_free_mp;
171 : : uint64_t offloads;
172 : : uint64_t mbuf_errors;
173 : : rte_iova_t tx_ring_dma; /* TX ring DMA address */
174 : : bool tx_deferred_start; /* don't start this queue in dev start */
175 : : bool q_set; /* indicate if tx queue has been configured */
176 : : bool use_vec_entry; /* use sw_ring_vec (true for vector and simple paths) */
177 : : union { /* the VSI this queue belongs to */
178 : : struct i40e_vsi *i40e_vsi;
179 : : struct iavf_vsi *iavf_vsi;
180 : : struct ice_vsi *ice_vsi;
181 : : };
182 : : const struct rte_memzone *mz;
183 : :
184 : : union {
185 : : struct { /* ICE driver specific values */
186 : : struct ice_txtime *tsq; /* Tx Time based queue */
187 : : uint32_t q_teid; /* TX schedule node id. */
188 : : };
189 : : struct { /* I40E driver specific values */
190 : : uint8_t dcb_tc;
191 : : };
192 : : struct { /* iavf driver specific values */
193 : : uint16_t ipsec_crypto_pkt_md_offset;
194 : : #define IAVF_TX_FLAGS_VLAN_TAG_LOC_L2TAG1 BIT(0)
195 : : #define IAVF_TX_FLAGS_VLAN_TAG_LOC_L2TAG2 BIT(1)
196 : : uint8_t vlan_flag;
197 : : uint8_t tc;
198 : : bool use_ctx; /* with ctx info, each pkt needs two descriptors */
199 : : };
200 : : struct { /* ixgbe specific values */
201 : : const struct ixgbe_txq_ops *ops;
202 : : struct ixgbe_advctx_info *ctx_cache;
203 : : uint32_t ctx_curr;
204 : : uint8_t pthresh; /**< Prefetch threshold register. */
205 : : uint8_t hthresh; /**< Host threshold register. */
206 : : uint8_t wthresh; /**< Write-back threshold reg. */
207 : : uint8_t using_ipsec; /**< indicates that IPsec TX feature is in use */
208 : : uint8_t is_vf; /**< indicates that this is a VF queue */
209 : : uint8_t vf_ctx_initialized; /**< VF context descriptors initialized */
210 : : };
211 : : struct { /* idpf specific values */
212 : : volatile union {
213 : : struct idpf_flex_tx_sched_desc *desc_ring;
214 : : struct idpf_splitq_tx_compl_desc *compl_ring;
215 : : };
216 : : struct ci_tx_queue *complq;
217 : : void **txqs; /*only valid for split queue mode*/
218 : : uint32_t tx_start_qid;
219 : : uint32_t latch_idx; /* Tx timestamp latch index */
220 : : uint16_t sw_nb_desc;
221 : : uint16_t sw_tail;
222 : : uint16_t rs_compl_count;
223 : : uint8_t expected_gen_id;
224 : : };
225 : : };
226 : : };
227 : :
228 : : struct ci_tx_path_features {
229 : : uint32_t tx_offloads;
230 : : enum rte_vect_max_simd simd_width;
231 : : bool simple_tx;
232 : : bool ctx_desc;
233 : : bool disabled;
234 : : bool single_queue;
235 : : };
236 : :
237 : : struct ci_tx_path_info {
238 : : eth_tx_burst_t pkt_burst;
239 : : const char *info;
240 : : struct ci_tx_path_features features;
241 : : eth_tx_prep_t pkt_prep;
242 : : };
243 : :
244 : : static __rte_always_inline void
245 : : ci_tx_backlog_entry(struct ci_tx_entry *txep, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
246 : : {
247 : : for (uint16_t i = 0; i < (int)nb_pkts; ++i)
248 : : txep[i].mbuf = tx_pkts[i];
249 : : }
250 : :
251 : : static __rte_always_inline void
252 : : ci_tx_backlog_entry_vec(struct ci_tx_entry_vec *txep, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
253 : : {
254 [ # # # # : 0 : for (uint16_t i = 0; i < nb_pkts; ++i)
# # # # ]
255 : 0 : txep[i].mbuf = tx_pkts[i];
256 : : }
257 : :
258 : : #define IETH_VPMD_TX_MAX_FREE_BUF 64
259 : :
260 : : typedef int (*ci_desc_done_fn)(struct ci_tx_queue *txq, uint16_t idx);
261 : :
262 : : static __rte_always_inline int
263 : : ci_tx_free_bufs_vec(struct ci_tx_queue *txq, ci_desc_done_fn desc_done, bool ctx_descs)
264 : : {
265 : : int nb_free = 0;
266 : : struct rte_mbuf *free[IETH_VPMD_TX_MAX_FREE_BUF];
267 : : struct rte_mbuf *m;
268 : :
269 : : /* check DD bits on threshold descriptor */
270 [ # # # # : 0 : if (!desc_done(txq, txq->tx_next_dd))
# # # # ]
271 : : return 0;
272 : :
273 : 0 : const uint32_t n = txq->tx_rs_thresh >> ctx_descs;
274 : :
275 : : /* first buffer to free from S/W ring is at index
276 : : * tx_next_dd - (tx_rs_thresh - 1)
277 : : */
278 : 0 : struct ci_tx_entry_vec *txep = txq->sw_ring_vec;
279 : 0 : txep += (txq->tx_next_dd >> ctx_descs) - (n - 1);
280 : :
281 : : /* is fast-free enabled? */
282 : : struct rte_mempool *mp =
283 : 0 : likely(txq->fast_free_mp != (void *)UINTPTR_MAX) ?
284 [ # # # # : 0 : txq->fast_free_mp :
# # # # ]
285 : 0 : (txq->fast_free_mp = txep[0].mbuf->pool);
286 : :
287 [ # # # # : 0 : if (mp != NULL && (n & 31) == 0) {
# # # # #
# # # # #
# # ]
288 : : void **cache_objs;
289 : : struct rte_mempool_cache *cache = rte_mempool_default_cache(mp, rte_lcore_id());
290 : :
291 [ # # # # : 0 : if (cache == NULL)
# # # # ]
292 : 0 : goto normal;
293 : :
294 : 0 : cache_objs = &cache->objs[cache->len];
295 : :
296 [ # # # # : 0 : if (n > RTE_MEMPOOL_CACHE_MAX_SIZE) {
# # # # ]
297 : : rte_mempool_ops_enqueue_bulk(mp, (void *)txep, n);
298 : 0 : goto done;
299 : : }
300 : :
301 : : /* The cache follows the following algorithm
302 : : * 1. Add the objects to the cache
303 : : * 2. Anything greater than the cache min value (if it
304 : : * crosses the cache flush threshold) is flushed to the ring.
305 : : */
306 : : /* Add elements back into the cache */
307 : : uint32_t copied = 0;
308 : : /* n is multiple of 32 */
309 [ # # # # : 0 : while (copied < n) {
# # # # ]
310 : 0 : memcpy(&cache_objs[copied], &txep[copied], 32 * sizeof(void *));
311 : 0 : copied += 32;
312 : : }
313 : 0 : cache->len += n;
314 : :
315 [ # # # # : 0 : if (cache->len >= cache->flushthresh) {
# # # # ]
316 : 0 : rte_mempool_ops_enqueue_bulk(mp, &cache->objs[cache->size],
317 : 0 : cache->len - cache->size);
318 : 0 : cache->len = cache->size;
319 : : }
320 : 0 : goto done;
321 : : }
322 : :
323 : 0 : normal:
324 [ # # # # : 0 : m = rte_pktmbuf_prefree_seg(txep[0].mbuf);
# # # # ]
325 [ # # # # : 0 : if (likely(m)) {
# # # # ]
326 : 0 : free[0] = m;
327 : : nb_free = 1;
328 [ # # # # : 0 : for (uint32_t i = 1; i < n; i++) {
# # # # ]
329 [ # # # # : 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
# # # # ]
330 [ # # # # : 0 : if (likely(m)) {
# # # # ]
331 [ # # # # : 0 : if (likely(m->pool == free[0]->pool)) {
# # # # ]
332 : 0 : free[nb_free++] = m;
333 : : } else {
334 [ # # # # : 0 : rte_mbuf_raw_free_bulk(free[0]->pool, free, nb_free);
# # # # ]
335 : 0 : free[0] = m;
336 : : nb_free = 1;
337 : : }
338 : : }
339 : : }
340 [ # # # # : 0 : rte_mbuf_raw_free_bulk(free[0]->pool, free, nb_free);
# # # # ]
341 : : } else {
342 [ # # # # : 0 : for (uint32_t i = 1; i < n; i++) {
# # # # ]
343 [ # # # # : 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
# # # # ]
344 : : if (m)
345 [ # # # # : 0 : rte_mempool_put(m->pool, m);
# # # # ]
346 : : }
347 : : }
348 : :
349 : 0 : done:
350 : : /* buffers were freed, update counters */
351 : 0 : txq->nb_tx_free = (uint16_t)(txq->nb_tx_free + txq->tx_rs_thresh);
352 : 0 : txq->tx_next_dd = (uint16_t)(txq->tx_next_dd + txq->tx_rs_thresh);
353 [ # # # # : 0 : if (txq->tx_next_dd >= txq->nb_tx_desc)
# # # # ]
354 : 0 : txq->tx_next_dd = (uint16_t)(txq->tx_rs_thresh - 1);
355 : :
356 [ # # ]: 0 : return txq->tx_rs_thresh;
357 : : }
358 : :
359 : : static inline void
360 : 0 : ci_txq_release_all_mbufs(struct ci_tx_queue *txq, bool use_ctx)
361 : : {
362 [ # # # # ]: 0 : if (unlikely(!txq || !txq->sw_ring))
363 : : return;
364 : :
365 [ # # ]: 0 : if (!txq->use_vec_entry) {
366 : : /* Regular scalar path uses sw_ring with ci_tx_entry */
367 [ # # ]: 0 : for (uint16_t i = 0; i < txq->nb_tx_desc; i++) {
368 [ # # ]: 0 : if (txq->sw_ring[i].mbuf != NULL) {
369 : : rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
370 : 0 : txq->sw_ring[i].mbuf = NULL;
371 : : }
372 : : }
373 : : return;
374 : : }
375 : :
376 : : /**
377 : : * Vector and simple paths use sw_ring_vec (ci_tx_entry_vec).
378 : : * vPMD tx will not set sw_ring's mbuf to NULL after free,
379 : : * so determining buffers to free is a little more complex.
380 : : */
381 : 0 : const uint16_t start = (txq->tx_next_dd - txq->tx_rs_thresh + 1) >> use_ctx;
382 : 0 : const uint16_t nb_desc = txq->nb_tx_desc >> use_ctx;
383 : 0 : const uint16_t end = txq->tx_tail >> use_ctx;
384 : :
385 : : uint16_t i = start;
386 [ # # ]: 0 : if (end < i) {
387 [ # # ]: 0 : for (; i < nb_desc; i++)
388 : 0 : rte_pktmbuf_free_seg(txq->sw_ring_vec[i].mbuf);
389 : : i = 0;
390 : : }
391 [ # # ]: 0 : for (; i < end; i++)
392 : 0 : rte_pktmbuf_free_seg(txq->sw_ring_vec[i].mbuf);
393 : 0 : memset(txq->sw_ring_vec, 0, sizeof(txq->sw_ring_vec[0]) * nb_desc);
394 : : }
395 : :
396 : : /**
397 : : * Select the best matching Tx path based on features
398 : : *
399 : : * @param req_features
400 : : * The requested features for the Tx path
401 : : * @param infos
402 : : * Array of information about the available Tx paths
403 : : * @param num_paths
404 : : * Number of available paths in the infos array
405 : : * @param default_path
406 : : * Index of the default path to use if no suitable path is found
407 : : *
408 : : * @return
409 : : * The packet burst function index that best matches the requested features,
410 : : * or default_path if no suitable path is found
411 : : */
412 : : static inline int
413 : 0 : ci_tx_path_select(const struct ci_tx_path_features *req_features,
414 : : const struct ci_tx_path_info *infos,
415 : : size_t num_paths,
416 : : int default_path)
417 : : {
418 : : int idx = default_path;
419 : : const struct ci_tx_path_features *chosen_path_features = NULL;
420 : :
421 [ # # ]: 0 : for (unsigned int i = 0; i < num_paths; i++) {
422 : 0 : const struct ci_tx_path_features *path_features = &infos[i].features;
423 : :
424 : : /* Do not select a path with a NULL pkt_burst function. */
425 [ # # ]: 0 : if (infos[i].pkt_burst == NULL)
426 : 0 : continue;
427 : :
428 : : /* Do not select a disabled tx path. */
429 [ # # ]: 0 : if (path_features->disabled)
430 : 0 : continue;
431 : :
432 : : /* Do not use a simple tx path if not requested. */
433 [ # # # # ]: 0 : if (path_features->simple_tx && !req_features->simple_tx)
434 : 0 : continue;
435 : :
436 : : /* If a context descriptor is requested, ensure the path supports it. */
437 [ # # # # ]: 0 : if (!path_features->ctx_desc && req_features->ctx_desc)
438 : 0 : continue;
439 : :
440 : : /* If requested, ensure the path supports single queue TX. */
441 [ # # ]: 0 : if (path_features->single_queue != req_features->single_queue)
442 : 0 : continue;
443 : :
444 : : /* Ensure the path supports the requested TX offloads. */
445 [ # # ]: 0 : if ((path_features->tx_offloads & req_features->tx_offloads) !=
446 : : req_features->tx_offloads)
447 : 0 : continue;
448 : :
449 : : /* Ensure the path's SIMD width is compatible with the requested width. */
450 [ # # ]: 0 : if (path_features->simd_width > req_features->simd_width)
451 : 0 : continue;
452 : :
453 : : /* Do not select the path if it is less suitable than the chosen path. */
454 [ # # ]: 0 : if (chosen_path_features != NULL) {
455 : : /* Do not select paths with lower SIMD width than the chosen path. */
456 [ # # ]: 0 : if (path_features->simd_width < chosen_path_features->simd_width)
457 : 0 : continue;
458 : : /* Do not select paths with more offloads enabled than the chosen path if
459 : : * the SIMD widths are the same.
460 : : */
461 [ # # ]: 0 : if (path_features->simd_width == chosen_path_features->simd_width &&
462 : : rte_popcount32(path_features->tx_offloads) >
463 [ # # ]: 0 : rte_popcount32(chosen_path_features->tx_offloads))
464 : 0 : continue;
465 : :
466 : : /* Don't use a context descriptor unless necessary */
467 [ # # # # ]: 0 : if (path_features->ctx_desc && !chosen_path_features->ctx_desc)
468 : 0 : continue;
469 : : }
470 : :
471 : : /* Finally, select the path since it has met all the requirements. */
472 : 0 : idx = i;
473 : 0 : chosen_path_features = &infos[idx].features;
474 : : }
475 : :
476 : 0 : return idx;
477 : : }
478 : :
479 : : /* include the scalar functions at the end, so they can use the common definitions.
480 : : * This is done so drivers can use all functions just by including tx.h
481 : : */
482 : : #include "tx_scalar.h"
483 : :
484 : : #endif /* _COMMON_INTEL_TX_H_ */
|