Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2023 Marvell.
3 : : */
4 : :
5 : : #include "otx_ep_common.h"
6 : : #include "otx2_ep_vf.h"
7 : : #include "otx_ep_rxtx.h"
8 : :
9 : : static inline int
10 : 0 : cnxk_ep_rx_refill_mbuf(struct otx_ep_droq *droq, uint32_t count)
11 : : {
12 : 0 : struct otx_ep_droq_desc *desc_ring = droq->desc_ring;
13 : 0 : struct rte_mbuf **recv_buf_list = droq->recv_buf_list;
14 : 0 : uint32_t refill_idx = droq->refill_idx;
15 : : struct rte_mbuf *buf;
16 : : uint32_t i;
17 : : int rc;
18 : :
19 : 0 : rc = rte_pktmbuf_alloc_bulk(droq->mpool, &recv_buf_list[refill_idx], count);
20 [ # # ]: 0 : if (unlikely(rc)) {
21 : 0 : droq->stats.rx_alloc_failure++;
22 : 0 : return rc;
23 : : }
24 : :
25 [ # # ]: 0 : for (i = 0; i < count; i++) {
26 : 0 : buf = recv_buf_list[refill_idx];
27 : 0 : desc_ring[refill_idx].buffer_ptr = rte_mbuf_data_iova_default(buf);
28 : 0 : refill_idx++;
29 : : }
30 : :
31 : 0 : droq->refill_idx = otx_ep_incr_index(droq->refill_idx, count, droq->nb_desc);
32 : 0 : droq->refill_count -= count;
33 : :
34 : 0 : return 0;
35 : : }
36 : :
37 : : static inline void
38 : 0 : cnxk_ep_rx_refill(struct otx_ep_droq *droq)
39 : : {
40 : : uint32_t desc_refilled = 0, count;
41 : 0 : uint32_t nb_desc = droq->nb_desc;
42 : 0 : uint32_t refill_idx = droq->refill_idx;
43 : : int rc;
44 : :
45 [ # # ]: 0 : if (unlikely(droq->read_idx == refill_idx))
46 : : return;
47 : :
48 [ # # ]: 0 : if (refill_idx < droq->read_idx) {
49 : 0 : count = droq->read_idx - refill_idx;
50 : 0 : rc = cnxk_ep_rx_refill_mbuf(droq, count);
51 [ # # ]: 0 : if (unlikely(rc)) {
52 : 0 : droq->stats.rx_alloc_failure++;
53 : 0 : return;
54 : : }
55 : : desc_refilled = count;
56 : : } else {
57 : 0 : count = nb_desc - refill_idx;
58 : 0 : rc = cnxk_ep_rx_refill_mbuf(droq, count);
59 [ # # ]: 0 : if (unlikely(rc)) {
60 : 0 : droq->stats.rx_alloc_failure++;
61 : 0 : return;
62 : : }
63 : :
64 : : desc_refilled = count;
65 : 0 : count = droq->read_idx;
66 : 0 : rc = cnxk_ep_rx_refill_mbuf(droq, count);
67 [ # # ]: 0 : if (unlikely(rc)) {
68 : 0 : droq->stats.rx_alloc_failure++;
69 : 0 : return;
70 : : }
71 : 0 : desc_refilled += count;
72 : : }
73 : :
74 : : /* Flush the droq descriptor data to memory to be sure
75 : : * that when we update the credits the data in memory is
76 : : * accurate.
77 : : */
78 : 0 : rte_io_wmb();
79 : 0 : rte_write32(desc_refilled, droq->pkts_credit_reg);
80 : : }
81 : :
82 : : static inline uint32_t
83 : 0 : cnxk_ep_check_rx_pkts(struct otx_ep_droq *droq)
84 : : {
85 : : uint32_t new_pkts;
86 : : uint32_t val;
87 : :
88 : : /* Batch subtractions from the HW counter to reduce PCIe traffic
89 : : * This adds an extra local variable, but almost halves the
90 : : * number of PCIe writes.
91 : : */
92 : 0 : val = __atomic_load_n(droq->pkts_sent_ism, __ATOMIC_RELAXED);
93 : 0 : new_pkts = val - droq->pkts_sent_ism_prev;
94 : 0 : droq->pkts_sent_ism_prev = val;
95 : :
96 [ # # ]: 0 : if (val > (uint32_t)(1 << 31)) {
97 : : /* Only subtract the packet count in the HW counter
98 : : * when count above halfway to saturation.
99 : : */
100 : 0 : rte_write64((uint64_t)val, droq->pkts_sent_reg);
101 : : rte_mb();
102 : :
103 : 0 : rte_write64(OTX2_SDP_REQUEST_ISM, droq->pkts_sent_reg);
104 [ # # ]: 0 : while (__atomic_load_n(droq->pkts_sent_ism, __ATOMIC_RELAXED) >= val) {
105 : 0 : rte_write64(OTX2_SDP_REQUEST_ISM, droq->pkts_sent_reg);
106 : : rte_mb();
107 : : }
108 : :
109 : 0 : droq->pkts_sent_ism_prev = 0;
110 : : }
111 : 0 : rte_write64(OTX2_SDP_REQUEST_ISM, droq->pkts_sent_reg);
112 : 0 : droq->pkts_pending += new_pkts;
113 : :
114 : 0 : return new_pkts;
115 : : }
116 : :
117 : : static inline int16_t __rte_hot
118 : : cnxk_ep_rx_pkts_to_process(struct otx_ep_droq *droq, uint16_t nb_pkts)
119 : : {
120 : 0 : if (droq->pkts_pending < nb_pkts)
121 : 0 : cnxk_ep_check_rx_pkts(droq);
122 : :
123 : 0 : return RTE_MIN(nb_pkts, droq->pkts_pending);
124 : : }
125 : :
126 : : static __rte_always_inline void
127 : : cnxk_ep_process_pkts_scalar(struct rte_mbuf **rx_pkts, struct otx_ep_droq *droq, uint16_t new_pkts)
128 : : {
129 : 0 : struct rte_mbuf **recv_buf_list = droq->recv_buf_list;
130 : 0 : uint32_t bytes_rsvd = 0, read_idx = droq->read_idx;
131 : 0 : uint16_t port_id = droq->otx_ep_dev->port_id;
132 : 0 : uint16_t nb_desc = droq->nb_desc;
133 : : uint16_t pkts;
134 : :
135 [ # # # # ]: 0 : for (pkts = 0; pkts < new_pkts; pkts++) {
136 : : struct otx_ep_droq_info *info;
137 : : struct rte_mbuf *mbuf;
138 : : uint16_t pkt_len;
139 : :
140 : 0 : mbuf = recv_buf_list[read_idx];
141 [ # # # # ]: 0 : info = rte_pktmbuf_mtod(mbuf, struct otx_ep_droq_info *);
142 : : read_idx = otx_ep_incr_index(read_idx, 1, nb_desc);
143 [ # # # # ]: 0 : pkt_len = rte_bswap16(info->length >> 48);
144 : 0 : mbuf->data_off += OTX_EP_INFO_SIZE;
145 : 0 : mbuf->pkt_len = pkt_len;
146 : 0 : mbuf->data_len = pkt_len;
147 : 0 : mbuf->port = port_id;
148 : 0 : rx_pkts[pkts] = mbuf;
149 : 0 : bytes_rsvd += pkt_len;
150 : : }
151 : 0 : droq->read_idx = read_idx;
152 : :
153 : 0 : droq->refill_count += new_pkts;
154 : 0 : droq->pkts_pending -= new_pkts;
155 : : /* Stats */
156 : 0 : droq->stats.pkts_received += new_pkts;
157 : 0 : droq->stats.bytes_received += bytes_rsvd;
158 : : }
159 : :
160 : : static __rte_always_inline void
161 : : cnxk_ep_process_pkts_scalar_mseg(struct rte_mbuf **rx_pkts, struct otx_ep_droq *droq,
162 : : uint16_t new_pkts)
163 : : {
164 : 0 : struct rte_mbuf **recv_buf_list = droq->recv_buf_list;
165 : : uint32_t total_pkt_len, bytes_rsvd = 0;
166 : 0 : uint16_t port_id = droq->otx_ep_dev->port_id;
167 : 0 : uint16_t nb_desc = droq->nb_desc;
168 : : uint16_t pkts;
169 : :
170 [ # # # # ]: 0 : for (pkts = 0; pkts < new_pkts; pkts++) {
171 : : struct otx_ep_droq_info *info;
172 : : struct rte_mbuf *first_buf = NULL;
173 : : struct rte_mbuf *last_buf = NULL;
174 : : struct rte_mbuf *mbuf;
175 : : uint32_t pkt_len = 0;
176 : :
177 : 0 : mbuf = recv_buf_list[droq->read_idx];
178 : 0 : info = rte_pktmbuf_mtod(mbuf, struct otx_ep_droq_info *);
179 : :
180 [ # # # # ]: 0 : total_pkt_len = rte_bswap16(info->length >> 48) + OTX_EP_INFO_SIZE;
181 : :
182 [ # # # # ]: 0 : while (pkt_len < total_pkt_len) {
183 : : int cpy_len;
184 : :
185 : 0 : cpy_len = ((pkt_len + droq->buffer_size) > total_pkt_len)
186 [ # # # # ]: 0 : ? ((uint32_t)total_pkt_len - pkt_len) : droq->buffer_size;
187 : :
188 : 0 : mbuf = droq->recv_buf_list[droq->read_idx];
189 : :
190 [ # # # # ]: 0 : if (!pkt_len) {
191 : : /* Note the first seg */
192 : : first_buf = mbuf;
193 : 0 : mbuf->data_off += OTX_EP_INFO_SIZE;
194 : 0 : mbuf->pkt_len = cpy_len - OTX_EP_INFO_SIZE;
195 : 0 : mbuf->data_len = cpy_len - OTX_EP_INFO_SIZE;
196 : : } else {
197 : 0 : mbuf->pkt_len = cpy_len;
198 : 0 : mbuf->data_len = cpy_len;
199 : 0 : first_buf->nb_segs++;
200 : 0 : first_buf->pkt_len += mbuf->pkt_len;
201 : : }
202 : :
203 [ # # # # ]: 0 : if (last_buf)
204 : 0 : last_buf->next = mbuf;
205 : :
206 : : last_buf = mbuf;
207 : :
208 : 0 : pkt_len += cpy_len;
209 : 0 : droq->read_idx = otx_ep_incr_index(droq->read_idx, 1, nb_desc);
210 : 0 : droq->refill_count++;
211 : : }
212 : : mbuf = first_buf;
213 : 0 : mbuf->port = port_id;
214 : 0 : rx_pkts[pkts] = mbuf;
215 : 0 : bytes_rsvd += pkt_len;
216 : : }
217 : :
218 : 0 : droq->refill_count += new_pkts;
219 : 0 : droq->pkts_pending -= pkts;
220 : : /* Stats */
221 : 0 : droq->stats.pkts_received += pkts;
222 : 0 : droq->stats.bytes_received += bytes_rsvd;
223 : : }
224 : :
225 : : uint16_t __rte_noinline __rte_hot
226 [ # # ]: 0 : cnxk_ep_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
227 : : {
228 : : struct otx_ep_droq *droq = (struct otx_ep_droq *)rx_queue;
229 : : uint16_t new_pkts;
230 : :
231 : 0 : new_pkts = cnxk_ep_rx_pkts_to_process(droq, nb_pkts);
232 : : cnxk_ep_process_pkts_scalar(rx_pkts, droq, new_pkts);
233 : :
234 : : /* Refill RX buffers */
235 [ # # ]: 0 : if (droq->refill_count >= DROQ_REFILL_THRESHOLD)
236 : 0 : cnxk_ep_rx_refill(droq);
237 : :
238 : 0 : return new_pkts;
239 : : }
240 : :
241 : : uint16_t __rte_noinline __rte_hot
242 [ # # ]: 0 : cn9k_ep_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
243 : : {
244 : : struct otx_ep_droq *droq = (struct otx_ep_droq *)rx_queue;
245 : : uint16_t new_pkts;
246 : :
247 : 0 : new_pkts = cnxk_ep_rx_pkts_to_process(droq, nb_pkts);
248 : : cnxk_ep_process_pkts_scalar(rx_pkts, droq, new_pkts);
249 : :
250 : : /* Refill RX buffers */
251 [ # # ]: 0 : if (droq->refill_count >= DROQ_REFILL_THRESHOLD) {
252 : 0 : cnxk_ep_rx_refill(droq);
253 : : } else {
254 : : /* SDP output goes into DROP state when output doorbell count
255 : : * goes below drop count. When door bell count is written with
256 : : * a value greater than drop count SDP output should come out
257 : : * of DROP state. Due to a race condition this is not happening.
258 : : * Writing doorbell register with 0 again may make SDP output
259 : : * come out of this state.
260 : : */
261 : :
262 : 0 : rte_write32(0, droq->pkts_credit_reg);
263 : : }
264 : :
265 : 0 : return new_pkts;
266 : : }
267 : :
268 : : uint16_t __rte_noinline __rte_hot
269 [ # # ]: 0 : cnxk_ep_recv_pkts_mseg(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
270 : : {
271 : : struct otx_ep_droq *droq = (struct otx_ep_droq *)rx_queue;
272 : : uint16_t new_pkts;
273 : :
274 : 0 : new_pkts = cnxk_ep_rx_pkts_to_process(droq, nb_pkts);
275 : : cnxk_ep_process_pkts_scalar_mseg(rx_pkts, droq, new_pkts);
276 : :
277 : : /* Refill RX buffers */
278 [ # # ]: 0 : if (droq->refill_count >= DROQ_REFILL_THRESHOLD)
279 : 0 : cnxk_ep_rx_refill(droq);
280 : :
281 : 0 : return new_pkts;
282 : : }
283 : :
284 : : uint16_t __rte_noinline __rte_hot
285 [ # # ]: 0 : cn9k_ep_recv_pkts_mseg(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
286 : : {
287 : : struct otx_ep_droq *droq = (struct otx_ep_droq *)rx_queue;
288 : : uint16_t new_pkts;
289 : :
290 : 0 : new_pkts = cnxk_ep_rx_pkts_to_process(droq, nb_pkts);
291 : : cnxk_ep_process_pkts_scalar_mseg(rx_pkts, droq, new_pkts);
292 : :
293 : : /* Refill RX buffers */
294 [ # # ]: 0 : if (droq->refill_count >= DROQ_REFILL_THRESHOLD) {
295 : 0 : cnxk_ep_rx_refill(droq);
296 : : } else {
297 : : /* SDP output goes into DROP state when output doorbell count
298 : : * goes below drop count. When door bell count is written with
299 : : * a value greater than drop count SDP output should come out
300 : : * of DROP state. Due to a race condition this is not happening.
301 : : * Writing doorbell register with 0 again may make SDP output
302 : : * come out of this state.
303 : : */
304 : :
305 : 0 : rte_write32(0, droq->pkts_credit_reg);
306 : : }
307 : :
308 : 0 : return new_pkts;
309 : : }
|