Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2013-2016 Intel Corporation
3 : : */
4 : :
5 : : #include <inttypes.h>
6 : :
7 : : #include <ethdev_driver.h>
8 : : #include <rte_common.h>
9 : : #include <rte_net.h>
10 : : #include "fm10k.h"
11 : : #include "base/fm10k_type.h"
12 : :
13 : : #ifdef RTE_PMD_PACKET_PREFETCH
14 : : #define rte_packet_prefetch(p) rte_prefetch1(p)
15 : : #else
16 : : #define rte_packet_prefetch(p) do {} while (0)
17 : : #endif
18 : :
19 : : #ifdef RTE_ETHDEV_DEBUG_RX
20 : : static inline void dump_rxd(union fm10k_rx_desc *rxd)
21 : : {
22 : : PMD_RX_LOG(DEBUG, "+----------------|----------------+");
23 : : PMD_RX_LOG(DEBUG, "| GLORT | PKT HDR & TYPE |");
24 : : PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", rxd->d.glort,
25 : : rxd->d.data);
26 : : PMD_RX_LOG(DEBUG, "+----------------|----------------+");
27 : : PMD_RX_LOG(DEBUG, "| VLAN & LEN | STATUS |");
28 : : PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", rxd->d.vlan_len,
29 : : rxd->d.staterr);
30 : : PMD_RX_LOG(DEBUG, "+----------------|----------------+");
31 : : PMD_RX_LOG(DEBUG, "| RESERVED | RSS_HASH |");
32 : : PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", 0, rxd->d.rss);
33 : : PMD_RX_LOG(DEBUG, "+----------------|----------------+");
34 : : PMD_RX_LOG(DEBUG, "| TIME TAG |");
35 : : PMD_RX_LOG(DEBUG, "| 0x%016"PRIx64" |", rxd->q.timestamp);
36 : : PMD_RX_LOG(DEBUG, "+----------------|----------------+");
37 : : }
38 : : #endif
39 : :
40 : : #define FM10K_TX_OFFLOAD_MASK (RTE_MBUF_F_TX_VLAN | \
41 : : RTE_MBUF_F_TX_IPV6 | \
42 : : RTE_MBUF_F_TX_IPV4 | \
43 : : RTE_MBUF_F_TX_IP_CKSUM | \
44 : : RTE_MBUF_F_TX_L4_MASK | \
45 : : RTE_MBUF_F_TX_TCP_SEG)
46 : :
47 : : #define FM10K_TX_OFFLOAD_NOTSUP_MASK \
48 : : (RTE_MBUF_F_TX_OFFLOAD_MASK ^ FM10K_TX_OFFLOAD_MASK)
49 : :
50 : : /* @note: When this function is changed, make corresponding change to
51 : : * fm10k_dev_supported_ptypes_get()
52 : : */
53 : : static inline void
54 : 0 : rx_desc_to_ol_flags(struct rte_mbuf *m, const union fm10k_rx_desc *d)
55 : : {
56 : : static const alignas(RTE_CACHE_LINE_SIZE) uint32_t
57 : : ptype_table[FM10K_RXD_PKTTYPE_MASK >> FM10K_RXD_PKTTYPE_SHIFT] = {
58 : : [FM10K_PKTTYPE_OTHER] = RTE_PTYPE_L2_ETHER,
59 : : [FM10K_PKTTYPE_IPV4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4,
60 : : [FM10K_PKTTYPE_IPV4_EX] = RTE_PTYPE_L2_ETHER |
61 : : RTE_PTYPE_L3_IPV4_EXT,
62 : : [FM10K_PKTTYPE_IPV6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6,
63 : : [FM10K_PKTTYPE_IPV6_EX] = RTE_PTYPE_L2_ETHER |
64 : : RTE_PTYPE_L3_IPV6_EXT,
65 : : [FM10K_PKTTYPE_IPV4 | FM10K_PKTTYPE_TCP] = RTE_PTYPE_L2_ETHER |
66 : : RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
67 : : [FM10K_PKTTYPE_IPV6 | FM10K_PKTTYPE_TCP] = RTE_PTYPE_L2_ETHER |
68 : : RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP,
69 : : [FM10K_PKTTYPE_IPV4 | FM10K_PKTTYPE_UDP] = RTE_PTYPE_L2_ETHER |
70 : : RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_UDP,
71 : : [FM10K_PKTTYPE_IPV6 | FM10K_PKTTYPE_UDP] = RTE_PTYPE_L2_ETHER |
72 : : RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_UDP,
73 : : };
74 : :
75 : 0 : m->packet_type = ptype_table[(d->w.pkt_info & FM10K_RXD_PKTTYPE_MASK)
76 : 0 : >> FM10K_RXD_PKTTYPE_SHIFT];
77 : :
78 [ # # ]: 0 : if (d->w.pkt_info & FM10K_RXD_RSSTYPE_MASK)
79 : 0 : m->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
80 : :
81 [ # # ]: 0 : if (unlikely((d->d.staterr &
82 : : (FM10K_RXD_STATUS_IPCS | FM10K_RXD_STATUS_IPE)) ==
83 : : (FM10K_RXD_STATUS_IPCS | FM10K_RXD_STATUS_IPE)))
84 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;
85 : : else
86 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD;
87 : :
88 [ # # ]: 0 : if (unlikely((d->d.staterr &
89 : : (FM10K_RXD_STATUS_L4CS | FM10K_RXD_STATUS_L4E)) ==
90 : : (FM10K_RXD_STATUS_L4CS | FM10K_RXD_STATUS_L4E)))
91 : 0 : m->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD;
92 : : else
93 : 0 : m->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD;
94 : 0 : }
95 : :
96 : : uint16_t
97 : 0 : fm10k_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
98 : : uint16_t nb_pkts)
99 : : {
100 : : struct rte_mbuf *mbuf;
101 : : union fm10k_rx_desc desc;
102 : : struct fm10k_rx_queue *q = rx_queue;
103 : : uint16_t count = 0;
104 : : int alloc = 0;
105 : : uint16_t next_dd;
106 : : int ret;
107 : :
108 : 0 : next_dd = q->next_dd;
109 : :
110 : 0 : nb_pkts = RTE_MIN(nb_pkts, q->alloc_thresh);
111 [ # # ]: 0 : for (count = 0; count < nb_pkts; ++count) {
112 [ # # ]: 0 : if (!(q->hw_ring[next_dd].d.staterr & FM10K_RXD_STATUS_DD))
113 : : break;
114 : 0 : mbuf = q->sw_ring[next_dd];
115 : 0 : desc = q->hw_ring[next_dd];
116 : : #ifdef RTE_ETHDEV_DEBUG_RX
117 : : dump_rxd(&desc);
118 : : #endif
119 : 0 : rte_pktmbuf_pkt_len(mbuf) = desc.w.length;
120 : 0 : rte_pktmbuf_data_len(mbuf) = desc.w.length;
121 : :
122 : 0 : mbuf->ol_flags = 0;
123 : : #ifdef RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE
124 : 0 : rx_desc_to_ol_flags(mbuf, &desc);
125 : : #endif
126 : :
127 : 0 : mbuf->hash.rss = desc.d.rss;
128 : : /**
129 : : * Packets in fm10k device always carry at least one VLAN tag.
130 : : * For those packets coming in without VLAN tag,
131 : : * the port default VLAN tag will be used.
132 : : * So, always RTE_MBUF_F_RX_VLAN flag is set and vlan_tci
133 : : * is valid for each RX packet's mbuf.
134 : : */
135 : 0 : mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
136 : 0 : mbuf->vlan_tci = desc.w.vlan;
137 : : /**
138 : : * mbuf->vlan_tci_outer is an idle field in fm10k driver,
139 : : * so it can be selected to store sglort value.
140 : : */
141 [ # # ]: 0 : if (q->rx_ftag_en)
142 : 0 : mbuf->vlan_tci_outer = rte_le_to_cpu_16(desc.w.sglort);
143 : :
144 : 0 : rx_pkts[count] = mbuf;
145 [ # # ]: 0 : if (++next_dd == q->nb_desc) {
146 : : next_dd = 0;
147 : : alloc = 1;
148 : : }
149 : :
150 : : /* Prefetch next mbuf while processing current one. */
151 : 0 : rte_prefetch0(q->sw_ring[next_dd]);
152 : :
153 : : /*
154 : : * When next RX descriptor is on a cache-line boundary,
155 : : * prefetch the next 4 RX descriptors and the next 8 pointers
156 : : * to mbufs.
157 : : */
158 [ # # ]: 0 : if ((next_dd & 0x3) == 0) {
159 : 0 : rte_prefetch0(&q->hw_ring[next_dd]);
160 : : rte_prefetch0(&q->sw_ring[next_dd]);
161 : : }
162 : : }
163 : :
164 : 0 : q->next_dd = next_dd;
165 : :
166 [ # # # # ]: 0 : if ((q->next_dd > q->next_trigger) || (alloc == 1)) {
167 : 0 : ret = rte_mempool_get_bulk(q->mp,
168 : 0 : (void **)&q->sw_ring[q->next_alloc],
169 [ # # ]: 0 : q->alloc_thresh);
170 : :
171 [ # # ]: 0 : if (unlikely(ret != 0)) {
172 : 0 : uint16_t port = q->port_id;
173 : : PMD_RX_LOG(ERR, "Failed to alloc mbuf");
174 : : /*
175 : : * Need to restore next_dd if we cannot allocate new
176 : : * buffers to replenish the old ones.
177 : : */
178 : 0 : q->next_dd = (q->next_dd + q->nb_desc - count) %
179 : : q->nb_desc;
180 : 0 : rte_eth_devices[port].data->rx_mbuf_alloc_failed++;
181 : 0 : return 0;
182 : : }
183 : :
184 [ # # ]: 0 : for (; q->next_alloc <= q->next_trigger; ++q->next_alloc) {
185 : 0 : mbuf = q->sw_ring[q->next_alloc];
186 : :
187 : : /* setup static mbuf fields */
188 : 0 : fm10k_pktmbuf_reset(mbuf, q->port_id);
189 : :
190 : : /* write descriptor */
191 : 0 : desc.q.pkt_addr = MBUF_DMA_ADDR_DEFAULT(mbuf);
192 : 0 : desc.q.hdr_addr = MBUF_DMA_ADDR_DEFAULT(mbuf);
193 : 0 : q->hw_ring[q->next_alloc] = desc;
194 : : }
195 : 0 : FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_trigger);
196 : 0 : q->next_trigger += q->alloc_thresh;
197 [ # # ]: 0 : if (q->next_trigger >= q->nb_desc) {
198 : 0 : q->next_trigger = q->alloc_thresh - 1;
199 : 0 : q->next_alloc = 0;
200 : : }
201 : : }
202 : :
203 : : return count;
204 : : }
205 : :
206 : : uint16_t
207 : 0 : fm10k_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
208 : : uint16_t nb_pkts)
209 : : {
210 : : struct rte_mbuf *mbuf;
211 : : union fm10k_rx_desc desc;
212 : : struct fm10k_rx_queue *q = rx_queue;
213 : : uint16_t count = 0;
214 : : uint16_t nb_rcv, nb_seg;
215 : : int alloc = 0;
216 : : uint16_t next_dd;
217 : 0 : struct rte_mbuf *first_seg = q->pkt_first_seg;
218 : 0 : struct rte_mbuf *last_seg = q->pkt_last_seg;
219 : : int ret;
220 : :
221 : 0 : next_dd = q->next_dd;
222 : : nb_rcv = 0;
223 : :
224 : 0 : nb_seg = RTE_MIN(nb_pkts, q->alloc_thresh);
225 [ # # ]: 0 : for (count = 0; count < nb_seg; count++) {
226 [ # # ]: 0 : if (!(q->hw_ring[next_dd].d.staterr & FM10K_RXD_STATUS_DD))
227 : : break;
228 : 0 : mbuf = q->sw_ring[next_dd];
229 : 0 : desc = q->hw_ring[next_dd];
230 : : #ifdef RTE_ETHDEV_DEBUG_RX
231 : : dump_rxd(&desc);
232 : : #endif
233 : :
234 [ # # ]: 0 : if (++next_dd == q->nb_desc) {
235 : : next_dd = 0;
236 : : alloc = 1;
237 : : }
238 : :
239 : : /* Prefetch next mbuf while processing current one. */
240 : 0 : rte_prefetch0(q->sw_ring[next_dd]);
241 : :
242 : : /*
243 : : * When next RX descriptor is on a cache-line boundary,
244 : : * prefetch the next 4 RX descriptors and the next 8 pointers
245 : : * to mbufs.
246 : : */
247 [ # # ]: 0 : if ((next_dd & 0x3) == 0) {
248 : 0 : rte_prefetch0(&q->hw_ring[next_dd]);
249 : : rte_prefetch0(&q->sw_ring[next_dd]);
250 : : }
251 : :
252 : : /* Fill data length */
253 : 0 : rte_pktmbuf_data_len(mbuf) = desc.w.length;
254 : :
255 : : /*
256 : : * If this is the first buffer of the received packet,
257 : : * set the pointer to the first mbuf of the packet and
258 : : * initialize its context.
259 : : * Otherwise, update the total length and the number of segments
260 : : * of the current scattered packet, and update the pointer to
261 : : * the last mbuf of the current packet.
262 : : */
263 [ # # ]: 0 : if (!first_seg) {
264 : : first_seg = mbuf;
265 : 0 : first_seg->pkt_len = desc.w.length;
266 : : } else {
267 : 0 : first_seg->pkt_len =
268 : 0 : (uint16_t)(first_seg->pkt_len +
269 : : rte_pktmbuf_data_len(mbuf));
270 : 0 : first_seg->nb_segs++;
271 : 0 : last_seg->next = mbuf;
272 : : }
273 : :
274 : : /*
275 : : * If this is not the last buffer of the received packet,
276 : : * update the pointer to the last mbuf of the current scattered
277 : : * packet and continue to parse the RX ring.
278 : : */
279 [ # # ]: 0 : if (!(desc.d.staterr & FM10K_RXD_STATUS_EOP)) {
280 : : last_seg = mbuf;
281 : 0 : continue;
282 : : }
283 : :
284 : 0 : first_seg->ol_flags = 0;
285 : : #ifdef RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE
286 : 0 : rx_desc_to_ol_flags(first_seg, &desc);
287 : : #endif
288 : 0 : first_seg->hash.rss = desc.d.rss;
289 : : /**
290 : : * Packets in fm10k device always carry at least one VLAN tag.
291 : : * For those packets coming in without VLAN tag,
292 : : * the port default VLAN tag will be used.
293 : : * So, always RTE_MBUF_F_RX_VLAN flag is set and vlan_tci
294 : : * is valid for each RX packet's mbuf.
295 : : */
296 : 0 : first_seg->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
297 : 0 : first_seg->vlan_tci = desc.w.vlan;
298 : : /**
299 : : * mbuf->vlan_tci_outer is an idle field in fm10k driver,
300 : : * so it can be selected to store sglort value.
301 : : */
302 [ # # ]: 0 : if (q->rx_ftag_en)
303 : 0 : first_seg->vlan_tci_outer =
304 : 0 : rte_le_to_cpu_16(desc.w.sglort);
305 : :
306 : : /* Prefetch data of first segment, if configured to do so. */
307 : 0 : rte_packet_prefetch((char *)first_seg->buf_addr +
308 : : first_seg->data_off);
309 : :
310 : : /*
311 : : * Store the mbuf address into the next entry of the array
312 : : * of returned packets.
313 : : */
314 : 0 : rx_pkts[nb_rcv++] = first_seg;
315 : :
316 : : /*
317 : : * Setup receipt context for a new packet.
318 : : */
319 : : first_seg = NULL;
320 : : }
321 : :
322 : 0 : q->next_dd = next_dd;
323 : :
324 [ # # # # ]: 0 : if ((q->next_dd > q->next_trigger) || (alloc == 1)) {
325 : 0 : ret = rte_mempool_get_bulk(q->mp,
326 : 0 : (void **)&q->sw_ring[q->next_alloc],
327 [ # # ]: 0 : q->alloc_thresh);
328 : :
329 [ # # ]: 0 : if (unlikely(ret != 0)) {
330 : 0 : uint16_t port = q->port_id;
331 : : PMD_RX_LOG(ERR, "Failed to alloc mbuf");
332 : : /*
333 : : * Need to restore next_dd if we cannot allocate new
334 : : * buffers to replenish the old ones.
335 : : */
336 : 0 : q->next_dd = (q->next_dd + q->nb_desc - count) %
337 : : q->nb_desc;
338 : 0 : rte_eth_devices[port].data->rx_mbuf_alloc_failed++;
339 : 0 : return 0;
340 : : }
341 : :
342 [ # # ]: 0 : for (; q->next_alloc <= q->next_trigger; ++q->next_alloc) {
343 : 0 : mbuf = q->sw_ring[q->next_alloc];
344 : :
345 : : /* setup static mbuf fields */
346 : 0 : fm10k_pktmbuf_reset(mbuf, q->port_id);
347 : :
348 : : /* write descriptor */
349 : 0 : desc.q.pkt_addr = MBUF_DMA_ADDR_DEFAULT(mbuf);
350 : 0 : desc.q.hdr_addr = MBUF_DMA_ADDR_DEFAULT(mbuf);
351 : 0 : q->hw_ring[q->next_alloc] = desc;
352 : : }
353 : 0 : FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_trigger);
354 : 0 : q->next_trigger += q->alloc_thresh;
355 [ # # ]: 0 : if (q->next_trigger >= q->nb_desc) {
356 : 0 : q->next_trigger = q->alloc_thresh - 1;
357 : 0 : q->next_alloc = 0;
358 : : }
359 : : }
360 : :
361 : 0 : q->pkt_first_seg = first_seg;
362 : 0 : q->pkt_last_seg = last_seg;
363 : :
364 : 0 : return nb_rcv;
365 : : }
366 : :
367 : : uint32_t
368 : 0 : fm10k_dev_rx_queue_count(void *rx_queue)
369 : : {
370 : : #define FM10K_RXQ_SCAN_INTERVAL 4
371 : : volatile union fm10k_rx_desc *rxdp;
372 : : struct fm10k_rx_queue *rxq;
373 : : uint16_t desc = 0;
374 : :
375 : : rxq = rx_queue;
376 : 0 : rxdp = &rxq->hw_ring[rxq->next_dd];
377 [ # # ]: 0 : while ((desc < rxq->nb_desc) &&
378 [ # # ]: 0 : rxdp->w.status & rte_cpu_to_le_16(FM10K_RXD_STATUS_DD)) {
379 : : /**
380 : : * Check the DD bit of a rx descriptor of each group of 4 desc,
381 : : * to avoid checking too frequently and downgrading performance
382 : : * too much.
383 : : */
384 : 0 : desc += FM10K_RXQ_SCAN_INTERVAL;
385 : 0 : rxdp += FM10K_RXQ_SCAN_INTERVAL;
386 [ # # ]: 0 : if (rxq->next_dd + desc >= rxq->nb_desc)
387 : 0 : rxdp = &rxq->hw_ring[rxq->next_dd + desc -
388 : : rxq->nb_desc];
389 : : }
390 : :
391 : 0 : return desc;
392 : : }
393 : :
394 : : int
395 : 0 : fm10k_dev_rx_descriptor_status(void *rx_queue, uint16_t offset)
396 : : {
397 : : volatile union fm10k_rx_desc *rxdp;
398 : : struct fm10k_rx_queue *rxq = rx_queue;
399 : : uint16_t nb_hold, trigger_last;
400 : : uint16_t desc;
401 : : int ret;
402 : :
403 [ # # ]: 0 : if (unlikely(offset >= rxq->nb_desc)) {
404 : 0 : PMD_DRV_LOG(ERR, "Invalid RX descriptor offset %u", offset);
405 : 0 : return 0;
406 : : }
407 : :
408 [ # # ]: 0 : if (rxq->next_trigger < rxq->alloc_thresh)
409 : 0 : trigger_last = rxq->next_trigger +
410 : : rxq->nb_desc - rxq->alloc_thresh;
411 : : else
412 : 0 : trigger_last = rxq->next_trigger - rxq->alloc_thresh;
413 : :
414 [ # # ]: 0 : if (rxq->next_dd < trigger_last)
415 : 0 : nb_hold = rxq->next_dd + rxq->nb_desc - trigger_last;
416 : : else
417 : 0 : nb_hold = rxq->next_dd - trigger_last;
418 : :
419 [ # # ]: 0 : if (offset >= rxq->nb_desc - nb_hold)
420 : : return RTE_ETH_RX_DESC_UNAVAIL;
421 : :
422 : 0 : desc = rxq->next_dd + offset;
423 [ # # ]: 0 : if (desc >= rxq->nb_desc)
424 : 0 : desc -= rxq->nb_desc;
425 : :
426 : 0 : rxdp = &rxq->hw_ring[desc];
427 : :
428 : 0 : ret = !!(rxdp->w.status &
429 : : rte_cpu_to_le_16(FM10K_RXD_STATUS_DD));
430 : :
431 : 0 : return ret;
432 : : }
433 : :
434 : : int
435 : 0 : fm10k_dev_tx_descriptor_status(void *tx_queue, uint16_t offset)
436 : : {
437 : : volatile struct fm10k_tx_desc *txdp;
438 : : struct fm10k_tx_queue *txq = tx_queue;
439 : : uint16_t desc;
440 : 0 : uint16_t next_rs = txq->nb_desc;
441 : 0 : struct fifo rs_tracker = txq->rs_tracker;
442 : : struct fifo *r = &rs_tracker;
443 : :
444 [ # # ]: 0 : if (unlikely(offset >= txq->nb_desc))
445 : : return -EINVAL;
446 : :
447 : 0 : desc = txq->next_free + offset;
448 : : /* go to next desc that has the RS bit */
449 : 0 : desc = (desc / txq->rs_thresh + 1) *
450 : 0 : txq->rs_thresh - 1;
451 : :
452 [ # # ]: 0 : if (desc >= txq->nb_desc) {
453 : 0 : desc -= txq->nb_desc;
454 [ # # ]: 0 : if (desc >= txq->nb_desc)
455 : 0 : desc -= txq->nb_desc;
456 : : }
457 : :
458 : : r->head = r->list;
459 [ # # ]: 0 : for ( ; r->head != r->endp; ) {
460 [ # # ]: 0 : if (*r->head >= desc && *r->head < next_rs)
461 : : next_rs = *r->head;
462 : 0 : ++r->head;
463 : : }
464 : :
465 : 0 : txdp = &txq->hw_ring[next_rs];
466 [ # # ]: 0 : if (txdp->flags & FM10K_TXD_FLAG_DONE)
467 : 0 : return RTE_ETH_TX_DESC_DONE;
468 : :
469 : : return RTE_ETH_TX_DESC_FULL;
470 : : }
471 : :
472 : : /*
473 : : * Free multiple TX mbuf at a time if they are in the same pool
474 : : *
475 : : * @txep: software desc ring index that starts to free
476 : : * @num: number of descs to free
477 : : *
478 : : */
479 : 0 : static inline void tx_free_bulk_mbuf(struct rte_mbuf **txep, int num)
480 : : {
481 : : struct rte_mbuf *m, *free[RTE_FM10K_TX_MAX_FREE_BUF_SZ];
482 : : int i;
483 : : int nb_free = 0;
484 : :
485 [ # # ]: 0 : if (unlikely(num == 0))
486 : 0 : return;
487 : :
488 : 0 : m = rte_pktmbuf_prefree_seg(txep[0]);
489 [ # # ]: 0 : if (likely(m != NULL)) {
490 : 0 : free[0] = m;
491 : : nb_free = 1;
492 [ # # ]: 0 : for (i = 1; i < num; i++) {
493 : 0 : m = rte_pktmbuf_prefree_seg(txep[i]);
494 [ # # ]: 0 : if (likely(m != NULL)) {
495 [ # # ]: 0 : if (likely(m->pool == free[0]->pool))
496 : 0 : free[nb_free++] = m;
497 : : else {
498 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool,
499 : : (void *)free, nb_free);
500 : 0 : free[0] = m;
501 : : nb_free = 1;
502 : : }
503 : : }
504 : 0 : txep[i] = NULL;
505 : : }
506 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool, (void **)free, nb_free);
507 : : } else {
508 [ # # ]: 0 : for (i = 1; i < num; i++) {
509 : 0 : m = rte_pktmbuf_prefree_seg(txep[i]);
510 [ # # ]: 0 : if (m != NULL)
511 [ # # ]: 0 : rte_mempool_put(m->pool, m);
512 : 0 : txep[i] = NULL;
513 : : }
514 : : }
515 : : }
516 : :
517 [ # # ]: 0 : static inline void tx_free_descriptors(struct fm10k_tx_queue *q)
518 : : {
519 : : uint16_t next_rs, count = 0;
520 : :
521 : : next_rs = fifo_peek(&q->rs_tracker);
522 [ # # ]: 0 : if (!(q->hw_ring[next_rs].flags & FM10K_TXD_FLAG_DONE))
523 : : return;
524 : :
525 : : /* the DONE flag is set on this descriptor so remove the ID
526 : : * from the RS bit tracker and free the buffers */
527 : : fifo_remove(&q->rs_tracker);
528 : :
529 : : /* wrap around? if so, free buffers from last_free up to but NOT
530 : : * including nb_desc */
531 [ # # ]: 0 : if (q->last_free > next_rs) {
532 : 0 : count = q->nb_desc - q->last_free;
533 : 0 : tx_free_bulk_mbuf(&q->sw_ring[q->last_free], count);
534 : 0 : q->last_free = 0;
535 : : }
536 : :
537 : : /* adjust free descriptor count before the next loop */
538 : 0 : q->nb_free += count + (next_rs + 1 - q->last_free);
539 : :
540 : : /* free buffers from last_free, up to and including next_rs */
541 [ # # ]: 0 : if (q->last_free <= next_rs) {
542 : 0 : count = next_rs - q->last_free + 1;
543 : 0 : tx_free_bulk_mbuf(&q->sw_ring[q->last_free], count);
544 : 0 : q->last_free += count;
545 : : }
546 : :
547 [ # # ]: 0 : if (q->last_free == q->nb_desc)
548 : 0 : q->last_free = 0;
549 : : }
550 : :
551 : 0 : static inline void tx_xmit_pkt(struct fm10k_tx_queue *q, struct rte_mbuf *mb)
552 : : {
553 : : uint16_t last_id;
554 : : uint8_t flags, hdrlen;
555 : :
556 : : /* always set the LAST flag on the last descriptor used to
557 : : * transmit the packet */
558 : : flags = FM10K_TXD_FLAG_LAST;
559 : 0 : last_id = q->next_free + mb->nb_segs - 1;
560 [ # # ]: 0 : if (last_id >= q->nb_desc)
561 : 0 : last_id = last_id - q->nb_desc;
562 : :
563 : : /* but only set the RS flag on the last descriptor if rs_thresh
564 : : * descriptors will be used since the RS flag was last set */
565 [ # # ]: 0 : if ((q->nb_used + mb->nb_segs) >= q->rs_thresh) {
566 : : flags |= FM10K_TXD_FLAG_RS;
567 : : fifo_insert(&q->rs_tracker, last_id);
568 : 0 : q->nb_used = 0;
569 : : } else {
570 : 0 : q->nb_used = q->nb_used + mb->nb_segs;
571 : : }
572 : :
573 : 0 : q->nb_free -= mb->nb_segs;
574 : :
575 : 0 : q->hw_ring[q->next_free].flags = 0;
576 [ # # ]: 0 : if (q->tx_ftag_en)
577 : 0 : q->hw_ring[q->next_free].flags |= FM10K_TXD_FLAG_FTAG;
578 : : /* set checksum flags on first descriptor of packet. SCTP checksum
579 : : * offload is not supported, but we do not explicitly check for this
580 : : * case in favor of greatly simplified processing. */
581 [ # # ]: 0 : if (mb->ol_flags & (RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_L4_MASK | RTE_MBUF_F_TX_TCP_SEG))
582 : 0 : q->hw_ring[q->next_free].flags |= FM10K_TXD_FLAG_CSUM;
583 : :
584 : : /* set vlan if requested */
585 [ # # ]: 0 : if (mb->ol_flags & RTE_MBUF_F_TX_VLAN)
586 : 0 : q->hw_ring[q->next_free].vlan = mb->vlan_tci;
587 : : else
588 : 0 : q->hw_ring[q->next_free].vlan = 0;
589 : :
590 : 0 : q->sw_ring[q->next_free] = mb;
591 : 0 : q->hw_ring[q->next_free].buffer_addr =
592 : 0 : rte_cpu_to_le_64(MBUF_DMA_ADDR(mb));
593 : 0 : q->hw_ring[q->next_free].buflen =
594 : 0 : rte_cpu_to_le_16(rte_pktmbuf_data_len(mb));
595 : :
596 [ # # ]: 0 : if (mb->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
597 : 0 : hdrlen = mb->l2_len + mb->l3_len + mb->l4_len;
598 [ # # ]: 0 : hdrlen += (mb->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) ?
599 : 0 : mb->outer_l2_len + mb->outer_l3_len : 0;
600 [ # # ]: 0 : if (q->hw_ring[q->next_free].flags & FM10K_TXD_FLAG_FTAG)
601 : 0 : hdrlen += sizeof(struct fm10k_ftag);
602 : :
603 [ # # # # ]: 0 : if (likely((hdrlen >= FM10K_TSO_MIN_HEADERLEN) &&
604 : : (hdrlen <= FM10K_TSO_MAX_HEADERLEN) &&
605 : : (mb->tso_segsz >= FM10K_TSO_MINMSS))) {
606 : 0 : q->hw_ring[q->next_free].mss = mb->tso_segsz;
607 : 0 : q->hw_ring[q->next_free].hdrlen = hdrlen;
608 : : }
609 : : }
610 : :
611 [ # # ]: 0 : if (++q->next_free == q->nb_desc)
612 : 0 : q->next_free = 0;
613 : :
614 : : /* fill up the rings */
615 [ # # ]: 0 : for (mb = mb->next; mb != NULL; mb = mb->next) {
616 : 0 : q->sw_ring[q->next_free] = mb;
617 : 0 : q->hw_ring[q->next_free].buffer_addr =
618 : 0 : rte_cpu_to_le_64(MBUF_DMA_ADDR(mb));
619 : 0 : q->hw_ring[q->next_free].buflen =
620 : 0 : rte_cpu_to_le_16(rte_pktmbuf_data_len(mb));
621 : 0 : q->hw_ring[q->next_free].flags = 0;
622 [ # # ]: 0 : if (++q->next_free == q->nb_desc)
623 : 0 : q->next_free = 0;
624 : : }
625 : :
626 : 0 : q->hw_ring[last_id].flags |= flags;
627 : 0 : }
628 : :
629 : : uint16_t
630 : 0 : fm10k_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
631 : : uint16_t nb_pkts)
632 : : {
633 : : struct fm10k_tx_queue *q = tx_queue;
634 : : struct rte_mbuf *mb;
635 : : uint16_t count;
636 : :
637 [ # # ]: 0 : for (count = 0; count < nb_pkts; ++count) {
638 : 0 : mb = tx_pkts[count];
639 : :
640 : : /* running low on descriptors? try to free some... */
641 [ # # ]: 0 : if (q->nb_free < q->free_thresh)
642 : 0 : tx_free_descriptors(q);
643 : :
644 : : /* make sure there are enough free descriptors to transmit the
645 : : * entire packet before doing anything */
646 [ # # ]: 0 : if (q->nb_free < mb->nb_segs)
647 : : break;
648 : :
649 : : /* sanity check to make sure the mbuf is valid */
650 [ # # # # ]: 0 : if ((mb->nb_segs == 0) ||
651 [ # # ]: 0 : ((mb->nb_segs > 1) && (mb->next == NULL)))
652 : : break;
653 : :
654 : : /* process the packet */
655 : 0 : tx_xmit_pkt(q, mb);
656 : : }
657 : :
658 : : /* update the tail pointer if any packets were processed */
659 [ # # ]: 0 : if (likely(count > 0))
660 : 0 : FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_free);
661 : :
662 : 0 : return count;
663 : : }
664 : :
665 : : uint16_t
666 : 0 : fm10k_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
667 : : uint16_t nb_pkts)
668 : : {
669 : : int i, ret;
670 : : struct rte_mbuf *m;
671 : :
672 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
673 : 0 : m = tx_pkts[i];
674 : :
675 [ # # ]: 0 : if ((m->ol_flags & RTE_MBUF_F_TX_TCP_SEG) &&
676 [ # # ]: 0 : (m->tso_segsz < FM10K_TSO_MINMSS)) {
677 : 0 : rte_errno = EINVAL;
678 : 0 : return i;
679 : : }
680 : :
681 [ # # ]: 0 : if (m->ol_flags & FM10K_TX_OFFLOAD_NOTSUP_MASK) {
682 : 0 : rte_errno = ENOTSUP;
683 : 0 : return i;
684 : : }
685 : :
686 : : #ifdef RTE_ETHDEV_DEBUG_TX
687 : : ret = rte_validate_tx_offload(m);
688 : : if (ret != 0) {
689 : : rte_errno = -ret;
690 : : return i;
691 : : }
692 : : #endif
693 : : ret = rte_net_intel_cksum_prepare(m);
694 [ # # ]: 0 : if (ret != 0) {
695 : 0 : rte_errno = -ret;
696 : 0 : return i;
697 : : }
698 : : }
699 : :
700 : 0 : return i;
701 : : }
|