1*d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*d30ea906Sjfb8856606  * Copyright(c) 2016-2017 Intel Corporation
32bfe3f2eSlogwang  */
42bfe3f2eSlogwang 
52bfe3f2eSlogwang #include <rte_atomic.h>
62bfe3f2eSlogwang #include <rte_cycles.h>
72bfe3f2eSlogwang #include <rte_event_ring.h>
82bfe3f2eSlogwang 
92bfe3f2eSlogwang #include "sw_evdev.h"
102bfe3f2eSlogwang 
112bfe3f2eSlogwang #define PORT_ENQUEUE_MAX_BURST_SIZE 64
122bfe3f2eSlogwang 
132bfe3f2eSlogwang static inline void
sw_event_release(struct sw_port * p,uint8_t index)142bfe3f2eSlogwang sw_event_release(struct sw_port *p, uint8_t index)
152bfe3f2eSlogwang {
162bfe3f2eSlogwang 	/*
172bfe3f2eSlogwang 	 * Drops the next outstanding event in our history. Used on dequeue
182bfe3f2eSlogwang 	 * to clear any history before dequeuing more events.
192bfe3f2eSlogwang 	 */
202bfe3f2eSlogwang 	RTE_SET_USED(index);
212bfe3f2eSlogwang 
222bfe3f2eSlogwang 	/* create drop message */
232bfe3f2eSlogwang 	struct rte_event ev;
242bfe3f2eSlogwang 	ev.op = sw_qe_flag_map[RTE_EVENT_OP_RELEASE];
252bfe3f2eSlogwang 
262bfe3f2eSlogwang 	uint16_t free_count;
272bfe3f2eSlogwang 	rte_event_ring_enqueue_burst(p->rx_worker_ring, &ev, 1, &free_count);
282bfe3f2eSlogwang 
292bfe3f2eSlogwang 	/* each release returns one credit */
302bfe3f2eSlogwang 	p->outstanding_releases--;
312bfe3f2eSlogwang 	p->inflight_credits++;
322bfe3f2eSlogwang }
332bfe3f2eSlogwang 
342bfe3f2eSlogwang /*
352bfe3f2eSlogwang  * special-case of rte_event_ring enqueue, with overriding the ops member on
362bfe3f2eSlogwang  * the events that get written to the ring.
372bfe3f2eSlogwang  */
382bfe3f2eSlogwang static inline unsigned int
enqueue_burst_with_ops(struct rte_event_ring * r,const struct rte_event * events,unsigned int n,uint8_t * ops)392bfe3f2eSlogwang enqueue_burst_with_ops(struct rte_event_ring *r, const struct rte_event *events,
402bfe3f2eSlogwang 		unsigned int n, uint8_t *ops)
412bfe3f2eSlogwang {
422bfe3f2eSlogwang 	struct rte_event tmp_evs[PORT_ENQUEUE_MAX_BURST_SIZE];
432bfe3f2eSlogwang 	unsigned int i;
442bfe3f2eSlogwang 
452bfe3f2eSlogwang 	memcpy(tmp_evs, events, n * sizeof(events[0]));
462bfe3f2eSlogwang 	for (i = 0; i < n; i++)
472bfe3f2eSlogwang 		tmp_evs[i].op = ops[i];
482bfe3f2eSlogwang 
492bfe3f2eSlogwang 	return rte_event_ring_enqueue_burst(r, tmp_evs, n, NULL);
502bfe3f2eSlogwang }
512bfe3f2eSlogwang 
522bfe3f2eSlogwang uint16_t
sw_event_enqueue_burst(void * port,const struct rte_event ev[],uint16_t num)532bfe3f2eSlogwang sw_event_enqueue_burst(void *port, const struct rte_event ev[], uint16_t num)
542bfe3f2eSlogwang {
552bfe3f2eSlogwang 	int32_t i;
562bfe3f2eSlogwang 	uint8_t new_ops[PORT_ENQUEUE_MAX_BURST_SIZE];
572bfe3f2eSlogwang 	struct sw_port *p = port;
582bfe3f2eSlogwang 	struct sw_evdev *sw = (void *)p->sw;
592bfe3f2eSlogwang 	uint32_t sw_inflights = rte_atomic32_read(&sw->inflights);
60*d30ea906Sjfb8856606 	uint32_t credit_update_quanta = sw->credit_update_quanta;
612bfe3f2eSlogwang 	int new = 0;
622bfe3f2eSlogwang 
632bfe3f2eSlogwang 	if (num > PORT_ENQUEUE_MAX_BURST_SIZE)
642bfe3f2eSlogwang 		num = PORT_ENQUEUE_MAX_BURST_SIZE;
652bfe3f2eSlogwang 
662bfe3f2eSlogwang 	for (i = 0; i < num; i++)
672bfe3f2eSlogwang 		new += (ev[i].op == RTE_EVENT_OP_NEW);
682bfe3f2eSlogwang 
692bfe3f2eSlogwang 	if (unlikely(new > 0 && p->inflight_max < sw_inflights))
702bfe3f2eSlogwang 		return 0;
712bfe3f2eSlogwang 
722bfe3f2eSlogwang 	if (p->inflight_credits < new) {
732bfe3f2eSlogwang 		/* check if event enqueue brings port over max threshold */
742bfe3f2eSlogwang 		if (sw_inflights + credit_update_quanta > sw->nb_events_limit)
752bfe3f2eSlogwang 			return 0;
762bfe3f2eSlogwang 
772bfe3f2eSlogwang 		rte_atomic32_add(&sw->inflights, credit_update_quanta);
782bfe3f2eSlogwang 		p->inflight_credits += (credit_update_quanta);
792bfe3f2eSlogwang 
80*d30ea906Sjfb8856606 		/* If there are fewer inflight credits than new events, limit
81*d30ea906Sjfb8856606 		 * the number of enqueued events.
82*d30ea906Sjfb8856606 		 */
83*d30ea906Sjfb8856606 		num = (p->inflight_credits < new) ? p->inflight_credits : new;
842bfe3f2eSlogwang 	}
852bfe3f2eSlogwang 
862bfe3f2eSlogwang 	for (i = 0; i < num; i++) {
872bfe3f2eSlogwang 		int op = ev[i].op;
882bfe3f2eSlogwang 		int outstanding = p->outstanding_releases > 0;
892bfe3f2eSlogwang 		const uint8_t invalid_qid = (ev[i].queue_id >= sw->qid_count);
902bfe3f2eSlogwang 
912bfe3f2eSlogwang 		p->inflight_credits -= (op == RTE_EVENT_OP_NEW);
922bfe3f2eSlogwang 		p->inflight_credits += (op == RTE_EVENT_OP_RELEASE) *
932bfe3f2eSlogwang 					outstanding;
942bfe3f2eSlogwang 
952bfe3f2eSlogwang 		new_ops[i] = sw_qe_flag_map[op];
962bfe3f2eSlogwang 		new_ops[i] &= ~(invalid_qid << QE_FLAG_VALID_SHIFT);
972bfe3f2eSlogwang 
982bfe3f2eSlogwang 		/* FWD and RELEASE packets will both resolve to taken (assuming
992bfe3f2eSlogwang 		 * correct usage of the API), providing very high correct
1002bfe3f2eSlogwang 		 * prediction rate.
1012bfe3f2eSlogwang 		 */
1022bfe3f2eSlogwang 		if ((new_ops[i] & QE_FLAG_COMPLETE) && outstanding)
1032bfe3f2eSlogwang 			p->outstanding_releases--;
1042bfe3f2eSlogwang 
1052bfe3f2eSlogwang 		/* error case: branch to avoid touching p->stats */
106*d30ea906Sjfb8856606 		if (unlikely(invalid_qid && op != RTE_EVENT_OP_RELEASE)) {
1072bfe3f2eSlogwang 			p->stats.rx_dropped++;
1082bfe3f2eSlogwang 			p->inflight_credits++;
1092bfe3f2eSlogwang 		}
1102bfe3f2eSlogwang 	}
1112bfe3f2eSlogwang 
1122bfe3f2eSlogwang 	/* returns number of events actually enqueued */
1132bfe3f2eSlogwang 	uint32_t enq = enqueue_burst_with_ops(p->rx_worker_ring, ev, i,
1142bfe3f2eSlogwang 					     new_ops);
1152bfe3f2eSlogwang 	if (p->outstanding_releases == 0 && p->last_dequeue_burst_sz != 0) {
1162bfe3f2eSlogwang 		uint64_t burst_ticks = rte_get_timer_cycles() -
1172bfe3f2eSlogwang 				p->last_dequeue_ticks;
1182bfe3f2eSlogwang 		uint64_t burst_pkt_ticks =
1192bfe3f2eSlogwang 			burst_ticks / p->last_dequeue_burst_sz;
1202bfe3f2eSlogwang 		p->avg_pkt_ticks -= p->avg_pkt_ticks / NUM_SAMPLES;
1212bfe3f2eSlogwang 		p->avg_pkt_ticks += burst_pkt_ticks / NUM_SAMPLES;
1222bfe3f2eSlogwang 		p->last_dequeue_ticks = 0;
1232bfe3f2eSlogwang 	}
124*d30ea906Sjfb8856606 
125*d30ea906Sjfb8856606 	/* Replenish credits if enough releases are performed */
126*d30ea906Sjfb8856606 	if (p->inflight_credits >= credit_update_quanta * 2) {
127*d30ea906Sjfb8856606 		rte_atomic32_sub(&sw->inflights, credit_update_quanta);
128*d30ea906Sjfb8856606 		p->inflight_credits -= credit_update_quanta;
129*d30ea906Sjfb8856606 	}
130*d30ea906Sjfb8856606 
1312bfe3f2eSlogwang 	return enq;
1322bfe3f2eSlogwang }
1332bfe3f2eSlogwang 
1342bfe3f2eSlogwang uint16_t
sw_event_enqueue(void * port,const struct rte_event * ev)1352bfe3f2eSlogwang sw_event_enqueue(void *port, const struct rte_event *ev)
1362bfe3f2eSlogwang {
1372bfe3f2eSlogwang 	return sw_event_enqueue_burst(port, ev, 1);
1382bfe3f2eSlogwang }
1392bfe3f2eSlogwang 
1402bfe3f2eSlogwang uint16_t
sw_event_dequeue_burst(void * port,struct rte_event * ev,uint16_t num,uint64_t wait)1412bfe3f2eSlogwang sw_event_dequeue_burst(void *port, struct rte_event *ev, uint16_t num,
1422bfe3f2eSlogwang 		uint64_t wait)
1432bfe3f2eSlogwang {
1442bfe3f2eSlogwang 	RTE_SET_USED(wait);
1452bfe3f2eSlogwang 	struct sw_port *p = (void *)port;
1462bfe3f2eSlogwang 	struct rte_event_ring *ring = p->cq_worker_ring;
1472bfe3f2eSlogwang 
1482bfe3f2eSlogwang 	/* check that all previous dequeues have been released */
149*d30ea906Sjfb8856606 	if (p->implicit_release) {
150*d30ea906Sjfb8856606 		struct sw_evdev *sw = (void *)p->sw;
151*d30ea906Sjfb8856606 		uint32_t credit_update_quanta = sw->credit_update_quanta;
1522bfe3f2eSlogwang 		uint16_t out_rels = p->outstanding_releases;
1532bfe3f2eSlogwang 		uint16_t i;
1542bfe3f2eSlogwang 		for (i = 0; i < out_rels; i++)
1552bfe3f2eSlogwang 			sw_event_release(p, i);
156*d30ea906Sjfb8856606 
157*d30ea906Sjfb8856606 		/* Replenish credits if enough releases are performed */
158*d30ea906Sjfb8856606 		if (p->inflight_credits >= credit_update_quanta * 2) {
159*d30ea906Sjfb8856606 			rte_atomic32_sub(&sw->inflights, credit_update_quanta);
160*d30ea906Sjfb8856606 			p->inflight_credits -= credit_update_quanta;
161*d30ea906Sjfb8856606 		}
1622bfe3f2eSlogwang 	}
1632bfe3f2eSlogwang 
1642bfe3f2eSlogwang 	/* returns number of events actually dequeued */
1652bfe3f2eSlogwang 	uint16_t ndeq = rte_event_ring_dequeue_burst(ring, ev, num, NULL);
1662bfe3f2eSlogwang 	if (unlikely(ndeq == 0)) {
1672bfe3f2eSlogwang 		p->zero_polls++;
1682bfe3f2eSlogwang 		p->total_polls++;
1692bfe3f2eSlogwang 		goto end;
1702bfe3f2eSlogwang 	}
1712bfe3f2eSlogwang 
172*d30ea906Sjfb8856606 	p->outstanding_releases += ndeq;
1732bfe3f2eSlogwang 	p->last_dequeue_burst_sz = ndeq;
1742bfe3f2eSlogwang 	p->last_dequeue_ticks = rte_get_timer_cycles();
1752bfe3f2eSlogwang 	p->poll_buckets[(ndeq - 1) >> SW_DEQ_STAT_BUCKET_SHIFT]++;
1762bfe3f2eSlogwang 	p->total_polls++;
1772bfe3f2eSlogwang 
1782bfe3f2eSlogwang end:
1792bfe3f2eSlogwang 	return ndeq;
1802bfe3f2eSlogwang }
1812bfe3f2eSlogwang 
1822bfe3f2eSlogwang uint16_t
sw_event_dequeue(void * port,struct rte_event * ev,uint64_t wait)1832bfe3f2eSlogwang sw_event_dequeue(void *port, struct rte_event *ev, uint64_t wait)
1842bfe3f2eSlogwang {
1852bfe3f2eSlogwang 	return sw_event_dequeue_burst(port, ev, 1, wait);
1862bfe3f2eSlogwang }
187