Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2023 Marvell.
3 : : */
4 : :
5 : : #include "cnxk_ep_vf.h"
6 : : #include "otx_ep_rxtx.h"
7 : :
8 : : static uint32_t
9 : 0 : cnxk_vf_update_read_index(struct otx_ep_instr_queue *iq)
10 : : {
11 : : uint32_t val;
12 : :
13 : : /* Batch subtractions from the HW counter to reduce PCIe traffic
14 : : * This adds an extra local variable, but almost halves the
15 : : * number of PCIe writes.
16 : : */
17 : 0 : val = __atomic_load_n(iq->inst_cnt_ism, __ATOMIC_RELAXED);
18 : 0 : iq->inst_cnt += val - iq->inst_cnt_ism_prev;
19 : 0 : iq->inst_cnt_ism_prev = val;
20 : :
21 [ # # ]: 0 : if (val > (uint32_t)(1 << 31)) {
22 : : /* Only subtract the packet count in the HW counter
23 : : * when count above halfway to saturation.
24 : : */
25 : 0 : rte_write64((uint64_t)val, iq->inst_cnt_reg);
26 : : rte_mb();
27 : :
28 : 0 : rte_write64(OTX2_SDP_REQUEST_ISM, iq->inst_cnt_reg);
29 [ # # ]: 0 : while (__atomic_load_n(iq->inst_cnt_ism, __ATOMIC_RELAXED) >= val) {
30 : 0 : rte_write64(OTX2_SDP_REQUEST_ISM, iq->inst_cnt_reg);
31 : : rte_mb();
32 : : }
33 : :
34 : 0 : iq->inst_cnt_ism_prev = 0;
35 : : }
36 : 0 : rte_write64(OTX2_SDP_REQUEST_ISM, iq->inst_cnt_reg);
37 : :
38 : : /* Modulo of the new index with the IQ size will give us
39 : : * the new index.
40 : : */
41 : 0 : return iq->inst_cnt & (iq->nb_desc - 1);
42 : : }
43 : :
44 : : static inline void
45 : 0 : cnxk_ep_flush_iq(struct otx_ep_instr_queue *iq)
46 : : {
47 : : uint32_t instr_processed = 0;
48 : : uint32_t cnt = 0;
49 : :
50 : 0 : iq->otx_read_index = cnxk_vf_update_read_index(iq);
51 : :
52 [ # # ]: 0 : if (unlikely(iq->flush_index == iq->otx_read_index))
53 : : return;
54 : :
55 [ # # ]: 0 : if (iq->flush_index < iq->otx_read_index) {
56 : 0 : instr_processed = iq->otx_read_index - iq->flush_index;
57 : 0 : rte_pktmbuf_free_bulk(&iq->mbuf_list[iq->flush_index], instr_processed);
58 : 0 : iq->flush_index = otx_ep_incr_index(iq->flush_index, instr_processed, iq->nb_desc);
59 : : } else {
60 : 0 : cnt = iq->nb_desc - iq->flush_index;
61 : 0 : rte_pktmbuf_free_bulk(&iq->mbuf_list[iq->flush_index], cnt);
62 : 0 : iq->flush_index = otx_ep_incr_index(iq->flush_index, cnt, iq->nb_desc);
63 : :
64 : 0 : instr_processed = iq->otx_read_index;
65 : 0 : rte_pktmbuf_free_bulk(&iq->mbuf_list[iq->flush_index], instr_processed);
66 : 0 : iq->flush_index = otx_ep_incr_index(iq->flush_index, instr_processed, iq->nb_desc);
67 : :
68 : 0 : instr_processed += cnt;
69 : : }
70 : :
71 : 0 : iq->stats.instr_processed = instr_processed;
72 : 0 : iq->instr_pending -= instr_processed;
73 : : }
74 : :
75 : : static inline void
76 : : set_sg_size(struct otx_ep_sg_entry *sg_entry, uint16_t size, uint32_t pos)
77 : : {
78 : : #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
79 : : sg_entry->u.size[pos] = size;
80 : : #elif RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
81 : 0 : sg_entry->u.size[(OTX_EP_NUM_SG_PTRS - 1) - pos] = size;
82 : : #endif
83 : : }
84 : :
85 : : static __rte_always_inline void
86 : : cnxk_ep_xmit_pkts_scalar(struct rte_mbuf **tx_pkts, struct otx_ep_instr_queue *iq, uint16_t nb_pkts)
87 : : {
88 : : struct cnxk_ep_instr_32B *iqcmd;
89 : : struct rte_mbuf *m;
90 : : uint32_t pkt_len;
91 : : uint32_t tx_bytes = 0;
92 : 0 : uint32_t write_idx = iq->host_write_index;
93 : : uint16_t pkts, nb_desc = iq->nb_desc;
94 : 0 : uint8_t desc_size = iq->desc_size;
95 : :
96 [ # # ]: 0 : for (pkts = 0; pkts < nb_pkts; pkts++) {
97 : 0 : m = tx_pkts[pkts];
98 : 0 : iq->mbuf_list[write_idx] = m;
99 : 0 : pkt_len = rte_pktmbuf_data_len(m);
100 : :
101 : 0 : iqcmd = (struct cnxk_ep_instr_32B *)(iq->base_addr + (write_idx * desc_size));
102 : 0 : iqcmd->ih.u64 = iq->partial_ih | pkt_len;
103 : 0 : iqcmd->dptr = rte_mbuf_data_iova(m); /*dptr*/
104 : 0 : tx_bytes += pkt_len;
105 : :
106 : : /* Increment the host write index */
107 : : write_idx = otx_ep_incr_index(write_idx, 1, nb_desc);
108 : : }
109 : 0 : iq->host_write_index = write_idx;
110 : :
111 : : /* ring dbell */
112 : 0 : rte_io_wmb();
113 : 0 : rte_write64(pkts, iq->doorbell_reg);
114 : 0 : iq->instr_pending += pkts;
115 : 0 : iq->stats.tx_pkts += pkts;
116 : 0 : iq->stats.tx_bytes += tx_bytes;
117 : : }
118 : :
119 : : static __rte_always_inline uint16_t
120 : : cnxk_ep_xmit_pkts_scalar_mseg(struct rte_mbuf **tx_pkts, struct otx_ep_instr_queue *iq,
121 : : uint16_t nb_pkts)
122 : : {
123 : : uint16_t frags, num_sg, mask = OTX_EP_NUM_SG_PTRS - 1;
124 : : struct otx_ep_buf_free_info *finfo;
125 : : struct cnxk_ep_instr_32B *iqcmd;
126 : : struct rte_mbuf *m;
127 : : uint32_t pkt_len, tx_bytes = 0;
128 : 0 : uint32_t write_idx = iq->host_write_index;
129 : : uint16_t pkts, nb_desc = iq->nb_desc;
130 : 0 : uint8_t desc_size = iq->desc_size;
131 : :
132 [ # # ]: 0 : for (pkts = 0; pkts < nb_pkts; pkts++) {
133 : : uint16_t j = 0;
134 : :
135 : 0 : m = tx_pkts[pkts];
136 : 0 : frags = m->nb_segs;
137 : :
138 : 0 : pkt_len = rte_pktmbuf_pkt_len(m);
139 : 0 : num_sg = (frags + mask) / OTX_EP_NUM_SG_PTRS;
140 : :
141 [ # # ]: 0 : if (unlikely(pkt_len > OTX_EP_MAX_PKT_SZ && num_sg > OTX_EP_MAX_SG_LISTS)) {
142 : 0 : otx_ep_err("Failed to xmit the pkt, pkt_len is higher or pkt has more segments\n");
143 : 0 : goto exit;
144 : : }
145 : :
146 : 0 : finfo = &iq->req_list[write_idx].finfo;
147 : :
148 : 0 : iq->mbuf_list[write_idx] = m;
149 : 0 : iqcmd = (struct cnxk_ep_instr_32B *)(iq->base_addr + (write_idx * desc_size));
150 : 0 : iqcmd->dptr = rte_mem_virt2iova(finfo->g.sg);
151 : 0 : iqcmd->ih.u64 = iq->partial_ih | (1ULL << 62) | ((uint64_t)frags << 48) | pkt_len;
152 : :
153 [ # # ]: 0 : while (frags--) {
154 : 0 : finfo->g.sg[(j >> 2)].ptr[(j & mask)] = rte_mbuf_data_iova(m);
155 : 0 : set_sg_size(&finfo->g.sg[(j >> 2)], m->data_len, (j & mask));
156 : 0 : j++;
157 : 0 : m = m->next;
158 : : }
159 : :
160 : : /* Increment the host write index */
161 : : write_idx = otx_ep_incr_index(write_idx, 1, nb_desc);
162 : 0 : tx_bytes += pkt_len;
163 : : }
164 : 0 : exit:
165 : 0 : iq->host_write_index = write_idx;
166 : :
167 : : /* ring dbell */
168 : 0 : rte_io_wmb();
169 : 0 : rte_write64(pkts, iq->doorbell_reg);
170 : 0 : iq->instr_pending += pkts;
171 : 0 : iq->stats.tx_pkts += pkts;
172 : 0 : iq->stats.tx_bytes += tx_bytes;
173 : :
174 : : return pkts;
175 : : }
176 : :
177 : : uint16_t __rte_noinline __rte_hot
178 : 0 : cnxk_ep_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
179 : : {
180 : : struct otx_ep_instr_queue *iq = (struct otx_ep_instr_queue *)tx_queue;
181 : : uint16_t pkts;
182 : :
183 : 0 : pkts = RTE_MIN(nb_pkts, iq->nb_desc - iq->instr_pending);
184 : :
185 : : cnxk_ep_xmit_pkts_scalar(tx_pkts, iq, pkts);
186 : :
187 [ # # ]: 0 : if (iq->instr_pending >= OTX_EP_MAX_INSTR)
188 : 0 : cnxk_ep_flush_iq(iq);
189 : :
190 : : /* Return no# of instructions posted successfully. */
191 : 0 : return pkts;
192 : : }
193 : :
194 : : uint16_t __rte_noinline __rte_hot
195 : 0 : cnxk_ep_xmit_pkts_mseg(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
196 : : {
197 : : struct otx_ep_instr_queue *iq = (struct otx_ep_instr_queue *)tx_queue;
198 : : uint16_t pkts;
199 : :
200 : 0 : pkts = RTE_MIN(nb_pkts, iq->nb_desc - iq->instr_pending);
201 : :
202 : : pkts = cnxk_ep_xmit_pkts_scalar_mseg(tx_pkts, iq, pkts);
203 : :
204 [ # # ]: 0 : if (iq->instr_pending >= OTX_EP_MAX_INSTR)
205 : 0 : cnxk_ep_flush_iq(iq);
206 : :
207 : : /* Return no# of instructions posted successfully. */
208 : 0 : return pkts;
209 : : }
|