15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
25566a3e3SBruce Richardson * Copyright(c) 2016-2017 Intel Corporation
3617995dfSBruce Richardson */
4617995dfSBruce Richardson
5617995dfSBruce Richardson #include <rte_ring.h>
6617995dfSBruce Richardson #include <rte_hash_crc.h>
786aed50aSBruce Richardson #include <rte_event_ring.h>
8617995dfSBruce Richardson #include "sw_evdev.h"
9dca926caSGage Eads #include "iq_chunk.h"
1070207f35SRadu Nicolau #include "event_ring.h"
11617995dfSBruce Richardson
12617995dfSBruce Richardson #define SW_IQS_MASK (SW_IQS_MAX-1)
13617995dfSBruce Richardson
14617995dfSBruce Richardson /* Retrieve the highest priority IQ or -1 if no pkts available. Doing the
15617995dfSBruce Richardson * CLZ twice is faster than caching the value due to data dependencies
16617995dfSBruce Richardson */
17617995dfSBruce Richardson #define PKT_MASK_TO_IQ(pkts) \
183d4e27fdSDavid Marchand (rte_ctz32(pkts | (1 << SW_IQS_MAX)))
19617995dfSBruce Richardson
20617995dfSBruce Richardson #if SW_IQS_MAX != 4
21617995dfSBruce Richardson #error Misconfigured PRIO_TO_IQ caused by SW_IQS_MAX value change
22617995dfSBruce Richardson #endif
23617995dfSBruce Richardson #define PRIO_TO_IQ(prio) (prio >> 6)
24617995dfSBruce Richardson
25617995dfSBruce Richardson #define MAX_PER_IQ_DEQUEUE 48
26617995dfSBruce Richardson #define FLOWID_MASK (SW_QID_NUM_FIDS-1)
277904c82aSHarry van Haaren /* use cheap bit mixing, we only need to lose a few bits */
287904c82aSHarry van Haaren #define SW_HASH_FLOWID(f) (((f) ^ (f >> 10)) & FLOWID_MASK)
29617995dfSBruce Richardson
3070207f35SRadu Nicolau
31617995dfSBruce Richardson static inline uint32_t
sw_schedule_atomic_to_cq(struct sw_evdev * sw,struct sw_qid * const qid,uint32_t iq_num,unsigned int count)32617995dfSBruce Richardson sw_schedule_atomic_to_cq(struct sw_evdev *sw, struct sw_qid * const qid,
33617995dfSBruce Richardson uint32_t iq_num, unsigned int count)
34617995dfSBruce Richardson {
35617995dfSBruce Richardson struct rte_event qes[MAX_PER_IQ_DEQUEUE]; /* count <= MAX */
36617995dfSBruce Richardson struct rte_event blocked_qes[MAX_PER_IQ_DEQUEUE];
37617995dfSBruce Richardson uint32_t nb_blocked = 0;
38617995dfSBruce Richardson uint32_t i;
39617995dfSBruce Richardson
40617995dfSBruce Richardson if (count > MAX_PER_IQ_DEQUEUE)
41617995dfSBruce Richardson count = MAX_PER_IQ_DEQUEUE;
42617995dfSBruce Richardson
43617995dfSBruce Richardson /* This is the QID ID. The QID ID is static, hence it can be
44617995dfSBruce Richardson * used to identify the stage of processing in history lists etc
45617995dfSBruce Richardson */
46617995dfSBruce Richardson uint32_t qid_id = qid->id;
47617995dfSBruce Richardson
48dca926caSGage Eads iq_dequeue_burst(sw, &qid->iq[iq_num], qes, count);
49617995dfSBruce Richardson for (i = 0; i < count; i++) {
50617995dfSBruce Richardson const struct rte_event *qe = &qes[i];
517904c82aSHarry van Haaren const uint16_t flow_id = SW_HASH_FLOWID(qes[i].flow_id);
52617995dfSBruce Richardson struct sw_fid_t *fid = &qid->fids[flow_id];
53617995dfSBruce Richardson int cq = fid->cq;
54617995dfSBruce Richardson
55617995dfSBruce Richardson if (cq < 0) {
56733fc6caSHarry van Haaren uint32_t cq_idx;
57733fc6caSHarry van Haaren if (qid->cq_next_tx >= qid->cq_num_mapped_cqs)
58617995dfSBruce Richardson qid->cq_next_tx = 0;
59733fc6caSHarry van Haaren cq_idx = qid->cq_next_tx++;
60733fc6caSHarry van Haaren
61617995dfSBruce Richardson cq = qid->cq_map[cq_idx];
62617995dfSBruce Richardson
63617995dfSBruce Richardson /* find least used */
64617995dfSBruce Richardson int cq_free_cnt = sw->cq_ring_space[cq];
65617995dfSBruce Richardson for (cq_idx = 0; cq_idx < qid->cq_num_mapped_cqs;
66617995dfSBruce Richardson cq_idx++) {
67617995dfSBruce Richardson int test_cq = qid->cq_map[cq_idx];
68617995dfSBruce Richardson int test_cq_free = sw->cq_ring_space[test_cq];
69617995dfSBruce Richardson if (test_cq_free > cq_free_cnt) {
70617995dfSBruce Richardson cq = test_cq;
71617995dfSBruce Richardson cq_free_cnt = test_cq_free;
72617995dfSBruce Richardson }
73617995dfSBruce Richardson }
74617995dfSBruce Richardson
75617995dfSBruce Richardson fid->cq = cq; /* this pins early */
76617995dfSBruce Richardson }
77617995dfSBruce Richardson
78617995dfSBruce Richardson if (sw->cq_ring_space[cq] == 0 ||
79617995dfSBruce Richardson sw->ports[cq].inflights == SW_PORT_HIST_LIST) {
80617995dfSBruce Richardson blocked_qes[nb_blocked++] = *qe;
81617995dfSBruce Richardson continue;
82617995dfSBruce Richardson }
83617995dfSBruce Richardson
84617995dfSBruce Richardson struct sw_port *p = &sw->ports[cq];
85617995dfSBruce Richardson
86617995dfSBruce Richardson /* at this point we can queue up the packet on the cq_buf */
87617995dfSBruce Richardson fid->pcount++;
88617995dfSBruce Richardson p->cq_buf[p->cq_buf_count++] = *qe;
89617995dfSBruce Richardson p->inflights++;
90617995dfSBruce Richardson sw->cq_ring_space[cq]--;
91617995dfSBruce Richardson
92617995dfSBruce Richardson int head = (p->hist_head++ & (SW_PORT_HIST_LIST-1));
93*5078a8f3SHarry van Haaren p->hist_list[head] = (struct sw_hist_list_entry) {
94*5078a8f3SHarry van Haaren .qid = qid_id,
95*5078a8f3SHarry van Haaren .fid = flow_id,
96*5078a8f3SHarry van Haaren };
97617995dfSBruce Richardson
98617995dfSBruce Richardson p->stats.tx_pkts++;
99617995dfSBruce Richardson qid->stats.tx_pkts++;
1000e1eadd0SHarry van Haaren qid->to_port[cq]++;
101617995dfSBruce Richardson
102617995dfSBruce Richardson /* if we just filled in the last slot, flush the buffer */
103617995dfSBruce Richardson if (sw->cq_ring_space[cq] == 0) {
10486aed50aSBruce Richardson struct rte_event_ring *worker = p->cq_worker_ring;
10586aed50aSBruce Richardson rte_event_ring_enqueue_burst(worker, p->cq_buf,
106617995dfSBruce Richardson p->cq_buf_count,
107617995dfSBruce Richardson &sw->cq_ring_space[cq]);
108617995dfSBruce Richardson p->cq_buf_count = 0;
109617995dfSBruce Richardson }
110617995dfSBruce Richardson }
111dca926caSGage Eads iq_put_back(sw, &qid->iq[iq_num], blocked_qes, nb_blocked);
112617995dfSBruce Richardson
113617995dfSBruce Richardson return count - nb_blocked;
114617995dfSBruce Richardson }
115617995dfSBruce Richardson
116617995dfSBruce Richardson static inline uint32_t
sw_schedule_parallel_to_cq(struct sw_evdev * sw,struct sw_qid * const qid,uint32_t iq_num,unsigned int count,int keep_order)117617995dfSBruce Richardson sw_schedule_parallel_to_cq(struct sw_evdev *sw, struct sw_qid * const qid,
118617995dfSBruce Richardson uint32_t iq_num, unsigned int count, int keep_order)
119617995dfSBruce Richardson {
120617995dfSBruce Richardson uint32_t i;
121617995dfSBruce Richardson uint32_t cq_idx = qid->cq_next_tx;
122617995dfSBruce Richardson
123617995dfSBruce Richardson /* This is the QID ID. The QID ID is static, hence it can be
124617995dfSBruce Richardson * used to identify the stage of processing in history lists etc
125617995dfSBruce Richardson */
126617995dfSBruce Richardson uint32_t qid_id = qid->id;
127617995dfSBruce Richardson
128617995dfSBruce Richardson if (count > MAX_PER_IQ_DEQUEUE)
129617995dfSBruce Richardson count = MAX_PER_IQ_DEQUEUE;
130617995dfSBruce Richardson
131617995dfSBruce Richardson if (keep_order)
132617995dfSBruce Richardson /* only schedule as many as we have reorder buffer entries */
133617995dfSBruce Richardson count = RTE_MIN(count,
13470207f35SRadu Nicolau rob_ring_count(qid->reorder_buffer_freelist));
135617995dfSBruce Richardson
136617995dfSBruce Richardson for (i = 0; i < count; i++) {
137dca926caSGage Eads const struct rte_event *qe = iq_peek(&qid->iq[iq_num]);
138617995dfSBruce Richardson uint32_t cq_check_count = 0;
139617995dfSBruce Richardson uint32_t cq;
140617995dfSBruce Richardson
141617995dfSBruce Richardson /*
142617995dfSBruce Richardson * for parallel, just send to next available CQ in round-robin
143617995dfSBruce Richardson * fashion. So scan for an available CQ. If all CQs are full
144617995dfSBruce Richardson * just return and move on to next QID
145617995dfSBruce Richardson */
146617995dfSBruce Richardson do {
147617995dfSBruce Richardson if (++cq_check_count > qid->cq_num_mapped_cqs)
148617995dfSBruce Richardson goto exit;
149733fc6caSHarry van Haaren if (cq_idx >= qid->cq_num_mapped_cqs)
150617995dfSBruce Richardson cq_idx = 0;
151733fc6caSHarry van Haaren cq = qid->cq_map[cq_idx++];
152733fc6caSHarry van Haaren
15370207f35SRadu Nicolau } while (sw->ports[cq].inflights == SW_PORT_HIST_LIST ||
15470207f35SRadu Nicolau rte_event_ring_free_count(
15570207f35SRadu Nicolau sw->ports[cq].cq_worker_ring) == 0);
156617995dfSBruce Richardson
157617995dfSBruce Richardson struct sw_port *p = &sw->ports[cq];
158617995dfSBruce Richardson if (sw->cq_ring_space[cq] == 0 ||
159617995dfSBruce Richardson p->inflights == SW_PORT_HIST_LIST)
160617995dfSBruce Richardson break;
161617995dfSBruce Richardson
162617995dfSBruce Richardson sw->cq_ring_space[cq]--;
163617995dfSBruce Richardson
164617995dfSBruce Richardson qid->stats.tx_pkts++;
165617995dfSBruce Richardson
166617995dfSBruce Richardson const int head = (p->hist_head & (SW_PORT_HIST_LIST-1));
167*5078a8f3SHarry van Haaren p->hist_list[head] = (struct sw_hist_list_entry) {
168*5078a8f3SHarry van Haaren .qid = qid_id,
169*5078a8f3SHarry van Haaren .fid = SW_HASH_FLOWID(qe->flow_id),
170*5078a8f3SHarry van Haaren };
171617995dfSBruce Richardson
172617995dfSBruce Richardson if (keep_order)
17370207f35SRadu Nicolau rob_ring_dequeue(qid->reorder_buffer_freelist,
174617995dfSBruce Richardson (void *)&p->hist_list[head].rob_entry);
175617995dfSBruce Richardson
176617995dfSBruce Richardson sw->ports[cq].cq_buf[sw->ports[cq].cq_buf_count++] = *qe;
177dca926caSGage Eads iq_pop(sw, &qid->iq[iq_num]);
178617995dfSBruce Richardson
179617995dfSBruce Richardson rte_compiler_barrier();
180617995dfSBruce Richardson p->inflights++;
181617995dfSBruce Richardson p->stats.tx_pkts++;
182617995dfSBruce Richardson p->hist_head++;
183617995dfSBruce Richardson }
184617995dfSBruce Richardson exit:
185617995dfSBruce Richardson qid->cq_next_tx = cq_idx;
186617995dfSBruce Richardson return i;
187617995dfSBruce Richardson }
188617995dfSBruce Richardson
189617995dfSBruce Richardson static uint32_t
sw_schedule_dir_to_cq(struct sw_evdev * sw,struct sw_qid * const qid,uint32_t iq_num,unsigned int count __rte_unused)190617995dfSBruce Richardson sw_schedule_dir_to_cq(struct sw_evdev *sw, struct sw_qid * const qid,
191617995dfSBruce Richardson uint32_t iq_num, unsigned int count __rte_unused)
192617995dfSBruce Richardson {
193617995dfSBruce Richardson uint32_t cq_id = qid->cq_map[0];
194617995dfSBruce Richardson struct sw_port *port = &sw->ports[cq_id];
195617995dfSBruce Richardson
196617995dfSBruce Richardson /* get max burst enq size for cq_ring */
197617995dfSBruce Richardson uint32_t count_free = sw->cq_ring_space[cq_id];
198617995dfSBruce Richardson if (count_free == 0)
199617995dfSBruce Richardson return 0;
200617995dfSBruce Richardson
201617995dfSBruce Richardson /* burst dequeue from the QID IQ ring */
202dca926caSGage Eads struct sw_iq *iq = &qid->iq[iq_num];
203dca926caSGage Eads uint32_t ret = iq_dequeue_burst(sw, iq,
204617995dfSBruce Richardson &port->cq_buf[port->cq_buf_count], count_free);
205617995dfSBruce Richardson port->cq_buf_count += ret;
206617995dfSBruce Richardson
207617995dfSBruce Richardson /* Update QID, Port and Total TX stats */
208617995dfSBruce Richardson qid->stats.tx_pkts += ret;
209617995dfSBruce Richardson port->stats.tx_pkts += ret;
210617995dfSBruce Richardson
211617995dfSBruce Richardson /* Subtract credits from cached value */
212617995dfSBruce Richardson sw->cq_ring_space[cq_id] -= ret;
213617995dfSBruce Richardson
214617995dfSBruce Richardson return ret;
215617995dfSBruce Richardson }
216617995dfSBruce Richardson
217617995dfSBruce Richardson static uint32_t
sw_schedule_qid_to_cq(struct sw_evdev * sw)218617995dfSBruce Richardson sw_schedule_qid_to_cq(struct sw_evdev *sw)
219617995dfSBruce Richardson {
220617995dfSBruce Richardson uint32_t pkts = 0;
221617995dfSBruce Richardson uint32_t qid_idx;
222617995dfSBruce Richardson
223617995dfSBruce Richardson sw->sched_cq_qid_called++;
224617995dfSBruce Richardson
225617995dfSBruce Richardson for (qid_idx = 0; qid_idx < sw->qid_count; qid_idx++) {
226617995dfSBruce Richardson struct sw_qid *qid = sw->qids_prioritized[qid_idx];
227617995dfSBruce Richardson
228617995dfSBruce Richardson int type = qid->type;
229617995dfSBruce Richardson int iq_num = PKT_MASK_TO_IQ(qid->iq_pkt_mask);
230617995dfSBruce Richardson
231617995dfSBruce Richardson /* zero mapped CQs indicates directed */
232733fc6caSHarry van Haaren if (iq_num >= SW_IQS_MAX || qid->cq_num_mapped_cqs == 0)
233617995dfSBruce Richardson continue;
234617995dfSBruce Richardson
235617995dfSBruce Richardson uint32_t pkts_done = 0;
236dca926caSGage Eads uint32_t count = iq_count(&qid->iq[iq_num]);
237617995dfSBruce Richardson
23870207f35SRadu Nicolau if (count >= sw->sched_min_burst) {
239617995dfSBruce Richardson if (type == SW_SCHED_TYPE_DIRECT)
240617995dfSBruce Richardson pkts_done += sw_schedule_dir_to_cq(sw, qid,
241617995dfSBruce Richardson iq_num, count);
242617995dfSBruce Richardson else if (type == RTE_SCHED_TYPE_ATOMIC)
243617995dfSBruce Richardson pkts_done += sw_schedule_atomic_to_cq(sw, qid,
244617995dfSBruce Richardson iq_num, count);
245617995dfSBruce Richardson else
246617995dfSBruce Richardson pkts_done += sw_schedule_parallel_to_cq(sw, qid,
247617995dfSBruce Richardson iq_num, count,
248617995dfSBruce Richardson type == RTE_SCHED_TYPE_ORDERED);
249617995dfSBruce Richardson }
250617995dfSBruce Richardson
251617995dfSBruce Richardson /* Check if the IQ that was polled is now empty, and unset it
252617995dfSBruce Richardson * in the IQ mask if its empty.
253617995dfSBruce Richardson */
254617995dfSBruce Richardson int all_done = (pkts_done == count);
255617995dfSBruce Richardson
256617995dfSBruce Richardson qid->iq_pkt_mask &= ~(all_done << (iq_num));
257617995dfSBruce Richardson pkts += pkts_done;
258617995dfSBruce Richardson }
259617995dfSBruce Richardson
260617995dfSBruce Richardson return pkts;
261617995dfSBruce Richardson }
262617995dfSBruce Richardson
263617995dfSBruce Richardson /* This function will perform re-ordering of packets, and injecting into
264617995dfSBruce Richardson * the appropriate QID IQ. As LB and DIR QIDs are in the same array, but *NOT*
265617995dfSBruce Richardson * contiguous in that array, this function accepts a "range" of QIDs to scan.
266617995dfSBruce Richardson */
267617995dfSBruce Richardson static uint16_t
sw_schedule_reorder(struct sw_evdev * sw,int qid_start,int qid_end)268617995dfSBruce Richardson sw_schedule_reorder(struct sw_evdev *sw, int qid_start, int qid_end)
269617995dfSBruce Richardson {
270617995dfSBruce Richardson /* Perform egress reordering */
271617995dfSBruce Richardson struct rte_event *qe;
272617995dfSBruce Richardson uint32_t pkts_iter = 0;
273617995dfSBruce Richardson
274617995dfSBruce Richardson for (; qid_start < qid_end; qid_start++) {
275617995dfSBruce Richardson struct sw_qid *qid = &sw->qids[qid_start];
27670207f35SRadu Nicolau unsigned int i, num_entries_in_use;
277617995dfSBruce Richardson
278617995dfSBruce Richardson if (qid->type != RTE_SCHED_TYPE_ORDERED)
279617995dfSBruce Richardson continue;
280617995dfSBruce Richardson
28170207f35SRadu Nicolau num_entries_in_use = rob_ring_free_count(
282617995dfSBruce Richardson qid->reorder_buffer_freelist);
283617995dfSBruce Richardson
28470207f35SRadu Nicolau if (num_entries_in_use < sw->sched_min_burst)
28570207f35SRadu Nicolau num_entries_in_use = 0;
28670207f35SRadu Nicolau
287617995dfSBruce Richardson for (i = 0; i < num_entries_in_use; i++) {
288617995dfSBruce Richardson struct reorder_buffer_entry *entry;
289617995dfSBruce Richardson int j;
290617995dfSBruce Richardson
291617995dfSBruce Richardson entry = &qid->reorder_buffer[qid->reorder_buffer_index];
292617995dfSBruce Richardson
293617995dfSBruce Richardson if (!entry->ready)
294617995dfSBruce Richardson break;
295617995dfSBruce Richardson
296617995dfSBruce Richardson for (j = 0; j < entry->num_fragments; j++) {
297617995dfSBruce Richardson uint16_t dest_qid;
298617995dfSBruce Richardson uint16_t dest_iq;
299617995dfSBruce Richardson
300617995dfSBruce Richardson int idx = entry->fragment_index + j;
301617995dfSBruce Richardson qe = &entry->fragments[idx];
302617995dfSBruce Richardson
303617995dfSBruce Richardson dest_qid = qe->queue_id;
304617995dfSBruce Richardson dest_iq = PRIO_TO_IQ(qe->priority);
305617995dfSBruce Richardson
306617995dfSBruce Richardson if (dest_qid >= sw->qid_count) {
307617995dfSBruce Richardson sw->stats.rx_dropped++;
308617995dfSBruce Richardson continue;
309617995dfSBruce Richardson }
310617995dfSBruce Richardson
311617995dfSBruce Richardson pkts_iter++;
312617995dfSBruce Richardson
313617995dfSBruce Richardson struct sw_qid *q = &sw->qids[dest_qid];
314dca926caSGage Eads struct sw_iq *iq = &q->iq[dest_iq];
315617995dfSBruce Richardson
316617995dfSBruce Richardson /* we checked for space above, so enqueue must
317617995dfSBruce Richardson * succeed
318617995dfSBruce Richardson */
319dca926caSGage Eads iq_enqueue(sw, iq, qe);
320617995dfSBruce Richardson q->iq_pkt_mask |= (1 << (dest_iq));
321617995dfSBruce Richardson q->iq_pkt_count[dest_iq]++;
322617995dfSBruce Richardson q->stats.rx_pkts++;
323617995dfSBruce Richardson }
324617995dfSBruce Richardson
325617995dfSBruce Richardson entry->ready = (j != entry->num_fragments);
326617995dfSBruce Richardson entry->num_fragments -= j;
327617995dfSBruce Richardson entry->fragment_index += j;
328617995dfSBruce Richardson
329617995dfSBruce Richardson if (!entry->ready) {
330617995dfSBruce Richardson entry->fragment_index = 0;
331617995dfSBruce Richardson
33270207f35SRadu Nicolau rob_ring_enqueue(
333617995dfSBruce Richardson qid->reorder_buffer_freelist,
334617995dfSBruce Richardson entry);
335617995dfSBruce Richardson
336617995dfSBruce Richardson qid->reorder_buffer_index++;
337617995dfSBruce Richardson qid->reorder_buffer_index %= qid->window_size;
338617995dfSBruce Richardson }
339617995dfSBruce Richardson }
340617995dfSBruce Richardson }
341617995dfSBruce Richardson return pkts_iter;
342617995dfSBruce Richardson }
343617995dfSBruce Richardson
344c0583d98SJerin Jacob static __rte_always_inline void
sw_refill_pp_buf(struct sw_evdev * sw,struct sw_port * port)345617995dfSBruce Richardson sw_refill_pp_buf(struct sw_evdev *sw, struct sw_port *port)
346617995dfSBruce Richardson {
347617995dfSBruce Richardson RTE_SET_USED(sw);
34886aed50aSBruce Richardson struct rte_event_ring *worker = port->rx_worker_ring;
349617995dfSBruce Richardson port->pp_buf_start = 0;
35086aed50aSBruce Richardson port->pp_buf_count = rte_event_ring_dequeue_burst(worker, port->pp_buf,
35170207f35SRadu Nicolau sw->sched_deq_burst_size, NULL);
352617995dfSBruce Richardson }
353617995dfSBruce Richardson
354c0583d98SJerin Jacob static __rte_always_inline uint32_t
__pull_port_lb(struct sw_evdev * sw,uint32_t port_id,int allow_reorder)355617995dfSBruce Richardson __pull_port_lb(struct sw_evdev *sw, uint32_t port_id, int allow_reorder)
356617995dfSBruce Richardson {
357fa865c01SFerruh Yigit static struct reorder_buffer_entry dummy_rob;
358617995dfSBruce Richardson uint32_t pkts_iter = 0;
359617995dfSBruce Richardson struct sw_port *port = &sw->ports[port_id];
360617995dfSBruce Richardson
361617995dfSBruce Richardson /* If shadow ring has 0 pkts, pull from worker ring */
36270207f35SRadu Nicolau if (!sw->refill_once_per_iter && port->pp_buf_count == 0)
363617995dfSBruce Richardson sw_refill_pp_buf(sw, port);
364617995dfSBruce Richardson
365617995dfSBruce Richardson while (port->pp_buf_count) {
366617995dfSBruce Richardson const struct rte_event *qe = &port->pp_buf[port->pp_buf_start];
367617995dfSBruce Richardson struct sw_hist_list_entry *hist_entry = NULL;
368617995dfSBruce Richardson uint8_t flags = qe->op;
369617995dfSBruce Richardson const uint16_t eop = !(flags & QE_FLAG_NOT_EOP);
370617995dfSBruce Richardson int needs_reorder = 0;
371617995dfSBruce Richardson /* if no-reordering, having PARTIAL == NEW */
372617995dfSBruce Richardson if (!allow_reorder && !eop)
373617995dfSBruce Richardson flags = QE_FLAG_VALID;
374617995dfSBruce Richardson
375617995dfSBruce Richardson uint32_t iq_num = PRIO_TO_IQ(qe->priority);
376617995dfSBruce Richardson struct sw_qid *qid = &sw->qids[qe->queue_id];
377617995dfSBruce Richardson
378617995dfSBruce Richardson /* now process based on flags. Note that for directed
379617995dfSBruce Richardson * queues, the enqueue_flush masks off all but the
380617995dfSBruce Richardson * valid flag. This makes FWD and PARTIAL enqueues just
381617995dfSBruce Richardson * NEW type, and makes DROPS no-op calls.
382617995dfSBruce Richardson */
383617995dfSBruce Richardson if ((flags & QE_FLAG_COMPLETE) && port->inflights > 0) {
384617995dfSBruce Richardson const uint32_t hist_tail = port->hist_tail &
385617995dfSBruce Richardson (SW_PORT_HIST_LIST - 1);
386617995dfSBruce Richardson
387617995dfSBruce Richardson hist_entry = &port->hist_list[hist_tail];
388617995dfSBruce Richardson const uint32_t hist_qid = hist_entry->qid;
389617995dfSBruce Richardson const uint32_t hist_fid = hist_entry->fid;
390617995dfSBruce Richardson
391617995dfSBruce Richardson struct sw_fid_t *fid =
392617995dfSBruce Richardson &sw->qids[hist_qid].fids[hist_fid];
393617995dfSBruce Richardson fid->pcount -= eop;
394617995dfSBruce Richardson if (fid->pcount == 0)
395617995dfSBruce Richardson fid->cq = -1;
396617995dfSBruce Richardson
397617995dfSBruce Richardson if (allow_reorder) {
398617995dfSBruce Richardson /* set reorder ready if an ordered QID */
399617995dfSBruce Richardson uintptr_t rob_ptr =
400617995dfSBruce Richardson (uintptr_t)hist_entry->rob_entry;
401617995dfSBruce Richardson const uintptr_t valid = (rob_ptr != 0);
402617995dfSBruce Richardson needs_reorder = valid;
403617995dfSBruce Richardson rob_ptr |=
404617995dfSBruce Richardson ((valid - 1) & (uintptr_t)&dummy_rob);
405617995dfSBruce Richardson struct reorder_buffer_entry *tmp_rob_ptr =
406617995dfSBruce Richardson (struct reorder_buffer_entry *)rob_ptr;
407617995dfSBruce Richardson tmp_rob_ptr->ready = eop * needs_reorder;
408617995dfSBruce Richardson }
409617995dfSBruce Richardson
410617995dfSBruce Richardson port->inflights -= eop;
411617995dfSBruce Richardson port->hist_tail += eop;
412617995dfSBruce Richardson }
413617995dfSBruce Richardson if (flags & QE_FLAG_VALID) {
414617995dfSBruce Richardson port->stats.rx_pkts++;
415617995dfSBruce Richardson
416617995dfSBruce Richardson if (allow_reorder && needs_reorder) {
417617995dfSBruce Richardson struct reorder_buffer_entry *rob_entry =
418617995dfSBruce Richardson hist_entry->rob_entry;
419617995dfSBruce Richardson
420617995dfSBruce Richardson /* Although fragmentation not currently
421617995dfSBruce Richardson * supported by eventdev API, we support it
422617995dfSBruce Richardson * here. Open: How do we alert the user that
423617995dfSBruce Richardson * they've exceeded max frags?
424617995dfSBruce Richardson */
425617995dfSBruce Richardson int num_frag = rob_entry->num_fragments;
426617995dfSBruce Richardson if (num_frag == SW_FRAGMENTS_MAX)
427617995dfSBruce Richardson sw->stats.rx_dropped++;
428617995dfSBruce Richardson else {
429617995dfSBruce Richardson int idx = rob_entry->num_fragments++;
430617995dfSBruce Richardson rob_entry->fragments[idx] = *qe;
431617995dfSBruce Richardson }
432617995dfSBruce Richardson goto end_qe;
433617995dfSBruce Richardson }
434617995dfSBruce Richardson
435617995dfSBruce Richardson /* Use the iq_num from above to push the QE
436617995dfSBruce Richardson * into the qid at the right priority
437617995dfSBruce Richardson */
438617995dfSBruce Richardson
439617995dfSBruce Richardson qid->iq_pkt_mask |= (1 << (iq_num));
440dca926caSGage Eads iq_enqueue(sw, &qid->iq[iq_num], qe);
441617995dfSBruce Richardson qid->iq_pkt_count[iq_num]++;
442617995dfSBruce Richardson qid->stats.rx_pkts++;
443617995dfSBruce Richardson pkts_iter++;
444617995dfSBruce Richardson }
445617995dfSBruce Richardson
446617995dfSBruce Richardson end_qe:
447617995dfSBruce Richardson port->pp_buf_start++;
448617995dfSBruce Richardson port->pp_buf_count--;
449617995dfSBruce Richardson } /* while (avail_qes) */
450617995dfSBruce Richardson
451617995dfSBruce Richardson return pkts_iter;
452617995dfSBruce Richardson }
453617995dfSBruce Richardson
454617995dfSBruce Richardson static uint32_t
sw_schedule_pull_port_lb(struct sw_evdev * sw,uint32_t port_id)455617995dfSBruce Richardson sw_schedule_pull_port_lb(struct sw_evdev *sw, uint32_t port_id)
456617995dfSBruce Richardson {
457617995dfSBruce Richardson return __pull_port_lb(sw, port_id, 1);
458617995dfSBruce Richardson }
459617995dfSBruce Richardson
460617995dfSBruce Richardson static uint32_t
sw_schedule_pull_port_no_reorder(struct sw_evdev * sw,uint32_t port_id)461617995dfSBruce Richardson sw_schedule_pull_port_no_reorder(struct sw_evdev *sw, uint32_t port_id)
462617995dfSBruce Richardson {
463617995dfSBruce Richardson return __pull_port_lb(sw, port_id, 0);
464617995dfSBruce Richardson }
465617995dfSBruce Richardson
466617995dfSBruce Richardson static uint32_t
sw_schedule_pull_port_dir(struct sw_evdev * sw,uint32_t port_id)467617995dfSBruce Richardson sw_schedule_pull_port_dir(struct sw_evdev *sw, uint32_t port_id)
468617995dfSBruce Richardson {
469617995dfSBruce Richardson uint32_t pkts_iter = 0;
470617995dfSBruce Richardson struct sw_port *port = &sw->ports[port_id];
471617995dfSBruce Richardson
472617995dfSBruce Richardson /* If shadow ring has 0 pkts, pull from worker ring */
47370207f35SRadu Nicolau if (!sw->refill_once_per_iter && port->pp_buf_count == 0)
474617995dfSBruce Richardson sw_refill_pp_buf(sw, port);
475617995dfSBruce Richardson
476617995dfSBruce Richardson while (port->pp_buf_count) {
477617995dfSBruce Richardson const struct rte_event *qe = &port->pp_buf[port->pp_buf_start];
478617995dfSBruce Richardson uint8_t flags = qe->op;
479617995dfSBruce Richardson
480617995dfSBruce Richardson if ((flags & QE_FLAG_VALID) == 0)
481617995dfSBruce Richardson goto end_qe;
482617995dfSBruce Richardson
483617995dfSBruce Richardson uint32_t iq_num = PRIO_TO_IQ(qe->priority);
484617995dfSBruce Richardson struct sw_qid *qid = &sw->qids[qe->queue_id];
485dca926caSGage Eads struct sw_iq *iq = &qid->iq[iq_num];
486617995dfSBruce Richardson
487617995dfSBruce Richardson port->stats.rx_pkts++;
488617995dfSBruce Richardson
489617995dfSBruce Richardson /* Use the iq_num from above to push the QE
490617995dfSBruce Richardson * into the qid at the right priority
491617995dfSBruce Richardson */
492617995dfSBruce Richardson qid->iq_pkt_mask |= (1 << (iq_num));
493dca926caSGage Eads iq_enqueue(sw, iq, qe);
494617995dfSBruce Richardson qid->iq_pkt_count[iq_num]++;
495617995dfSBruce Richardson qid->stats.rx_pkts++;
496617995dfSBruce Richardson pkts_iter++;
497617995dfSBruce Richardson
498617995dfSBruce Richardson end_qe:
499617995dfSBruce Richardson port->pp_buf_start++;
500617995dfSBruce Richardson port->pp_buf_count--;
501617995dfSBruce Richardson } /* while port->pp_buf_count */
502617995dfSBruce Richardson
503617995dfSBruce Richardson return pkts_iter;
504617995dfSBruce Richardson }
505617995dfSBruce Richardson
5064689c579SMattias Rönnblom int32_t
sw_event_schedule(struct rte_eventdev * dev)507617995dfSBruce Richardson sw_event_schedule(struct rte_eventdev *dev)
508617995dfSBruce Richardson {
509617995dfSBruce Richardson struct sw_evdev *sw = sw_pmd_priv(dev);
510617995dfSBruce Richardson uint32_t in_pkts, out_pkts;
511617995dfSBruce Richardson uint32_t out_pkts_total = 0, in_pkts_total = 0;
512617995dfSBruce Richardson int32_t sched_quanta = sw->sched_quanta;
513617995dfSBruce Richardson uint32_t i;
514617995dfSBruce Richardson
515617995dfSBruce Richardson sw->sched_called++;
51663ddc002SVipin Varghese if (unlikely(!sw->started))
5174689c579SMattias Rönnblom return -EAGAIN;
518617995dfSBruce Richardson
519617995dfSBruce Richardson do {
520617995dfSBruce Richardson uint32_t in_pkts_this_iteration = 0;
521617995dfSBruce Richardson
522617995dfSBruce Richardson /* Pull from rx_ring for ports */
523617995dfSBruce Richardson do {
524617995dfSBruce Richardson in_pkts = 0;
525bd5ac24fSHarry van Haaren for (i = 0; i < sw->port_count; i++) {
526bd5ac24fSHarry van Haaren /* ack the unlinks in progress as done */
527bd5ac24fSHarry van Haaren if (sw->ports[i].unlinks_in_progress)
528bd5ac24fSHarry van Haaren sw->ports[i].unlinks_in_progress = 0;
529bd5ac24fSHarry van Haaren
530617995dfSBruce Richardson if (sw->ports[i].is_directed)
531617995dfSBruce Richardson in_pkts += sw_schedule_pull_port_dir(sw, i);
532617995dfSBruce Richardson else if (sw->ports[i].num_ordered_qids > 0)
533617995dfSBruce Richardson in_pkts += sw_schedule_pull_port_lb(sw, i);
534617995dfSBruce Richardson else
535617995dfSBruce Richardson in_pkts += sw_schedule_pull_port_no_reorder(sw, i);
536bd5ac24fSHarry van Haaren }
537617995dfSBruce Richardson
538617995dfSBruce Richardson /* QID scan for re-ordered */
539617995dfSBruce Richardson in_pkts += sw_schedule_reorder(sw, 0,
540617995dfSBruce Richardson sw->qid_count);
541617995dfSBruce Richardson in_pkts_this_iteration += in_pkts;
542617995dfSBruce Richardson } while (in_pkts > 4 &&
543617995dfSBruce Richardson (int)in_pkts_this_iteration < sched_quanta);
544617995dfSBruce Richardson
545e4dff550SVipin Varghese out_pkts = sw_schedule_qid_to_cq(sw);
546617995dfSBruce Richardson out_pkts_total += out_pkts;
547617995dfSBruce Richardson in_pkts_total += in_pkts_this_iteration;
548617995dfSBruce Richardson
549617995dfSBruce Richardson if (in_pkts == 0 && out_pkts == 0)
550617995dfSBruce Richardson break;
551617995dfSBruce Richardson } while ((int)out_pkts_total < sched_quanta);
552617995dfSBruce Richardson
553642bc2a3SVipin Varghese sw->stats.tx_pkts += out_pkts_total;
554642bc2a3SVipin Varghese sw->stats.rx_pkts += in_pkts_total;
555642bc2a3SVipin Varghese
556642bc2a3SVipin Varghese sw->sched_no_iq_enqueues += (in_pkts_total == 0);
557642bc2a3SVipin Varghese sw->sched_no_cq_enqueues += (out_pkts_total == 0);
558642bc2a3SVipin Varghese
559324b37e6SHarry van Haaren uint64_t work_done = (in_pkts_total + out_pkts_total) != 0;
560324b37e6SHarry van Haaren sw->sched_progress_last_iter = work_done;
561324b37e6SHarry van Haaren
562324b37e6SHarry van Haaren uint64_t cqs_scheds_last_iter = 0;
563324b37e6SHarry van Haaren
564617995dfSBruce Richardson /* push all the internal buffered QEs in port->cq_ring to the
565617995dfSBruce Richardson * worker cores: aka, do the ring transfers batched.
566617995dfSBruce Richardson */
56770207f35SRadu Nicolau int no_enq = 1;
568617995dfSBruce Richardson for (i = 0; i < sw->port_count; i++) {
56970207f35SRadu Nicolau struct sw_port *port = &sw->ports[i];
57070207f35SRadu Nicolau struct rte_event_ring *worker = port->cq_worker_ring;
57170207f35SRadu Nicolau
57270207f35SRadu Nicolau /* If shadow ring has 0 pkts, pull from worker ring */
57370207f35SRadu Nicolau if (sw->refill_once_per_iter && port->pp_buf_count == 0)
57470207f35SRadu Nicolau sw_refill_pp_buf(sw, port);
57570207f35SRadu Nicolau
57670207f35SRadu Nicolau if (port->cq_buf_count >= sw->sched_min_burst) {
57770207f35SRadu Nicolau rte_event_ring_enqueue_burst(worker,
57870207f35SRadu Nicolau port->cq_buf,
57970207f35SRadu Nicolau port->cq_buf_count,
580617995dfSBruce Richardson &sw->cq_ring_space[i]);
58170207f35SRadu Nicolau port->cq_buf_count = 0;
58270207f35SRadu Nicolau no_enq = 0;
583324b37e6SHarry van Haaren cqs_scheds_last_iter |= (1ULL << i);
58470207f35SRadu Nicolau } else {
58570207f35SRadu Nicolau sw->cq_ring_space[i] =
58670207f35SRadu Nicolau rte_event_ring_free_count(worker) -
58770207f35SRadu Nicolau port->cq_buf_count;
58870207f35SRadu Nicolau }
58970207f35SRadu Nicolau }
59070207f35SRadu Nicolau
59170207f35SRadu Nicolau if (no_enq) {
59270207f35SRadu Nicolau if (unlikely(sw->sched_flush_count > SCHED_NO_ENQ_CYCLE_FLUSH))
59370207f35SRadu Nicolau sw->sched_min_burst = 1;
59470207f35SRadu Nicolau else
59570207f35SRadu Nicolau sw->sched_flush_count++;
59670207f35SRadu Nicolau } else {
59770207f35SRadu Nicolau if (sw->sched_flush_count)
59870207f35SRadu Nicolau sw->sched_flush_count--;
59970207f35SRadu Nicolau else
60070207f35SRadu Nicolau sw->sched_min_burst = sw->sched_min_burst_size;
601617995dfSBruce Richardson }
602617995dfSBruce Richardson
603324b37e6SHarry van Haaren /* Provide stats on what eventdev ports were scheduled to this
604324b37e6SHarry van Haaren * iteration. If more than 64 ports are active, always report that
605324b37e6SHarry van Haaren * all Eventdev ports have been scheduled events.
606324b37e6SHarry van Haaren */
607324b37e6SHarry van Haaren sw->sched_last_iter_bitmask = cqs_scheds_last_iter;
608324b37e6SHarry van Haaren if (unlikely(sw->port_count >= 64))
609324b37e6SHarry van Haaren sw->sched_last_iter_bitmask = UINT64_MAX;
6104689c579SMattias Rönnblom
6114689c579SMattias Rönnblom return work_done ? 0 : -EAGAIN;
612617995dfSBruce Richardson }
613