1*2d9fd380Sjfb8856606 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2*2d9fd380Sjfb8856606 * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
3*2d9fd380Sjfb8856606 */
4*2d9fd380Sjfb8856606
5*2d9fd380Sjfb8856606 #include <sys/queue.h>
6*2d9fd380Sjfb8856606 #include <stdio.h>
7*2d9fd380Sjfb8856606 #include <stdlib.h>
8*2d9fd380Sjfb8856606 #include <string.h>
9*2d9fd380Sjfb8856606 #include <errno.h>
10*2d9fd380Sjfb8856606 #include <stdint.h>
11*2d9fd380Sjfb8856606 #include <stdarg.h>
12*2d9fd380Sjfb8856606 #include <unistd.h>
13*2d9fd380Sjfb8856606 #include <inttypes.h>
14*2d9fd380Sjfb8856606
15*2d9fd380Sjfb8856606 #include <rte_byteorder.h>
16*2d9fd380Sjfb8856606 #include <rte_common.h>
17*2d9fd380Sjfb8856606 #include <rte_cycles.h>
18*2d9fd380Sjfb8856606 #include <rte_log.h>
19*2d9fd380Sjfb8856606 #include <rte_debug.h>
20*2d9fd380Sjfb8856606 #include <rte_interrupts.h>
21*2d9fd380Sjfb8856606 #include <rte_pci.h>
22*2d9fd380Sjfb8856606 #include <rte_memory.h>
23*2d9fd380Sjfb8856606 #include <rte_memzone.h>
24*2d9fd380Sjfb8856606 #include <rte_launch.h>
25*2d9fd380Sjfb8856606 #include <rte_eal.h>
26*2d9fd380Sjfb8856606 #include <rte_per_lcore.h>
27*2d9fd380Sjfb8856606 #include <rte_lcore.h>
28*2d9fd380Sjfb8856606 #include <rte_atomic.h>
29*2d9fd380Sjfb8856606 #include <rte_branch_prediction.h>
30*2d9fd380Sjfb8856606 #include <rte_mempool.h>
31*2d9fd380Sjfb8856606 #include <rte_malloc.h>
32*2d9fd380Sjfb8856606 #include <rte_mbuf.h>
33*2d9fd380Sjfb8856606 #include <rte_ether.h>
34*2d9fd380Sjfb8856606 #include <rte_ethdev_driver.h>
35*2d9fd380Sjfb8856606 #include <rte_prefetch.h>
36*2d9fd380Sjfb8856606 #include <rte_udp.h>
37*2d9fd380Sjfb8856606 #include <rte_tcp.h>
38*2d9fd380Sjfb8856606 #include <rte_sctp.h>
39*2d9fd380Sjfb8856606 #include <rte_string_fns.h>
40*2d9fd380Sjfb8856606 #include <rte_errno.h>
41*2d9fd380Sjfb8856606 #include <rte_ip.h>
42*2d9fd380Sjfb8856606 #include <rte_net.h>
43*2d9fd380Sjfb8856606
44*2d9fd380Sjfb8856606 #include "ionic_logs.h"
45*2d9fd380Sjfb8856606 #include "ionic_mac_api.h"
46*2d9fd380Sjfb8856606 #include "ionic_ethdev.h"
47*2d9fd380Sjfb8856606 #include "ionic_lif.h"
48*2d9fd380Sjfb8856606 #include "ionic_rxtx.h"
49*2d9fd380Sjfb8856606
50*2d9fd380Sjfb8856606 #define IONIC_RX_RING_DOORBELL_STRIDE (32 - 1)
51*2d9fd380Sjfb8856606
52*2d9fd380Sjfb8856606 /*********************************************************************
53*2d9fd380Sjfb8856606 *
54*2d9fd380Sjfb8856606 * TX functions
55*2d9fd380Sjfb8856606 *
56*2d9fd380Sjfb8856606 **********************************************************************/
57*2d9fd380Sjfb8856606
58*2d9fd380Sjfb8856606 void
ionic_txq_info_get(struct rte_eth_dev * dev,uint16_t queue_id,struct rte_eth_txq_info * qinfo)59*2d9fd380Sjfb8856606 ionic_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
60*2d9fd380Sjfb8856606 struct rte_eth_txq_info *qinfo)
61*2d9fd380Sjfb8856606 {
62*2d9fd380Sjfb8856606 struct ionic_qcq *txq = dev->data->tx_queues[queue_id];
63*2d9fd380Sjfb8856606 struct ionic_queue *q = &txq->q;
64*2d9fd380Sjfb8856606
65*2d9fd380Sjfb8856606 qinfo->nb_desc = q->num_descs;
66*2d9fd380Sjfb8856606 qinfo->conf.offloads = txq->offloads;
67*2d9fd380Sjfb8856606 qinfo->conf.tx_deferred_start = txq->deferred_start;
68*2d9fd380Sjfb8856606 }
69*2d9fd380Sjfb8856606
70*2d9fd380Sjfb8856606 static inline void __rte_cold
ionic_tx_flush(struct ionic_cq * cq)71*2d9fd380Sjfb8856606 ionic_tx_flush(struct ionic_cq *cq)
72*2d9fd380Sjfb8856606 {
73*2d9fd380Sjfb8856606 struct ionic_queue *q = cq->bound_q;
74*2d9fd380Sjfb8856606 struct ionic_desc_info *q_desc_info;
75*2d9fd380Sjfb8856606 struct rte_mbuf *txm, *next;
76*2d9fd380Sjfb8856606 struct ionic_txq_comp *cq_desc_base = cq->base;
77*2d9fd380Sjfb8856606 struct ionic_txq_comp *cq_desc;
78*2d9fd380Sjfb8856606 u_int32_t comp_index = (u_int32_t)-1;
79*2d9fd380Sjfb8856606
80*2d9fd380Sjfb8856606 cq_desc = &cq_desc_base[cq->tail_idx];
81*2d9fd380Sjfb8856606 while (color_match(cq_desc->color, cq->done_color)) {
82*2d9fd380Sjfb8856606 cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
83*2d9fd380Sjfb8856606
84*2d9fd380Sjfb8856606 /* Prefetch the next 4 descriptors (not really useful here) */
85*2d9fd380Sjfb8856606 if ((cq->tail_idx & 0x3) == 0)
86*2d9fd380Sjfb8856606 rte_prefetch0(&cq_desc_base[cq->tail_idx]);
87*2d9fd380Sjfb8856606
88*2d9fd380Sjfb8856606 if (cq->tail_idx == 0)
89*2d9fd380Sjfb8856606 cq->done_color = !cq->done_color;
90*2d9fd380Sjfb8856606
91*2d9fd380Sjfb8856606 comp_index = cq_desc->comp_index;
92*2d9fd380Sjfb8856606
93*2d9fd380Sjfb8856606 cq_desc = &cq_desc_base[cq->tail_idx];
94*2d9fd380Sjfb8856606 }
95*2d9fd380Sjfb8856606
96*2d9fd380Sjfb8856606 if (comp_index != (u_int32_t)-1) {
97*2d9fd380Sjfb8856606 while (q->tail_idx != comp_index) {
98*2d9fd380Sjfb8856606 q_desc_info = &q->info[q->tail_idx];
99*2d9fd380Sjfb8856606
100*2d9fd380Sjfb8856606 q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
101*2d9fd380Sjfb8856606
102*2d9fd380Sjfb8856606 /* Prefetch the next 4 descriptors */
103*2d9fd380Sjfb8856606 if ((q->tail_idx & 0x3) == 0)
104*2d9fd380Sjfb8856606 /* q desc info */
105*2d9fd380Sjfb8856606 rte_prefetch0(&q->info[q->tail_idx]);
106*2d9fd380Sjfb8856606
107*2d9fd380Sjfb8856606 /*
108*2d9fd380Sjfb8856606 * Note: you can just use rte_pktmbuf_free,
109*2d9fd380Sjfb8856606 * but this loop is faster
110*2d9fd380Sjfb8856606 */
111*2d9fd380Sjfb8856606 txm = q_desc_info->cb_arg;
112*2d9fd380Sjfb8856606 while (txm != NULL) {
113*2d9fd380Sjfb8856606 next = txm->next;
114*2d9fd380Sjfb8856606 rte_pktmbuf_free_seg(txm);
115*2d9fd380Sjfb8856606 txm = next;
116*2d9fd380Sjfb8856606 }
117*2d9fd380Sjfb8856606 }
118*2d9fd380Sjfb8856606 }
119*2d9fd380Sjfb8856606 }
120*2d9fd380Sjfb8856606
121*2d9fd380Sjfb8856606 void __rte_cold
ionic_dev_tx_queue_release(void * tx_queue)122*2d9fd380Sjfb8856606 ionic_dev_tx_queue_release(void *tx_queue)
123*2d9fd380Sjfb8856606 {
124*2d9fd380Sjfb8856606 struct ionic_qcq *txq = (struct ionic_qcq *)tx_queue;
125*2d9fd380Sjfb8856606
126*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
127*2d9fd380Sjfb8856606
128*2d9fd380Sjfb8856606 ionic_qcq_free(txq);
129*2d9fd380Sjfb8856606 }
130*2d9fd380Sjfb8856606
131*2d9fd380Sjfb8856606 int __rte_cold
ionic_dev_tx_queue_stop(struct rte_eth_dev * eth_dev,uint16_t tx_queue_id)132*2d9fd380Sjfb8856606 ionic_dev_tx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id)
133*2d9fd380Sjfb8856606 {
134*2d9fd380Sjfb8856606 struct ionic_qcq *txq;
135*2d9fd380Sjfb8856606
136*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
137*2d9fd380Sjfb8856606
138*2d9fd380Sjfb8856606 txq = eth_dev->data->tx_queues[tx_queue_id];
139*2d9fd380Sjfb8856606
140*2d9fd380Sjfb8856606 /*
141*2d9fd380Sjfb8856606 * Note: we should better post NOP Tx desc and wait for its completion
142*2d9fd380Sjfb8856606 * before disabling Tx queue
143*2d9fd380Sjfb8856606 */
144*2d9fd380Sjfb8856606
145*2d9fd380Sjfb8856606 ionic_qcq_disable(txq);
146*2d9fd380Sjfb8856606
147*2d9fd380Sjfb8856606 ionic_tx_flush(&txq->cq);
148*2d9fd380Sjfb8856606
149*2d9fd380Sjfb8856606 ionic_lif_txq_deinit(txq);
150*2d9fd380Sjfb8856606
151*2d9fd380Sjfb8856606 eth_dev->data->tx_queue_state[tx_queue_id] =
152*2d9fd380Sjfb8856606 RTE_ETH_QUEUE_STATE_STOPPED;
153*2d9fd380Sjfb8856606
154*2d9fd380Sjfb8856606 return 0;
155*2d9fd380Sjfb8856606 }
156*2d9fd380Sjfb8856606
157*2d9fd380Sjfb8856606 int __rte_cold
ionic_dev_tx_queue_setup(struct rte_eth_dev * eth_dev,uint16_t tx_queue_id,uint16_t nb_desc,uint32_t socket_id __rte_unused,const struct rte_eth_txconf * tx_conf)158*2d9fd380Sjfb8856606 ionic_dev_tx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id,
159*2d9fd380Sjfb8856606 uint16_t nb_desc, uint32_t socket_id __rte_unused,
160*2d9fd380Sjfb8856606 const struct rte_eth_txconf *tx_conf)
161*2d9fd380Sjfb8856606 {
162*2d9fd380Sjfb8856606 struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
163*2d9fd380Sjfb8856606 struct ionic_qcq *txq;
164*2d9fd380Sjfb8856606 uint64_t offloads;
165*2d9fd380Sjfb8856606 int err;
166*2d9fd380Sjfb8856606
167*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
168*2d9fd380Sjfb8856606
169*2d9fd380Sjfb8856606 IONIC_PRINT(DEBUG, "Configuring TX queue %u with %u buffers",
170*2d9fd380Sjfb8856606 tx_queue_id, nb_desc);
171*2d9fd380Sjfb8856606
172*2d9fd380Sjfb8856606 if (tx_queue_id >= lif->ntxqcqs) {
173*2d9fd380Sjfb8856606 IONIC_PRINT(DEBUG, "Queue index %u not available "
174*2d9fd380Sjfb8856606 "(max %u queues)",
175*2d9fd380Sjfb8856606 tx_queue_id, lif->ntxqcqs);
176*2d9fd380Sjfb8856606 return -EINVAL;
177*2d9fd380Sjfb8856606 }
178*2d9fd380Sjfb8856606
179*2d9fd380Sjfb8856606 offloads = tx_conf->offloads | eth_dev->data->dev_conf.txmode.offloads;
180*2d9fd380Sjfb8856606
181*2d9fd380Sjfb8856606 /* Validate number of receive descriptors */
182*2d9fd380Sjfb8856606 if (!rte_is_power_of_2(nb_desc) || nb_desc < IONIC_MIN_RING_DESC)
183*2d9fd380Sjfb8856606 return -EINVAL; /* or use IONIC_DEFAULT_RING_DESC */
184*2d9fd380Sjfb8856606
185*2d9fd380Sjfb8856606 /* Free memory prior to re-allocation if needed... */
186*2d9fd380Sjfb8856606 if (eth_dev->data->tx_queues[tx_queue_id] != NULL) {
187*2d9fd380Sjfb8856606 void *tx_queue = eth_dev->data->tx_queues[tx_queue_id];
188*2d9fd380Sjfb8856606 ionic_dev_tx_queue_release(tx_queue);
189*2d9fd380Sjfb8856606 eth_dev->data->tx_queues[tx_queue_id] = NULL;
190*2d9fd380Sjfb8856606 }
191*2d9fd380Sjfb8856606
192*2d9fd380Sjfb8856606 err = ionic_tx_qcq_alloc(lif, tx_queue_id, nb_desc, &txq);
193*2d9fd380Sjfb8856606 if (err) {
194*2d9fd380Sjfb8856606 IONIC_PRINT(DEBUG, "Queue allocation failure");
195*2d9fd380Sjfb8856606 return -EINVAL;
196*2d9fd380Sjfb8856606 }
197*2d9fd380Sjfb8856606
198*2d9fd380Sjfb8856606 /* Do not start queue with rte_eth_dev_start() */
199*2d9fd380Sjfb8856606 txq->deferred_start = tx_conf->tx_deferred_start;
200*2d9fd380Sjfb8856606
201*2d9fd380Sjfb8856606 txq->offloads = offloads;
202*2d9fd380Sjfb8856606
203*2d9fd380Sjfb8856606 eth_dev->data->tx_queues[tx_queue_id] = txq;
204*2d9fd380Sjfb8856606
205*2d9fd380Sjfb8856606 return 0;
206*2d9fd380Sjfb8856606 }
207*2d9fd380Sjfb8856606
208*2d9fd380Sjfb8856606 /*
209*2d9fd380Sjfb8856606 * Start Transmit Units for specified queue.
210*2d9fd380Sjfb8856606 */
211*2d9fd380Sjfb8856606 int __rte_cold
ionic_dev_tx_queue_start(struct rte_eth_dev * eth_dev,uint16_t tx_queue_id)212*2d9fd380Sjfb8856606 ionic_dev_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id)
213*2d9fd380Sjfb8856606 {
214*2d9fd380Sjfb8856606 struct ionic_qcq *txq;
215*2d9fd380Sjfb8856606 int err;
216*2d9fd380Sjfb8856606
217*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
218*2d9fd380Sjfb8856606
219*2d9fd380Sjfb8856606 txq = eth_dev->data->tx_queues[tx_queue_id];
220*2d9fd380Sjfb8856606
221*2d9fd380Sjfb8856606 err = ionic_lif_txq_init(txq);
222*2d9fd380Sjfb8856606 if (err)
223*2d9fd380Sjfb8856606 return err;
224*2d9fd380Sjfb8856606
225*2d9fd380Sjfb8856606 ionic_qcq_enable(txq);
226*2d9fd380Sjfb8856606
227*2d9fd380Sjfb8856606 eth_dev->data->tx_queue_state[tx_queue_id] =
228*2d9fd380Sjfb8856606 RTE_ETH_QUEUE_STATE_STARTED;
229*2d9fd380Sjfb8856606
230*2d9fd380Sjfb8856606 return 0;
231*2d9fd380Sjfb8856606 }
232*2d9fd380Sjfb8856606
233*2d9fd380Sjfb8856606 static void
ionic_tx_tcp_pseudo_csum(struct rte_mbuf * txm)234*2d9fd380Sjfb8856606 ionic_tx_tcp_pseudo_csum(struct rte_mbuf *txm)
235*2d9fd380Sjfb8856606 {
236*2d9fd380Sjfb8856606 struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(txm, struct ether_hdr *);
237*2d9fd380Sjfb8856606 char *l3_hdr = ((char *)eth_hdr) + txm->l2_len;
238*2d9fd380Sjfb8856606 struct rte_tcp_hdr *tcp_hdr = (struct rte_tcp_hdr *)
239*2d9fd380Sjfb8856606 (l3_hdr + txm->l3_len);
240*2d9fd380Sjfb8856606
241*2d9fd380Sjfb8856606 if (txm->ol_flags & PKT_TX_IP_CKSUM) {
242*2d9fd380Sjfb8856606 struct rte_ipv4_hdr *ipv4_hdr = (struct rte_ipv4_hdr *)l3_hdr;
243*2d9fd380Sjfb8856606 ipv4_hdr->hdr_checksum = 0;
244*2d9fd380Sjfb8856606 tcp_hdr->cksum = 0;
245*2d9fd380Sjfb8856606 tcp_hdr->cksum = rte_ipv4_udptcp_cksum(ipv4_hdr, tcp_hdr);
246*2d9fd380Sjfb8856606 } else {
247*2d9fd380Sjfb8856606 struct rte_ipv6_hdr *ipv6_hdr = (struct rte_ipv6_hdr *)l3_hdr;
248*2d9fd380Sjfb8856606 tcp_hdr->cksum = 0;
249*2d9fd380Sjfb8856606 tcp_hdr->cksum = rte_ipv6_udptcp_cksum(ipv6_hdr, tcp_hdr);
250*2d9fd380Sjfb8856606 }
251*2d9fd380Sjfb8856606 }
252*2d9fd380Sjfb8856606
253*2d9fd380Sjfb8856606 static void
ionic_tx_tcp_inner_pseudo_csum(struct rte_mbuf * txm)254*2d9fd380Sjfb8856606 ionic_tx_tcp_inner_pseudo_csum(struct rte_mbuf *txm)
255*2d9fd380Sjfb8856606 {
256*2d9fd380Sjfb8856606 struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(txm, struct ether_hdr *);
257*2d9fd380Sjfb8856606 char *l3_hdr = ((char *)eth_hdr) + txm->outer_l2_len +
258*2d9fd380Sjfb8856606 txm->outer_l3_len + txm->l2_len;
259*2d9fd380Sjfb8856606 struct rte_tcp_hdr *tcp_hdr = (struct rte_tcp_hdr *)
260*2d9fd380Sjfb8856606 (l3_hdr + txm->l3_len);
261*2d9fd380Sjfb8856606
262*2d9fd380Sjfb8856606 if (txm->ol_flags & PKT_TX_IPV4) {
263*2d9fd380Sjfb8856606 struct rte_ipv4_hdr *ipv4_hdr = (struct rte_ipv4_hdr *)l3_hdr;
264*2d9fd380Sjfb8856606 ipv4_hdr->hdr_checksum = 0;
265*2d9fd380Sjfb8856606 tcp_hdr->cksum = 0;
266*2d9fd380Sjfb8856606 tcp_hdr->cksum = rte_ipv4_udptcp_cksum(ipv4_hdr, tcp_hdr);
267*2d9fd380Sjfb8856606 } else {
268*2d9fd380Sjfb8856606 struct rte_ipv6_hdr *ipv6_hdr = (struct rte_ipv6_hdr *)l3_hdr;
269*2d9fd380Sjfb8856606 tcp_hdr->cksum = 0;
270*2d9fd380Sjfb8856606 tcp_hdr->cksum = rte_ipv6_udptcp_cksum(ipv6_hdr, tcp_hdr);
271*2d9fd380Sjfb8856606 }
272*2d9fd380Sjfb8856606 }
273*2d9fd380Sjfb8856606
274*2d9fd380Sjfb8856606 static void
ionic_tx_tso_post(struct ionic_queue * q,struct ionic_txq_desc * desc,struct rte_mbuf * txm,rte_iova_t addr,uint8_t nsge,uint16_t len,uint32_t hdrlen,uint32_t mss,bool encap,uint16_t vlan_tci,bool has_vlan,bool start,bool done)275*2d9fd380Sjfb8856606 ionic_tx_tso_post(struct ionic_queue *q, struct ionic_txq_desc *desc,
276*2d9fd380Sjfb8856606 struct rte_mbuf *txm,
277*2d9fd380Sjfb8856606 rte_iova_t addr, uint8_t nsge, uint16_t len,
278*2d9fd380Sjfb8856606 uint32_t hdrlen, uint32_t mss,
279*2d9fd380Sjfb8856606 bool encap,
280*2d9fd380Sjfb8856606 uint16_t vlan_tci, bool has_vlan,
281*2d9fd380Sjfb8856606 bool start, bool done)
282*2d9fd380Sjfb8856606 {
283*2d9fd380Sjfb8856606 uint8_t flags = 0;
284*2d9fd380Sjfb8856606 flags |= has_vlan ? IONIC_TXQ_DESC_FLAG_VLAN : 0;
285*2d9fd380Sjfb8856606 flags |= encap ? IONIC_TXQ_DESC_FLAG_ENCAP : 0;
286*2d9fd380Sjfb8856606 flags |= start ? IONIC_TXQ_DESC_FLAG_TSO_SOT : 0;
287*2d9fd380Sjfb8856606 flags |= done ? IONIC_TXQ_DESC_FLAG_TSO_EOT : 0;
288*2d9fd380Sjfb8856606
289*2d9fd380Sjfb8856606 desc->cmd = encode_txq_desc_cmd(IONIC_TXQ_DESC_OPCODE_TSO,
290*2d9fd380Sjfb8856606 flags, nsge, addr);
291*2d9fd380Sjfb8856606 desc->len = len;
292*2d9fd380Sjfb8856606 desc->vlan_tci = vlan_tci;
293*2d9fd380Sjfb8856606 desc->hdr_len = hdrlen;
294*2d9fd380Sjfb8856606 desc->mss = mss;
295*2d9fd380Sjfb8856606
296*2d9fd380Sjfb8856606 ionic_q_post(q, done, NULL, done ? txm : NULL);
297*2d9fd380Sjfb8856606 }
298*2d9fd380Sjfb8856606
299*2d9fd380Sjfb8856606 static struct ionic_txq_desc *
ionic_tx_tso_next(struct ionic_queue * q,struct ionic_txq_sg_elem ** elem)300*2d9fd380Sjfb8856606 ionic_tx_tso_next(struct ionic_queue *q, struct ionic_txq_sg_elem **elem)
301*2d9fd380Sjfb8856606 {
302*2d9fd380Sjfb8856606 struct ionic_txq_desc *desc_base = q->base;
303*2d9fd380Sjfb8856606 struct ionic_txq_sg_desc *sg_desc_base = q->sg_base;
304*2d9fd380Sjfb8856606 struct ionic_txq_desc *desc = &desc_base[q->head_idx];
305*2d9fd380Sjfb8856606 struct ionic_txq_sg_desc *sg_desc = &sg_desc_base[q->head_idx];
306*2d9fd380Sjfb8856606
307*2d9fd380Sjfb8856606 *elem = sg_desc->elems;
308*2d9fd380Sjfb8856606 return desc;
309*2d9fd380Sjfb8856606 }
310*2d9fd380Sjfb8856606
311*2d9fd380Sjfb8856606 static int
ionic_tx_tso(struct ionic_queue * q,struct rte_mbuf * txm,uint64_t offloads __rte_unused,bool not_xmit_more)312*2d9fd380Sjfb8856606 ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm,
313*2d9fd380Sjfb8856606 uint64_t offloads __rte_unused, bool not_xmit_more)
314*2d9fd380Sjfb8856606 {
315*2d9fd380Sjfb8856606 struct ionic_tx_stats *stats = IONIC_Q_TO_TX_STATS(q);
316*2d9fd380Sjfb8856606 struct ionic_txq_desc *desc;
317*2d9fd380Sjfb8856606 struct ionic_txq_sg_elem *elem;
318*2d9fd380Sjfb8856606 struct rte_mbuf *txm_seg;
319*2d9fd380Sjfb8856606 uint64_t desc_addr = 0;
320*2d9fd380Sjfb8856606 uint16_t desc_len = 0;
321*2d9fd380Sjfb8856606 uint8_t desc_nsge;
322*2d9fd380Sjfb8856606 uint32_t hdrlen;
323*2d9fd380Sjfb8856606 uint32_t mss = txm->tso_segsz;
324*2d9fd380Sjfb8856606 uint32_t frag_left = 0;
325*2d9fd380Sjfb8856606 uint32_t left;
326*2d9fd380Sjfb8856606 uint32_t seglen;
327*2d9fd380Sjfb8856606 uint32_t len;
328*2d9fd380Sjfb8856606 uint32_t offset = 0;
329*2d9fd380Sjfb8856606 bool start, done;
330*2d9fd380Sjfb8856606 bool encap;
331*2d9fd380Sjfb8856606 bool has_vlan = !!(txm->ol_flags & PKT_TX_VLAN_PKT);
332*2d9fd380Sjfb8856606 uint16_t vlan_tci = txm->vlan_tci;
333*2d9fd380Sjfb8856606 uint64_t ol_flags = txm->ol_flags;
334*2d9fd380Sjfb8856606
335*2d9fd380Sjfb8856606 encap = ((ol_flags & PKT_TX_OUTER_IP_CKSUM) ||
336*2d9fd380Sjfb8856606 (ol_flags & PKT_TX_OUTER_UDP_CKSUM)) &&
337*2d9fd380Sjfb8856606 ((ol_flags & PKT_TX_OUTER_IPV4) ||
338*2d9fd380Sjfb8856606 (ol_flags & PKT_TX_OUTER_IPV6));
339*2d9fd380Sjfb8856606
340*2d9fd380Sjfb8856606 /* Preload inner-most TCP csum field with IP pseudo hdr
341*2d9fd380Sjfb8856606 * calculated with IP length set to zero. HW will later
342*2d9fd380Sjfb8856606 * add in length to each TCP segment resulting from the TSO.
343*2d9fd380Sjfb8856606 */
344*2d9fd380Sjfb8856606
345*2d9fd380Sjfb8856606 if (encap) {
346*2d9fd380Sjfb8856606 ionic_tx_tcp_inner_pseudo_csum(txm);
347*2d9fd380Sjfb8856606 hdrlen = txm->outer_l2_len + txm->outer_l3_len +
348*2d9fd380Sjfb8856606 txm->l2_len + txm->l3_len + txm->l4_len;
349*2d9fd380Sjfb8856606 } else {
350*2d9fd380Sjfb8856606 ionic_tx_tcp_pseudo_csum(txm);
351*2d9fd380Sjfb8856606 hdrlen = txm->l2_len + txm->l3_len + txm->l4_len;
352*2d9fd380Sjfb8856606 }
353*2d9fd380Sjfb8856606
354*2d9fd380Sjfb8856606 seglen = hdrlen + mss;
355*2d9fd380Sjfb8856606 left = txm->data_len;
356*2d9fd380Sjfb8856606
357*2d9fd380Sjfb8856606 desc = ionic_tx_tso_next(q, &elem);
358*2d9fd380Sjfb8856606 start = true;
359*2d9fd380Sjfb8856606
360*2d9fd380Sjfb8856606 /* Chop data up into desc segments */
361*2d9fd380Sjfb8856606
362*2d9fd380Sjfb8856606 while (left > 0) {
363*2d9fd380Sjfb8856606 len = RTE_MIN(seglen, left);
364*2d9fd380Sjfb8856606 frag_left = seglen - len;
365*2d9fd380Sjfb8856606 desc_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(txm));
366*2d9fd380Sjfb8856606 desc_len = len;
367*2d9fd380Sjfb8856606 desc_nsge = 0;
368*2d9fd380Sjfb8856606 left -= len;
369*2d9fd380Sjfb8856606 offset += len;
370*2d9fd380Sjfb8856606 if (txm->nb_segs > 1 && frag_left > 0)
371*2d9fd380Sjfb8856606 continue;
372*2d9fd380Sjfb8856606 done = (txm->nb_segs == 1 && left == 0);
373*2d9fd380Sjfb8856606 ionic_tx_tso_post(q, desc, txm,
374*2d9fd380Sjfb8856606 desc_addr, desc_nsge, desc_len,
375*2d9fd380Sjfb8856606 hdrlen, mss,
376*2d9fd380Sjfb8856606 encap,
377*2d9fd380Sjfb8856606 vlan_tci, has_vlan,
378*2d9fd380Sjfb8856606 start, done && not_xmit_more);
379*2d9fd380Sjfb8856606 desc = ionic_tx_tso_next(q, &elem);
380*2d9fd380Sjfb8856606 start = false;
381*2d9fd380Sjfb8856606 seglen = mss;
382*2d9fd380Sjfb8856606 }
383*2d9fd380Sjfb8856606
384*2d9fd380Sjfb8856606 /* Chop frags into desc segments */
385*2d9fd380Sjfb8856606
386*2d9fd380Sjfb8856606 txm_seg = txm->next;
387*2d9fd380Sjfb8856606 while (txm_seg != NULL) {
388*2d9fd380Sjfb8856606 offset = 0;
389*2d9fd380Sjfb8856606 left = txm_seg->data_len;
390*2d9fd380Sjfb8856606 stats->frags++;
391*2d9fd380Sjfb8856606
392*2d9fd380Sjfb8856606 while (left > 0) {
393*2d9fd380Sjfb8856606 rte_iova_t data_iova;
394*2d9fd380Sjfb8856606 data_iova = rte_mbuf_data_iova(txm_seg);
395*2d9fd380Sjfb8856606 elem->addr = rte_cpu_to_le_64(data_iova) + offset;
396*2d9fd380Sjfb8856606 if (frag_left > 0) {
397*2d9fd380Sjfb8856606 len = RTE_MIN(frag_left, left);
398*2d9fd380Sjfb8856606 frag_left -= len;
399*2d9fd380Sjfb8856606 elem->len = len;
400*2d9fd380Sjfb8856606 elem++;
401*2d9fd380Sjfb8856606 desc_nsge++;
402*2d9fd380Sjfb8856606 } else {
403*2d9fd380Sjfb8856606 len = RTE_MIN(mss, left);
404*2d9fd380Sjfb8856606 frag_left = mss - len;
405*2d9fd380Sjfb8856606 data_iova = rte_mbuf_data_iova(txm_seg);
406*2d9fd380Sjfb8856606 desc_addr = rte_cpu_to_le_64(data_iova);
407*2d9fd380Sjfb8856606 desc_len = len;
408*2d9fd380Sjfb8856606 desc_nsge = 0;
409*2d9fd380Sjfb8856606 }
410*2d9fd380Sjfb8856606 left -= len;
411*2d9fd380Sjfb8856606 offset += len;
412*2d9fd380Sjfb8856606 if (txm_seg->next != NULL && frag_left > 0)
413*2d9fd380Sjfb8856606 continue;
414*2d9fd380Sjfb8856606 done = (txm_seg->next == NULL && left == 0);
415*2d9fd380Sjfb8856606 ionic_tx_tso_post(q, desc, txm_seg,
416*2d9fd380Sjfb8856606 desc_addr, desc_nsge, desc_len,
417*2d9fd380Sjfb8856606 hdrlen, mss,
418*2d9fd380Sjfb8856606 encap,
419*2d9fd380Sjfb8856606 vlan_tci, has_vlan,
420*2d9fd380Sjfb8856606 start, done && not_xmit_more);
421*2d9fd380Sjfb8856606 desc = ionic_tx_tso_next(q, &elem);
422*2d9fd380Sjfb8856606 start = false;
423*2d9fd380Sjfb8856606 }
424*2d9fd380Sjfb8856606
425*2d9fd380Sjfb8856606 txm_seg = txm_seg->next;
426*2d9fd380Sjfb8856606 }
427*2d9fd380Sjfb8856606
428*2d9fd380Sjfb8856606 stats->tso++;
429*2d9fd380Sjfb8856606
430*2d9fd380Sjfb8856606 return 0;
431*2d9fd380Sjfb8856606 }
432*2d9fd380Sjfb8856606
433*2d9fd380Sjfb8856606 static int
ionic_tx(struct ionic_queue * q,struct rte_mbuf * txm,uint64_t offloads,bool not_xmit_more)434*2d9fd380Sjfb8856606 ionic_tx(struct ionic_queue *q, struct rte_mbuf *txm,
435*2d9fd380Sjfb8856606 uint64_t offloads, bool not_xmit_more)
436*2d9fd380Sjfb8856606 {
437*2d9fd380Sjfb8856606 struct ionic_txq_desc *desc_base = q->base;
438*2d9fd380Sjfb8856606 struct ionic_txq_sg_desc *sg_desc_base = q->sg_base;
439*2d9fd380Sjfb8856606 struct ionic_txq_desc *desc = &desc_base[q->head_idx];
440*2d9fd380Sjfb8856606 struct ionic_txq_sg_desc *sg_desc = &sg_desc_base[q->head_idx];
441*2d9fd380Sjfb8856606 struct ionic_txq_sg_elem *elem = sg_desc->elems;
442*2d9fd380Sjfb8856606 struct ionic_tx_stats *stats = IONIC_Q_TO_TX_STATS(q);
443*2d9fd380Sjfb8856606 struct rte_mbuf *txm_seg;
444*2d9fd380Sjfb8856606 bool encap;
445*2d9fd380Sjfb8856606 bool has_vlan;
446*2d9fd380Sjfb8856606 uint64_t ol_flags = txm->ol_flags;
447*2d9fd380Sjfb8856606 uint64_t addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(txm));
448*2d9fd380Sjfb8856606 uint8_t opcode = IONIC_TXQ_DESC_OPCODE_CSUM_NONE;
449*2d9fd380Sjfb8856606 uint8_t flags = 0;
450*2d9fd380Sjfb8856606
451*2d9fd380Sjfb8856606 if ((ol_flags & PKT_TX_IP_CKSUM) &&
452*2d9fd380Sjfb8856606 (offloads & DEV_TX_OFFLOAD_IPV4_CKSUM)) {
453*2d9fd380Sjfb8856606 opcode = IONIC_TXQ_DESC_OPCODE_CSUM_HW;
454*2d9fd380Sjfb8856606 flags |= IONIC_TXQ_DESC_FLAG_CSUM_L3;
455*2d9fd380Sjfb8856606 if (((ol_flags & PKT_TX_TCP_CKSUM) &&
456*2d9fd380Sjfb8856606 (offloads & DEV_TX_OFFLOAD_TCP_CKSUM)) ||
457*2d9fd380Sjfb8856606 ((ol_flags & PKT_TX_UDP_CKSUM) &&
458*2d9fd380Sjfb8856606 (offloads & DEV_TX_OFFLOAD_UDP_CKSUM)))
459*2d9fd380Sjfb8856606 flags |= IONIC_TXQ_DESC_FLAG_CSUM_L4;
460*2d9fd380Sjfb8856606 } else {
461*2d9fd380Sjfb8856606 stats->no_csum++;
462*2d9fd380Sjfb8856606 }
463*2d9fd380Sjfb8856606
464*2d9fd380Sjfb8856606 has_vlan = (ol_flags & PKT_TX_VLAN_PKT);
465*2d9fd380Sjfb8856606 encap = ((ol_flags & PKT_TX_OUTER_IP_CKSUM) ||
466*2d9fd380Sjfb8856606 (ol_flags & PKT_TX_OUTER_UDP_CKSUM)) &&
467*2d9fd380Sjfb8856606 ((ol_flags & PKT_TX_OUTER_IPV4) ||
468*2d9fd380Sjfb8856606 (ol_flags & PKT_TX_OUTER_IPV6));
469*2d9fd380Sjfb8856606
470*2d9fd380Sjfb8856606 flags |= has_vlan ? IONIC_TXQ_DESC_FLAG_VLAN : 0;
471*2d9fd380Sjfb8856606 flags |= encap ? IONIC_TXQ_DESC_FLAG_ENCAP : 0;
472*2d9fd380Sjfb8856606
473*2d9fd380Sjfb8856606 desc->cmd = encode_txq_desc_cmd(opcode, flags, txm->nb_segs - 1, addr);
474*2d9fd380Sjfb8856606 desc->len = txm->data_len;
475*2d9fd380Sjfb8856606 desc->vlan_tci = txm->vlan_tci;
476*2d9fd380Sjfb8856606
477*2d9fd380Sjfb8856606 txm_seg = txm->next;
478*2d9fd380Sjfb8856606 while (txm_seg != NULL) {
479*2d9fd380Sjfb8856606 elem->len = txm_seg->data_len;
480*2d9fd380Sjfb8856606 elem->addr = rte_cpu_to_le_64(rte_mbuf_data_iova(txm_seg));
481*2d9fd380Sjfb8856606 stats->frags++;
482*2d9fd380Sjfb8856606 elem++;
483*2d9fd380Sjfb8856606 txm_seg = txm_seg->next;
484*2d9fd380Sjfb8856606 }
485*2d9fd380Sjfb8856606
486*2d9fd380Sjfb8856606 ionic_q_post(q, not_xmit_more, NULL, txm);
487*2d9fd380Sjfb8856606
488*2d9fd380Sjfb8856606 return 0;
489*2d9fd380Sjfb8856606 }
490*2d9fd380Sjfb8856606
491*2d9fd380Sjfb8856606 uint16_t
ionic_xmit_pkts(void * tx_queue,struct rte_mbuf ** tx_pkts,uint16_t nb_pkts)492*2d9fd380Sjfb8856606 ionic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
493*2d9fd380Sjfb8856606 uint16_t nb_pkts)
494*2d9fd380Sjfb8856606 {
495*2d9fd380Sjfb8856606 struct ionic_qcq *txq = (struct ionic_qcq *)tx_queue;
496*2d9fd380Sjfb8856606 struct ionic_queue *q = &txq->q;
497*2d9fd380Sjfb8856606 struct ionic_cq *cq = &txq->cq;
498*2d9fd380Sjfb8856606 struct ionic_tx_stats *stats = IONIC_Q_TO_TX_STATS(q);
499*2d9fd380Sjfb8856606 uint32_t next_q_head_idx;
500*2d9fd380Sjfb8856606 uint32_t bytes_tx = 0;
501*2d9fd380Sjfb8856606 uint16_t nb_tx = 0;
502*2d9fd380Sjfb8856606 int err;
503*2d9fd380Sjfb8856606 bool last;
504*2d9fd380Sjfb8856606
505*2d9fd380Sjfb8856606 /* Cleaning old buffers */
506*2d9fd380Sjfb8856606 ionic_tx_flush(cq);
507*2d9fd380Sjfb8856606
508*2d9fd380Sjfb8856606 if (unlikely(ionic_q_space_avail(q) < nb_pkts)) {
509*2d9fd380Sjfb8856606 stats->stop += nb_pkts;
510*2d9fd380Sjfb8856606 return 0;
511*2d9fd380Sjfb8856606 }
512*2d9fd380Sjfb8856606
513*2d9fd380Sjfb8856606 while (nb_tx < nb_pkts) {
514*2d9fd380Sjfb8856606 last = (nb_tx == (nb_pkts - 1));
515*2d9fd380Sjfb8856606
516*2d9fd380Sjfb8856606 next_q_head_idx = (q->head_idx + 1) & (q->num_descs - 1);
517*2d9fd380Sjfb8856606 if ((next_q_head_idx & 0x3) == 0) {
518*2d9fd380Sjfb8856606 struct ionic_txq_desc *desc_base = q->base;
519*2d9fd380Sjfb8856606 rte_prefetch0(&desc_base[next_q_head_idx]);
520*2d9fd380Sjfb8856606 rte_prefetch0(&q->info[next_q_head_idx]);
521*2d9fd380Sjfb8856606 }
522*2d9fd380Sjfb8856606
523*2d9fd380Sjfb8856606 if (tx_pkts[nb_tx]->ol_flags & PKT_TX_TCP_SEG)
524*2d9fd380Sjfb8856606 err = ionic_tx_tso(q, tx_pkts[nb_tx], txq->offloads,
525*2d9fd380Sjfb8856606 last);
526*2d9fd380Sjfb8856606 else
527*2d9fd380Sjfb8856606 err = ionic_tx(q, tx_pkts[nb_tx], txq->offloads, last);
528*2d9fd380Sjfb8856606 if (err) {
529*2d9fd380Sjfb8856606 stats->drop += nb_pkts - nb_tx;
530*2d9fd380Sjfb8856606 if (nb_tx > 0)
531*2d9fd380Sjfb8856606 ionic_q_flush(q);
532*2d9fd380Sjfb8856606 break;
533*2d9fd380Sjfb8856606 }
534*2d9fd380Sjfb8856606
535*2d9fd380Sjfb8856606 bytes_tx += tx_pkts[nb_tx]->pkt_len;
536*2d9fd380Sjfb8856606 nb_tx++;
537*2d9fd380Sjfb8856606 }
538*2d9fd380Sjfb8856606
539*2d9fd380Sjfb8856606 stats->packets += nb_tx;
540*2d9fd380Sjfb8856606 stats->bytes += bytes_tx;
541*2d9fd380Sjfb8856606
542*2d9fd380Sjfb8856606 return nb_tx;
543*2d9fd380Sjfb8856606 }
544*2d9fd380Sjfb8856606
545*2d9fd380Sjfb8856606 /*********************************************************************
546*2d9fd380Sjfb8856606 *
547*2d9fd380Sjfb8856606 * TX prep functions
548*2d9fd380Sjfb8856606 *
549*2d9fd380Sjfb8856606 **********************************************************************/
550*2d9fd380Sjfb8856606
551*2d9fd380Sjfb8856606 #define IONIC_TX_OFFLOAD_MASK ( \
552*2d9fd380Sjfb8856606 PKT_TX_IPV4 | \
553*2d9fd380Sjfb8856606 PKT_TX_IPV6 | \
554*2d9fd380Sjfb8856606 PKT_TX_VLAN | \
555*2d9fd380Sjfb8856606 PKT_TX_IP_CKSUM | \
556*2d9fd380Sjfb8856606 PKT_TX_TCP_SEG | \
557*2d9fd380Sjfb8856606 PKT_TX_L4_MASK)
558*2d9fd380Sjfb8856606
559*2d9fd380Sjfb8856606 #define IONIC_TX_OFFLOAD_NOTSUP_MASK \
560*2d9fd380Sjfb8856606 (PKT_TX_OFFLOAD_MASK ^ IONIC_TX_OFFLOAD_MASK)
561*2d9fd380Sjfb8856606
562*2d9fd380Sjfb8856606 uint16_t
ionic_prep_pkts(void * tx_queue __rte_unused,struct rte_mbuf ** tx_pkts,uint16_t nb_pkts)563*2d9fd380Sjfb8856606 ionic_prep_pkts(void *tx_queue __rte_unused, struct rte_mbuf **tx_pkts,
564*2d9fd380Sjfb8856606 uint16_t nb_pkts)
565*2d9fd380Sjfb8856606 {
566*2d9fd380Sjfb8856606 struct rte_mbuf *txm;
567*2d9fd380Sjfb8856606 uint64_t offloads;
568*2d9fd380Sjfb8856606 int i = 0;
569*2d9fd380Sjfb8856606
570*2d9fd380Sjfb8856606 for (i = 0; i < nb_pkts; i++) {
571*2d9fd380Sjfb8856606 txm = tx_pkts[i];
572*2d9fd380Sjfb8856606
573*2d9fd380Sjfb8856606 if (txm->nb_segs > IONIC_TX_MAX_SG_ELEMS) {
574*2d9fd380Sjfb8856606 rte_errno = -EINVAL;
575*2d9fd380Sjfb8856606 break;
576*2d9fd380Sjfb8856606 }
577*2d9fd380Sjfb8856606
578*2d9fd380Sjfb8856606 offloads = txm->ol_flags;
579*2d9fd380Sjfb8856606
580*2d9fd380Sjfb8856606 if (offloads & IONIC_TX_OFFLOAD_NOTSUP_MASK) {
581*2d9fd380Sjfb8856606 rte_errno = -ENOTSUP;
582*2d9fd380Sjfb8856606 break;
583*2d9fd380Sjfb8856606 }
584*2d9fd380Sjfb8856606 }
585*2d9fd380Sjfb8856606
586*2d9fd380Sjfb8856606 return i;
587*2d9fd380Sjfb8856606 }
588*2d9fd380Sjfb8856606
589*2d9fd380Sjfb8856606 /*********************************************************************
590*2d9fd380Sjfb8856606 *
591*2d9fd380Sjfb8856606 * RX functions
592*2d9fd380Sjfb8856606 *
593*2d9fd380Sjfb8856606 **********************************************************************/
594*2d9fd380Sjfb8856606
595*2d9fd380Sjfb8856606 static void ionic_rx_recycle(struct ionic_queue *q, uint32_t q_desc_index,
596*2d9fd380Sjfb8856606 struct rte_mbuf *mbuf);
597*2d9fd380Sjfb8856606
598*2d9fd380Sjfb8856606 void
ionic_rxq_info_get(struct rte_eth_dev * dev,uint16_t queue_id,struct rte_eth_rxq_info * qinfo)599*2d9fd380Sjfb8856606 ionic_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
600*2d9fd380Sjfb8856606 struct rte_eth_rxq_info *qinfo)
601*2d9fd380Sjfb8856606 {
602*2d9fd380Sjfb8856606 struct ionic_qcq *rxq = dev->data->rx_queues[queue_id];
603*2d9fd380Sjfb8856606 struct ionic_queue *q = &rxq->q;
604*2d9fd380Sjfb8856606
605*2d9fd380Sjfb8856606 qinfo->mp = rxq->mb_pool;
606*2d9fd380Sjfb8856606 qinfo->scattered_rx = dev->data->scattered_rx;
607*2d9fd380Sjfb8856606 qinfo->nb_desc = q->num_descs;
608*2d9fd380Sjfb8856606 qinfo->conf.rx_deferred_start = rxq->deferred_start;
609*2d9fd380Sjfb8856606 qinfo->conf.offloads = rxq->offloads;
610*2d9fd380Sjfb8856606 }
611*2d9fd380Sjfb8856606
612*2d9fd380Sjfb8856606 static void __rte_cold
ionic_rx_empty(struct ionic_queue * q)613*2d9fd380Sjfb8856606 ionic_rx_empty(struct ionic_queue *q)
614*2d9fd380Sjfb8856606 {
615*2d9fd380Sjfb8856606 struct ionic_qcq *rxq = IONIC_Q_TO_QCQ(q);
616*2d9fd380Sjfb8856606 struct ionic_desc_info *cur;
617*2d9fd380Sjfb8856606 struct rte_mbuf *mbuf;
618*2d9fd380Sjfb8856606
619*2d9fd380Sjfb8856606 while (q->tail_idx != q->head_idx) {
620*2d9fd380Sjfb8856606 cur = &q->info[q->tail_idx];
621*2d9fd380Sjfb8856606 mbuf = cur->cb_arg;
622*2d9fd380Sjfb8856606 rte_mempool_put(rxq->mb_pool, mbuf);
623*2d9fd380Sjfb8856606
624*2d9fd380Sjfb8856606 q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
625*2d9fd380Sjfb8856606 }
626*2d9fd380Sjfb8856606 }
627*2d9fd380Sjfb8856606
628*2d9fd380Sjfb8856606 void __rte_cold
ionic_dev_rx_queue_release(void * rx_queue)629*2d9fd380Sjfb8856606 ionic_dev_rx_queue_release(void *rx_queue)
630*2d9fd380Sjfb8856606 {
631*2d9fd380Sjfb8856606 struct ionic_qcq *rxq = (struct ionic_qcq *)rx_queue;
632*2d9fd380Sjfb8856606
633*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
634*2d9fd380Sjfb8856606
635*2d9fd380Sjfb8856606 ionic_rx_empty(&rxq->q);
636*2d9fd380Sjfb8856606
637*2d9fd380Sjfb8856606 ionic_qcq_free(rxq);
638*2d9fd380Sjfb8856606 }
639*2d9fd380Sjfb8856606
640*2d9fd380Sjfb8856606 int __rte_cold
ionic_dev_rx_queue_setup(struct rte_eth_dev * eth_dev,uint16_t rx_queue_id,uint16_t nb_desc,uint32_t socket_id __rte_unused,const struct rte_eth_rxconf * rx_conf,struct rte_mempool * mp)641*2d9fd380Sjfb8856606 ionic_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
642*2d9fd380Sjfb8856606 uint16_t rx_queue_id,
643*2d9fd380Sjfb8856606 uint16_t nb_desc,
644*2d9fd380Sjfb8856606 uint32_t socket_id __rte_unused,
645*2d9fd380Sjfb8856606 const struct rte_eth_rxconf *rx_conf,
646*2d9fd380Sjfb8856606 struct rte_mempool *mp)
647*2d9fd380Sjfb8856606 {
648*2d9fd380Sjfb8856606 struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
649*2d9fd380Sjfb8856606 struct ionic_qcq *rxq;
650*2d9fd380Sjfb8856606 uint64_t offloads;
651*2d9fd380Sjfb8856606 int err;
652*2d9fd380Sjfb8856606
653*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
654*2d9fd380Sjfb8856606
655*2d9fd380Sjfb8856606 IONIC_PRINT(DEBUG, "Configuring RX queue %u with %u buffers",
656*2d9fd380Sjfb8856606 rx_queue_id, nb_desc);
657*2d9fd380Sjfb8856606
658*2d9fd380Sjfb8856606 if (rx_queue_id >= lif->nrxqcqs) {
659*2d9fd380Sjfb8856606 IONIC_PRINT(ERR,
660*2d9fd380Sjfb8856606 "Queue index %u not available (max %u queues)",
661*2d9fd380Sjfb8856606 rx_queue_id, lif->nrxqcqs);
662*2d9fd380Sjfb8856606 return -EINVAL;
663*2d9fd380Sjfb8856606 }
664*2d9fd380Sjfb8856606
665*2d9fd380Sjfb8856606 offloads = rx_conf->offloads | eth_dev->data->dev_conf.rxmode.offloads;
666*2d9fd380Sjfb8856606
667*2d9fd380Sjfb8856606 /* Validate number of receive descriptors */
668*2d9fd380Sjfb8856606 if (!rte_is_power_of_2(nb_desc) ||
669*2d9fd380Sjfb8856606 nb_desc < IONIC_MIN_RING_DESC ||
670*2d9fd380Sjfb8856606 nb_desc > IONIC_MAX_RING_DESC) {
671*2d9fd380Sjfb8856606 IONIC_PRINT(ERR,
672*2d9fd380Sjfb8856606 "Bad number of descriptors (%u) for queue %u (min: %u)",
673*2d9fd380Sjfb8856606 nb_desc, rx_queue_id, IONIC_MIN_RING_DESC);
674*2d9fd380Sjfb8856606 return -EINVAL; /* or use IONIC_DEFAULT_RING_DESC */
675*2d9fd380Sjfb8856606 }
676*2d9fd380Sjfb8856606
677*2d9fd380Sjfb8856606 if (rx_conf->offloads & DEV_RX_OFFLOAD_SCATTER)
678*2d9fd380Sjfb8856606 eth_dev->data->scattered_rx = 1;
679*2d9fd380Sjfb8856606
680*2d9fd380Sjfb8856606 /* Free memory prior to re-allocation if needed... */
681*2d9fd380Sjfb8856606 if (eth_dev->data->rx_queues[rx_queue_id] != NULL) {
682*2d9fd380Sjfb8856606 void *rx_queue = eth_dev->data->rx_queues[rx_queue_id];
683*2d9fd380Sjfb8856606 ionic_dev_rx_queue_release(rx_queue);
684*2d9fd380Sjfb8856606 eth_dev->data->rx_queues[rx_queue_id] = NULL;
685*2d9fd380Sjfb8856606 }
686*2d9fd380Sjfb8856606
687*2d9fd380Sjfb8856606 err = ionic_rx_qcq_alloc(lif, rx_queue_id, nb_desc, &rxq);
688*2d9fd380Sjfb8856606 if (err) {
689*2d9fd380Sjfb8856606 IONIC_PRINT(ERR, "Queue allocation failure");
690*2d9fd380Sjfb8856606 return -EINVAL;
691*2d9fd380Sjfb8856606 }
692*2d9fd380Sjfb8856606
693*2d9fd380Sjfb8856606 rxq->mb_pool = mp;
694*2d9fd380Sjfb8856606
695*2d9fd380Sjfb8856606 /*
696*2d9fd380Sjfb8856606 * Note: the interface does not currently support
697*2d9fd380Sjfb8856606 * DEV_RX_OFFLOAD_KEEP_CRC, please also consider ETHER_CRC_LEN
698*2d9fd380Sjfb8856606 * when the adapter will be able to keep the CRC and subtract
699*2d9fd380Sjfb8856606 * it to the length for all received packets:
700*2d9fd380Sjfb8856606 * if (eth_dev->data->dev_conf.rxmode.offloads &
701*2d9fd380Sjfb8856606 * DEV_RX_OFFLOAD_KEEP_CRC)
702*2d9fd380Sjfb8856606 * rxq->crc_len = ETHER_CRC_LEN;
703*2d9fd380Sjfb8856606 */
704*2d9fd380Sjfb8856606
705*2d9fd380Sjfb8856606 /* Do not start queue with rte_eth_dev_start() */
706*2d9fd380Sjfb8856606 rxq->deferred_start = rx_conf->rx_deferred_start;
707*2d9fd380Sjfb8856606
708*2d9fd380Sjfb8856606 rxq->offloads = offloads;
709*2d9fd380Sjfb8856606
710*2d9fd380Sjfb8856606 eth_dev->data->rx_queues[rx_queue_id] = rxq;
711*2d9fd380Sjfb8856606
712*2d9fd380Sjfb8856606 return 0;
713*2d9fd380Sjfb8856606 }
714*2d9fd380Sjfb8856606
715*2d9fd380Sjfb8856606 static void
ionic_rx_clean(struct ionic_queue * q,uint32_t q_desc_index,uint32_t cq_desc_index,void * cb_arg,void * service_cb_arg)716*2d9fd380Sjfb8856606 ionic_rx_clean(struct ionic_queue *q,
717*2d9fd380Sjfb8856606 uint32_t q_desc_index, uint32_t cq_desc_index,
718*2d9fd380Sjfb8856606 void *cb_arg, void *service_cb_arg)
719*2d9fd380Sjfb8856606 {
720*2d9fd380Sjfb8856606 struct ionic_rxq_comp *cq_desc_base = q->bound_cq->base;
721*2d9fd380Sjfb8856606 struct ionic_rxq_comp *cq_desc = &cq_desc_base[cq_desc_index];
722*2d9fd380Sjfb8856606 struct rte_mbuf *rxm = cb_arg;
723*2d9fd380Sjfb8856606 struct rte_mbuf *rxm_seg;
724*2d9fd380Sjfb8856606 struct ionic_qcq *rxq = IONIC_Q_TO_QCQ(q);
725*2d9fd380Sjfb8856606 uint32_t max_frame_size =
726*2d9fd380Sjfb8856606 rxq->lif->eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
727*2d9fd380Sjfb8856606 uint64_t pkt_flags = 0;
728*2d9fd380Sjfb8856606 uint32_t pkt_type;
729*2d9fd380Sjfb8856606 struct ionic_rx_stats *stats = IONIC_Q_TO_RX_STATS(q);
730*2d9fd380Sjfb8856606 struct ionic_rx_service *recv_args = (struct ionic_rx_service *)
731*2d9fd380Sjfb8856606 service_cb_arg;
732*2d9fd380Sjfb8856606 uint32_t buf_size = (uint16_t)
733*2d9fd380Sjfb8856606 (rte_pktmbuf_data_room_size(rxq->mb_pool) -
734*2d9fd380Sjfb8856606 RTE_PKTMBUF_HEADROOM);
735*2d9fd380Sjfb8856606 uint32_t left;
736*2d9fd380Sjfb8856606
737*2d9fd380Sjfb8856606 if (!recv_args) {
738*2d9fd380Sjfb8856606 stats->no_cb_arg++;
739*2d9fd380Sjfb8856606 /* Flush */
740*2d9fd380Sjfb8856606 rte_pktmbuf_free(rxm);
741*2d9fd380Sjfb8856606 /*
742*2d9fd380Sjfb8856606 * Note: rte_mempool_put is faster with no segs
743*2d9fd380Sjfb8856606 * rte_mempool_put(rxq->mb_pool, rxm);
744*2d9fd380Sjfb8856606 */
745*2d9fd380Sjfb8856606 return;
746*2d9fd380Sjfb8856606 }
747*2d9fd380Sjfb8856606
748*2d9fd380Sjfb8856606 if (cq_desc->status) {
749*2d9fd380Sjfb8856606 stats->bad_cq_status++;
750*2d9fd380Sjfb8856606 ionic_rx_recycle(q, q_desc_index, rxm);
751*2d9fd380Sjfb8856606 return;
752*2d9fd380Sjfb8856606 }
753*2d9fd380Sjfb8856606
754*2d9fd380Sjfb8856606 if (recv_args->nb_rx >= recv_args->nb_pkts) {
755*2d9fd380Sjfb8856606 stats->no_room++;
756*2d9fd380Sjfb8856606 ionic_rx_recycle(q, q_desc_index, rxm);
757*2d9fd380Sjfb8856606 return;
758*2d9fd380Sjfb8856606 }
759*2d9fd380Sjfb8856606
760*2d9fd380Sjfb8856606 if (cq_desc->len > max_frame_size ||
761*2d9fd380Sjfb8856606 cq_desc->len == 0) {
762*2d9fd380Sjfb8856606 stats->bad_len++;
763*2d9fd380Sjfb8856606 ionic_rx_recycle(q, q_desc_index, rxm);
764*2d9fd380Sjfb8856606 return;
765*2d9fd380Sjfb8856606 }
766*2d9fd380Sjfb8856606
767*2d9fd380Sjfb8856606 rxm->data_off = RTE_PKTMBUF_HEADROOM;
768*2d9fd380Sjfb8856606 rte_prefetch1((char *)rxm->buf_addr + rxm->data_off);
769*2d9fd380Sjfb8856606 rxm->nb_segs = 1; /* cq_desc->num_sg_elems */
770*2d9fd380Sjfb8856606 rxm->pkt_len = cq_desc->len;
771*2d9fd380Sjfb8856606 rxm->port = rxq->lif->port_id;
772*2d9fd380Sjfb8856606
773*2d9fd380Sjfb8856606 left = cq_desc->len;
774*2d9fd380Sjfb8856606
775*2d9fd380Sjfb8856606 rxm->data_len = RTE_MIN(buf_size, left);
776*2d9fd380Sjfb8856606 left -= rxm->data_len;
777*2d9fd380Sjfb8856606
778*2d9fd380Sjfb8856606 rxm_seg = rxm->next;
779*2d9fd380Sjfb8856606 while (rxm_seg && left) {
780*2d9fd380Sjfb8856606 rxm_seg->data_len = RTE_MIN(buf_size, left);
781*2d9fd380Sjfb8856606 left -= rxm_seg->data_len;
782*2d9fd380Sjfb8856606
783*2d9fd380Sjfb8856606 rxm_seg = rxm_seg->next;
784*2d9fd380Sjfb8856606 rxm->nb_segs++;
785*2d9fd380Sjfb8856606 }
786*2d9fd380Sjfb8856606
787*2d9fd380Sjfb8856606 /* RSS */
788*2d9fd380Sjfb8856606 pkt_flags |= PKT_RX_RSS_HASH;
789*2d9fd380Sjfb8856606 rxm->hash.rss = cq_desc->rss_hash;
790*2d9fd380Sjfb8856606
791*2d9fd380Sjfb8856606 /* Vlan Strip */
792*2d9fd380Sjfb8856606 if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_VLAN) {
793*2d9fd380Sjfb8856606 pkt_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
794*2d9fd380Sjfb8856606 rxm->vlan_tci = cq_desc->vlan_tci;
795*2d9fd380Sjfb8856606 }
796*2d9fd380Sjfb8856606
797*2d9fd380Sjfb8856606 /* Checksum */
798*2d9fd380Sjfb8856606 if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_CALC) {
799*2d9fd380Sjfb8856606 if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_OK)
800*2d9fd380Sjfb8856606 pkt_flags |= PKT_RX_IP_CKSUM_GOOD;
801*2d9fd380Sjfb8856606 else if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_BAD)
802*2d9fd380Sjfb8856606 pkt_flags |= PKT_RX_IP_CKSUM_BAD;
803*2d9fd380Sjfb8856606
804*2d9fd380Sjfb8856606 if ((cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_TCP_OK) ||
805*2d9fd380Sjfb8856606 (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_UDP_OK))
806*2d9fd380Sjfb8856606 pkt_flags |= PKT_RX_L4_CKSUM_GOOD;
807*2d9fd380Sjfb8856606 else if ((cq_desc->csum_flags &
808*2d9fd380Sjfb8856606 IONIC_RXQ_COMP_CSUM_F_TCP_BAD) ||
809*2d9fd380Sjfb8856606 (cq_desc->csum_flags &
810*2d9fd380Sjfb8856606 IONIC_RXQ_COMP_CSUM_F_UDP_BAD))
811*2d9fd380Sjfb8856606 pkt_flags |= PKT_RX_L4_CKSUM_BAD;
812*2d9fd380Sjfb8856606 }
813*2d9fd380Sjfb8856606
814*2d9fd380Sjfb8856606 rxm->ol_flags = pkt_flags;
815*2d9fd380Sjfb8856606
816*2d9fd380Sjfb8856606 /* Packet Type */
817*2d9fd380Sjfb8856606 switch (cq_desc->pkt_type_color & IONIC_RXQ_COMP_PKT_TYPE_MASK) {
818*2d9fd380Sjfb8856606 case IONIC_PKT_TYPE_IPV4:
819*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4;
820*2d9fd380Sjfb8856606 break;
821*2d9fd380Sjfb8856606 case IONIC_PKT_TYPE_IPV6:
822*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6;
823*2d9fd380Sjfb8856606 break;
824*2d9fd380Sjfb8856606 case IONIC_PKT_TYPE_IPV4_TCP:
825*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4 |
826*2d9fd380Sjfb8856606 RTE_PTYPE_L4_TCP;
827*2d9fd380Sjfb8856606 break;
828*2d9fd380Sjfb8856606 case IONIC_PKT_TYPE_IPV6_TCP:
829*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6 |
830*2d9fd380Sjfb8856606 RTE_PTYPE_L4_TCP;
831*2d9fd380Sjfb8856606 break;
832*2d9fd380Sjfb8856606 case IONIC_PKT_TYPE_IPV4_UDP:
833*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4 |
834*2d9fd380Sjfb8856606 RTE_PTYPE_L4_UDP;
835*2d9fd380Sjfb8856606 break;
836*2d9fd380Sjfb8856606 case IONIC_PKT_TYPE_IPV6_UDP:
837*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6 |
838*2d9fd380Sjfb8856606 RTE_PTYPE_L4_UDP;
839*2d9fd380Sjfb8856606 break;
840*2d9fd380Sjfb8856606 default:
841*2d9fd380Sjfb8856606 {
842*2d9fd380Sjfb8856606 struct rte_ether_hdr *eth_h = rte_pktmbuf_mtod(rxm,
843*2d9fd380Sjfb8856606 struct rte_ether_hdr *);
844*2d9fd380Sjfb8856606 uint16_t ether_type = eth_h->ether_type;
845*2d9fd380Sjfb8856606 if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP))
846*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_L2_ETHER_ARP;
847*2d9fd380Sjfb8856606 else
848*2d9fd380Sjfb8856606 pkt_type = RTE_PTYPE_UNKNOWN;
849*2d9fd380Sjfb8856606 break;
850*2d9fd380Sjfb8856606 }
851*2d9fd380Sjfb8856606 }
852*2d9fd380Sjfb8856606
853*2d9fd380Sjfb8856606 rxm->packet_type = pkt_type;
854*2d9fd380Sjfb8856606
855*2d9fd380Sjfb8856606 recv_args->rx_pkts[recv_args->nb_rx] = rxm;
856*2d9fd380Sjfb8856606 recv_args->nb_rx++;
857*2d9fd380Sjfb8856606
858*2d9fd380Sjfb8856606 stats->packets++;
859*2d9fd380Sjfb8856606 stats->bytes += rxm->pkt_len;
860*2d9fd380Sjfb8856606 }
861*2d9fd380Sjfb8856606
862*2d9fd380Sjfb8856606 static void
ionic_rx_recycle(struct ionic_queue * q,uint32_t q_desc_index,struct rte_mbuf * mbuf)863*2d9fd380Sjfb8856606 ionic_rx_recycle(struct ionic_queue *q, uint32_t q_desc_index,
864*2d9fd380Sjfb8856606 struct rte_mbuf *mbuf)
865*2d9fd380Sjfb8856606 {
866*2d9fd380Sjfb8856606 struct ionic_rxq_desc *desc_base = q->base;
867*2d9fd380Sjfb8856606 struct ionic_rxq_desc *old = &desc_base[q_desc_index];
868*2d9fd380Sjfb8856606 struct ionic_rxq_desc *new = &desc_base[q->head_idx];
869*2d9fd380Sjfb8856606
870*2d9fd380Sjfb8856606 new->addr = old->addr;
871*2d9fd380Sjfb8856606 new->len = old->len;
872*2d9fd380Sjfb8856606
873*2d9fd380Sjfb8856606 ionic_q_post(q, true, ionic_rx_clean, mbuf);
874*2d9fd380Sjfb8856606 }
875*2d9fd380Sjfb8856606
876*2d9fd380Sjfb8856606 static int __rte_cold
ionic_rx_fill(struct ionic_qcq * rxq,uint32_t len)877*2d9fd380Sjfb8856606 ionic_rx_fill(struct ionic_qcq *rxq, uint32_t len)
878*2d9fd380Sjfb8856606 {
879*2d9fd380Sjfb8856606 struct ionic_queue *q = &rxq->q;
880*2d9fd380Sjfb8856606 struct ionic_rxq_desc *desc_base = q->base;
881*2d9fd380Sjfb8856606 struct ionic_rxq_sg_desc *sg_desc_base = q->sg_base;
882*2d9fd380Sjfb8856606 struct ionic_rxq_desc *desc;
883*2d9fd380Sjfb8856606 struct ionic_rxq_sg_desc *sg_desc;
884*2d9fd380Sjfb8856606 struct ionic_rxq_sg_elem *elem;
885*2d9fd380Sjfb8856606 rte_iova_t dma_addr;
886*2d9fd380Sjfb8856606 uint32_t i, j, nsegs, buf_size, size;
887*2d9fd380Sjfb8856606 bool ring_doorbell;
888*2d9fd380Sjfb8856606
889*2d9fd380Sjfb8856606 buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mb_pool) -
890*2d9fd380Sjfb8856606 RTE_PKTMBUF_HEADROOM);
891*2d9fd380Sjfb8856606
892*2d9fd380Sjfb8856606 /* Initialize software ring entries */
893*2d9fd380Sjfb8856606 for (i = ionic_q_space_avail(q); i; i--) {
894*2d9fd380Sjfb8856606 struct rte_mbuf *rxm = rte_mbuf_raw_alloc(rxq->mb_pool);
895*2d9fd380Sjfb8856606 struct rte_mbuf *prev_rxm_seg;
896*2d9fd380Sjfb8856606
897*2d9fd380Sjfb8856606 if (rxm == NULL) {
898*2d9fd380Sjfb8856606 IONIC_PRINT(ERR, "RX mbuf alloc failed");
899*2d9fd380Sjfb8856606 return -ENOMEM;
900*2d9fd380Sjfb8856606 }
901*2d9fd380Sjfb8856606
902*2d9fd380Sjfb8856606 nsegs = (len + buf_size - 1) / buf_size;
903*2d9fd380Sjfb8856606
904*2d9fd380Sjfb8856606 desc = &desc_base[q->head_idx];
905*2d9fd380Sjfb8856606 dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(rxm));
906*2d9fd380Sjfb8856606 desc->addr = dma_addr;
907*2d9fd380Sjfb8856606 desc->len = buf_size;
908*2d9fd380Sjfb8856606 size = buf_size;
909*2d9fd380Sjfb8856606 desc->opcode = (nsegs > 1) ? IONIC_RXQ_DESC_OPCODE_SG :
910*2d9fd380Sjfb8856606 IONIC_RXQ_DESC_OPCODE_SIMPLE;
911*2d9fd380Sjfb8856606 rxm->next = NULL;
912*2d9fd380Sjfb8856606
913*2d9fd380Sjfb8856606 prev_rxm_seg = rxm;
914*2d9fd380Sjfb8856606 sg_desc = &sg_desc_base[q->head_idx];
915*2d9fd380Sjfb8856606 elem = sg_desc->elems;
916*2d9fd380Sjfb8856606 for (j = 0; j < nsegs - 1 && j < IONIC_RX_MAX_SG_ELEMS; j++) {
917*2d9fd380Sjfb8856606 struct rte_mbuf *rxm_seg;
918*2d9fd380Sjfb8856606 rte_iova_t data_iova;
919*2d9fd380Sjfb8856606
920*2d9fd380Sjfb8856606 rxm_seg = rte_mbuf_raw_alloc(rxq->mb_pool);
921*2d9fd380Sjfb8856606 if (rxm_seg == NULL) {
922*2d9fd380Sjfb8856606 IONIC_PRINT(ERR, "RX mbuf alloc failed");
923*2d9fd380Sjfb8856606 return -ENOMEM;
924*2d9fd380Sjfb8856606 }
925*2d9fd380Sjfb8856606
926*2d9fd380Sjfb8856606 data_iova = rte_mbuf_data_iova(rxm_seg);
927*2d9fd380Sjfb8856606 dma_addr = rte_cpu_to_le_64(data_iova);
928*2d9fd380Sjfb8856606 elem->addr = dma_addr;
929*2d9fd380Sjfb8856606 elem->len = buf_size;
930*2d9fd380Sjfb8856606 size += buf_size;
931*2d9fd380Sjfb8856606 elem++;
932*2d9fd380Sjfb8856606 rxm_seg->next = NULL;
933*2d9fd380Sjfb8856606 prev_rxm_seg->next = rxm_seg;
934*2d9fd380Sjfb8856606 prev_rxm_seg = rxm_seg;
935*2d9fd380Sjfb8856606 }
936*2d9fd380Sjfb8856606
937*2d9fd380Sjfb8856606 if (size < len)
938*2d9fd380Sjfb8856606 IONIC_PRINT(ERR, "Rx SG size is not sufficient (%d < %d)",
939*2d9fd380Sjfb8856606 size, len);
940*2d9fd380Sjfb8856606
941*2d9fd380Sjfb8856606 ring_doorbell = ((q->head_idx + 1) &
942*2d9fd380Sjfb8856606 IONIC_RX_RING_DOORBELL_STRIDE) == 0;
943*2d9fd380Sjfb8856606
944*2d9fd380Sjfb8856606 ionic_q_post(q, ring_doorbell, ionic_rx_clean, rxm);
945*2d9fd380Sjfb8856606 }
946*2d9fd380Sjfb8856606
947*2d9fd380Sjfb8856606 return 0;
948*2d9fd380Sjfb8856606 }
949*2d9fd380Sjfb8856606
950*2d9fd380Sjfb8856606 /*
951*2d9fd380Sjfb8856606 * Start Receive Units for specified queue.
952*2d9fd380Sjfb8856606 */
953*2d9fd380Sjfb8856606 int __rte_cold
ionic_dev_rx_queue_start(struct rte_eth_dev * eth_dev,uint16_t rx_queue_id)954*2d9fd380Sjfb8856606 ionic_dev_rx_queue_start(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
955*2d9fd380Sjfb8856606 {
956*2d9fd380Sjfb8856606 uint32_t frame_size = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
957*2d9fd380Sjfb8856606 struct ionic_qcq *rxq;
958*2d9fd380Sjfb8856606 int err;
959*2d9fd380Sjfb8856606
960*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
961*2d9fd380Sjfb8856606
962*2d9fd380Sjfb8856606 IONIC_PRINT(DEBUG, "Allocating RX queue buffers (size: %u)",
963*2d9fd380Sjfb8856606 frame_size);
964*2d9fd380Sjfb8856606
965*2d9fd380Sjfb8856606 rxq = eth_dev->data->rx_queues[rx_queue_id];
966*2d9fd380Sjfb8856606
967*2d9fd380Sjfb8856606 err = ionic_lif_rxq_init(rxq);
968*2d9fd380Sjfb8856606 if (err)
969*2d9fd380Sjfb8856606 return err;
970*2d9fd380Sjfb8856606
971*2d9fd380Sjfb8856606 /* Allocate buffers for descriptor rings */
972*2d9fd380Sjfb8856606 if (ionic_rx_fill(rxq, frame_size) != 0) {
973*2d9fd380Sjfb8856606 IONIC_PRINT(ERR, "Could not alloc mbuf for queue:%d",
974*2d9fd380Sjfb8856606 rx_queue_id);
975*2d9fd380Sjfb8856606 return -1;
976*2d9fd380Sjfb8856606 }
977*2d9fd380Sjfb8856606
978*2d9fd380Sjfb8856606 ionic_qcq_enable(rxq);
979*2d9fd380Sjfb8856606
980*2d9fd380Sjfb8856606 eth_dev->data->rx_queue_state[rx_queue_id] =
981*2d9fd380Sjfb8856606 RTE_ETH_QUEUE_STATE_STARTED;
982*2d9fd380Sjfb8856606
983*2d9fd380Sjfb8856606 return 0;
984*2d9fd380Sjfb8856606 }
985*2d9fd380Sjfb8856606
986*2d9fd380Sjfb8856606 static inline void __rte_cold
ionic_rxq_service(struct ionic_cq * cq,uint32_t work_to_do,void * service_cb_arg)987*2d9fd380Sjfb8856606 ionic_rxq_service(struct ionic_cq *cq, uint32_t work_to_do,
988*2d9fd380Sjfb8856606 void *service_cb_arg)
989*2d9fd380Sjfb8856606 {
990*2d9fd380Sjfb8856606 struct ionic_queue *q = cq->bound_q;
991*2d9fd380Sjfb8856606 struct ionic_desc_info *q_desc_info;
992*2d9fd380Sjfb8856606 struct ionic_rxq_comp *cq_desc_base = cq->base;
993*2d9fd380Sjfb8856606 struct ionic_rxq_comp *cq_desc;
994*2d9fd380Sjfb8856606 bool more;
995*2d9fd380Sjfb8856606 uint32_t curr_q_tail_idx, curr_cq_tail_idx;
996*2d9fd380Sjfb8856606 uint32_t work_done = 0;
997*2d9fd380Sjfb8856606
998*2d9fd380Sjfb8856606 if (work_to_do == 0)
999*2d9fd380Sjfb8856606 return;
1000*2d9fd380Sjfb8856606
1001*2d9fd380Sjfb8856606 cq_desc = &cq_desc_base[cq->tail_idx];
1002*2d9fd380Sjfb8856606 while (color_match(cq_desc->pkt_type_color, cq->done_color)) {
1003*2d9fd380Sjfb8856606 curr_cq_tail_idx = cq->tail_idx;
1004*2d9fd380Sjfb8856606 cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
1005*2d9fd380Sjfb8856606
1006*2d9fd380Sjfb8856606 if (cq->tail_idx == 0)
1007*2d9fd380Sjfb8856606 cq->done_color = !cq->done_color;
1008*2d9fd380Sjfb8856606
1009*2d9fd380Sjfb8856606 /* Prefetch the next 4 descriptors */
1010*2d9fd380Sjfb8856606 if ((cq->tail_idx & 0x3) == 0)
1011*2d9fd380Sjfb8856606 rte_prefetch0(&cq_desc_base[cq->tail_idx]);
1012*2d9fd380Sjfb8856606
1013*2d9fd380Sjfb8856606 do {
1014*2d9fd380Sjfb8856606 more = (q->tail_idx != cq_desc->comp_index);
1015*2d9fd380Sjfb8856606
1016*2d9fd380Sjfb8856606 q_desc_info = &q->info[q->tail_idx];
1017*2d9fd380Sjfb8856606
1018*2d9fd380Sjfb8856606 curr_q_tail_idx = q->tail_idx;
1019*2d9fd380Sjfb8856606 q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
1020*2d9fd380Sjfb8856606
1021*2d9fd380Sjfb8856606 /* Prefetch the next 4 descriptors */
1022*2d9fd380Sjfb8856606 if ((q->tail_idx & 0x3) == 0)
1023*2d9fd380Sjfb8856606 /* q desc info */
1024*2d9fd380Sjfb8856606 rte_prefetch0(&q->info[q->tail_idx]);
1025*2d9fd380Sjfb8856606
1026*2d9fd380Sjfb8856606 ionic_rx_clean(q, curr_q_tail_idx, curr_cq_tail_idx,
1027*2d9fd380Sjfb8856606 q_desc_info->cb_arg, service_cb_arg);
1028*2d9fd380Sjfb8856606
1029*2d9fd380Sjfb8856606 } while (more);
1030*2d9fd380Sjfb8856606
1031*2d9fd380Sjfb8856606 if (++work_done == work_to_do)
1032*2d9fd380Sjfb8856606 break;
1033*2d9fd380Sjfb8856606
1034*2d9fd380Sjfb8856606 cq_desc = &cq_desc_base[cq->tail_idx];
1035*2d9fd380Sjfb8856606 }
1036*2d9fd380Sjfb8856606 }
1037*2d9fd380Sjfb8856606
1038*2d9fd380Sjfb8856606 /*
1039*2d9fd380Sjfb8856606 * Stop Receive Units for specified queue.
1040*2d9fd380Sjfb8856606 */
1041*2d9fd380Sjfb8856606 int __rte_cold
ionic_dev_rx_queue_stop(struct rte_eth_dev * eth_dev,uint16_t rx_queue_id)1042*2d9fd380Sjfb8856606 ionic_dev_rx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
1043*2d9fd380Sjfb8856606 {
1044*2d9fd380Sjfb8856606 struct ionic_qcq *rxq;
1045*2d9fd380Sjfb8856606
1046*2d9fd380Sjfb8856606 IONIC_PRINT_CALL();
1047*2d9fd380Sjfb8856606
1048*2d9fd380Sjfb8856606 rxq = eth_dev->data->rx_queues[rx_queue_id];
1049*2d9fd380Sjfb8856606
1050*2d9fd380Sjfb8856606 ionic_qcq_disable(rxq);
1051*2d9fd380Sjfb8856606
1052*2d9fd380Sjfb8856606 /* Flush */
1053*2d9fd380Sjfb8856606 ionic_rxq_service(&rxq->cq, -1, NULL);
1054*2d9fd380Sjfb8856606
1055*2d9fd380Sjfb8856606 ionic_lif_rxq_deinit(rxq);
1056*2d9fd380Sjfb8856606
1057*2d9fd380Sjfb8856606 eth_dev->data->rx_queue_state[rx_queue_id] =
1058*2d9fd380Sjfb8856606 RTE_ETH_QUEUE_STATE_STOPPED;
1059*2d9fd380Sjfb8856606
1060*2d9fd380Sjfb8856606 return 0;
1061*2d9fd380Sjfb8856606 }
1062*2d9fd380Sjfb8856606
1063*2d9fd380Sjfb8856606 uint16_t
ionic_recv_pkts(void * rx_queue,struct rte_mbuf ** rx_pkts,uint16_t nb_pkts)1064*2d9fd380Sjfb8856606 ionic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
1065*2d9fd380Sjfb8856606 uint16_t nb_pkts)
1066*2d9fd380Sjfb8856606 {
1067*2d9fd380Sjfb8856606 struct ionic_qcq *rxq = (struct ionic_qcq *)rx_queue;
1068*2d9fd380Sjfb8856606 uint32_t frame_size =
1069*2d9fd380Sjfb8856606 rxq->lif->eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
1070*2d9fd380Sjfb8856606 struct ionic_cq *cq = &rxq->cq;
1071*2d9fd380Sjfb8856606 struct ionic_rx_service service_cb_arg;
1072*2d9fd380Sjfb8856606
1073*2d9fd380Sjfb8856606 service_cb_arg.rx_pkts = rx_pkts;
1074*2d9fd380Sjfb8856606 service_cb_arg.nb_pkts = nb_pkts;
1075*2d9fd380Sjfb8856606 service_cb_arg.nb_rx = 0;
1076*2d9fd380Sjfb8856606
1077*2d9fd380Sjfb8856606 ionic_rxq_service(cq, nb_pkts, &service_cb_arg);
1078*2d9fd380Sjfb8856606
1079*2d9fd380Sjfb8856606 ionic_rx_fill(rxq, frame_size);
1080*2d9fd380Sjfb8856606
1081*2d9fd380Sjfb8856606 return service_cb_arg.nb_rx;
1082*2d9fd380Sjfb8856606 }
1083