15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 25566a3e3SBruce Richardson * Copyright(c) 2016-2017 Intel Corporation 3656af918SBruce Richardson */ 4656af918SBruce Richardson 5656af918SBruce Richardson #include <rte_atomic.h> 6656af918SBruce Richardson #include <rte_cycles.h> 786aed50aSBruce Richardson #include <rte_event_ring.h> 8656af918SBruce Richardson 9656af918SBruce Richardson #include "sw_evdev.h" 10656af918SBruce Richardson 11656af918SBruce Richardson #define PORT_ENQUEUE_MAX_BURST_SIZE 64 12656af918SBruce Richardson 13656af918SBruce Richardson static inline void 14656af918SBruce Richardson sw_event_release(struct sw_port *p, uint8_t index) 15656af918SBruce Richardson { 16656af918SBruce Richardson /* 17656af918SBruce Richardson * Drops the next outstanding event in our history. Used on dequeue 18656af918SBruce Richardson * to clear any history before dequeuing more events. 19656af918SBruce Richardson */ 20656af918SBruce Richardson RTE_SET_USED(index); 21656af918SBruce Richardson 22656af918SBruce Richardson /* create drop message */ 231e846151SFerruh Yigit struct rte_event ev; 241e846151SFerruh Yigit ev.op = sw_qe_flag_map[RTE_EVENT_OP_RELEASE]; 25656af918SBruce Richardson 26656af918SBruce Richardson uint16_t free_count; 2786aed50aSBruce Richardson rte_event_ring_enqueue_burst(p->rx_worker_ring, &ev, 1, &free_count); 28656af918SBruce Richardson 29656af918SBruce Richardson /* each release returns one credit */ 30656af918SBruce Richardson p->outstanding_releases--; 31656af918SBruce Richardson p->inflight_credits++; 32656af918SBruce Richardson } 33656af918SBruce Richardson 3486aed50aSBruce Richardson /* 3586aed50aSBruce Richardson * special-case of rte_event_ring enqueue, with overriding the ops member on 3686aed50aSBruce Richardson * the events that get written to the ring. 3786aed50aSBruce Richardson */ 3886aed50aSBruce Richardson static inline unsigned int 3986aed50aSBruce Richardson enqueue_burst_with_ops(struct rte_event_ring *r, const struct rte_event *events, 4086aed50aSBruce Richardson unsigned int n, uint8_t *ops) 4186aed50aSBruce Richardson { 4286aed50aSBruce Richardson struct rte_event tmp_evs[PORT_ENQUEUE_MAX_BURST_SIZE]; 4386aed50aSBruce Richardson unsigned int i; 4486aed50aSBruce Richardson 4586aed50aSBruce Richardson memcpy(tmp_evs, events, n * sizeof(events[0])); 4686aed50aSBruce Richardson for (i = 0; i < n; i++) 4786aed50aSBruce Richardson tmp_evs[i].op = ops[i]; 4886aed50aSBruce Richardson 4986aed50aSBruce Richardson return rte_event_ring_enqueue_burst(r, tmp_evs, n, NULL); 5086aed50aSBruce Richardson } 5186aed50aSBruce Richardson 52656af918SBruce Richardson uint16_t 53656af918SBruce Richardson sw_event_enqueue_burst(void *port, const struct rte_event ev[], uint16_t num) 54656af918SBruce Richardson { 55656af918SBruce Richardson int32_t i; 56656af918SBruce Richardson uint8_t new_ops[PORT_ENQUEUE_MAX_BURST_SIZE]; 57656af918SBruce Richardson struct sw_port *p = port; 58656af918SBruce Richardson struct sw_evdev *sw = (void *)p->sw; 59656af918SBruce Richardson uint32_t sw_inflights = rte_atomic32_read(&sw->inflights); 60decdc1cdSGage Eads uint32_t credit_update_quanta = sw->credit_update_quanta; 616cf86202SGage Eads int new = 0; 62656af918SBruce Richardson 63656af918SBruce Richardson if (num > PORT_ENQUEUE_MAX_BURST_SIZE) 64656af918SBruce Richardson num = PORT_ENQUEUE_MAX_BURST_SIZE; 65656af918SBruce Richardson 666cf86202SGage Eads for (i = 0; i < num; i++) 676cf86202SGage Eads new += (ev[i].op == RTE_EVENT_OP_NEW); 686cf86202SGage Eads 696cf86202SGage Eads if (unlikely(new > 0 && p->inflight_max < sw_inflights)) 706cf86202SGage Eads return 0; 716cf86202SGage Eads 726cf86202SGage Eads if (p->inflight_credits < new) { 73656af918SBruce Richardson /* check if event enqueue brings port over max threshold */ 74656af918SBruce Richardson if (sw_inflights + credit_update_quanta > sw->nb_events_limit) 75656af918SBruce Richardson return 0; 76656af918SBruce Richardson 77656af918SBruce Richardson rte_atomic32_add(&sw->inflights, credit_update_quanta); 78656af918SBruce Richardson p->inflight_credits += (credit_update_quanta); 79656af918SBruce Richardson 80*4deeb214SGage Eads /* If there are fewer inflight credits than new events, limit 81*4deeb214SGage Eads * the number of enqueued events. 82*4deeb214SGage Eads */ 83*4deeb214SGage Eads num = (p->inflight_credits < new) ? p->inflight_credits : new; 84656af918SBruce Richardson } 85656af918SBruce Richardson 86656af918SBruce Richardson for (i = 0; i < num; i++) { 87656af918SBruce Richardson int op = ev[i].op; 88656af918SBruce Richardson int outstanding = p->outstanding_releases > 0; 89656af918SBruce Richardson const uint8_t invalid_qid = (ev[i].queue_id >= sw->qid_count); 90656af918SBruce Richardson 91656af918SBruce Richardson p->inflight_credits -= (op == RTE_EVENT_OP_NEW); 92656af918SBruce Richardson p->inflight_credits += (op == RTE_EVENT_OP_RELEASE) * 93656af918SBruce Richardson outstanding; 94656af918SBruce Richardson 95656af918SBruce Richardson new_ops[i] = sw_qe_flag_map[op]; 96656af918SBruce Richardson new_ops[i] &= ~(invalid_qid << QE_FLAG_VALID_SHIFT); 97656af918SBruce Richardson 98656af918SBruce Richardson /* FWD and RELEASE packets will both resolve to taken (assuming 99656af918SBruce Richardson * correct usage of the API), providing very high correct 100656af918SBruce Richardson * prediction rate. 101656af918SBruce Richardson */ 102decdc1cdSGage Eads if ((new_ops[i] & QE_FLAG_COMPLETE) && outstanding) 103656af918SBruce Richardson p->outstanding_releases--; 10495a896abSHarry van Haaren 10595a896abSHarry van Haaren /* error case: branch to avoid touching p->stats */ 106decdc1cdSGage Eads if (unlikely(invalid_qid && op != RTE_EVENT_OP_RELEASE)) { 107656af918SBruce Richardson p->stats.rx_dropped++; 10895a896abSHarry van Haaren p->inflight_credits++; 10995a896abSHarry van Haaren } 110656af918SBruce Richardson } 111656af918SBruce Richardson 112656af918SBruce Richardson /* returns number of events actually enqueued */ 11386aed50aSBruce Richardson uint32_t enq = enqueue_burst_with_ops(p->rx_worker_ring, ev, i, 114656af918SBruce Richardson new_ops); 115656af918SBruce Richardson if (p->outstanding_releases == 0 && p->last_dequeue_burst_sz != 0) { 116656af918SBruce Richardson uint64_t burst_ticks = rte_get_timer_cycles() - 117656af918SBruce Richardson p->last_dequeue_ticks; 118656af918SBruce Richardson uint64_t burst_pkt_ticks = 119656af918SBruce Richardson burst_ticks / p->last_dequeue_burst_sz; 120656af918SBruce Richardson p->avg_pkt_ticks -= p->avg_pkt_ticks / NUM_SAMPLES; 121656af918SBruce Richardson p->avg_pkt_ticks += burst_pkt_ticks / NUM_SAMPLES; 122656af918SBruce Richardson p->last_dequeue_ticks = 0; 123656af918SBruce Richardson } 124decdc1cdSGage Eads 125decdc1cdSGage Eads /* Replenish credits if enough releases are performed */ 126decdc1cdSGage Eads if (p->inflight_credits >= credit_update_quanta * 2) { 127decdc1cdSGage Eads rte_atomic32_sub(&sw->inflights, credit_update_quanta); 128decdc1cdSGage Eads p->inflight_credits -= credit_update_quanta; 129decdc1cdSGage Eads } 130decdc1cdSGage Eads 131656af918SBruce Richardson return enq; 132656af918SBruce Richardson } 133656af918SBruce Richardson 134656af918SBruce Richardson uint16_t 135656af918SBruce Richardson sw_event_dequeue_burst(void *port, struct rte_event *ev, uint16_t num, 136656af918SBruce Richardson uint64_t wait) 137656af918SBruce Richardson { 138656af918SBruce Richardson RTE_SET_USED(wait); 139656af918SBruce Richardson struct sw_port *p = (void *)port; 14086aed50aSBruce Richardson struct rte_event_ring *ring = p->cq_worker_ring; 141656af918SBruce Richardson 142656af918SBruce Richardson /* check that all previous dequeues have been released */ 143decdc1cdSGage Eads if (p->implicit_release) { 144decdc1cdSGage Eads struct sw_evdev *sw = (void *)p->sw; 145decdc1cdSGage Eads uint32_t credit_update_quanta = sw->credit_update_quanta; 146656af918SBruce Richardson uint16_t out_rels = p->outstanding_releases; 147656af918SBruce Richardson uint16_t i; 148656af918SBruce Richardson for (i = 0; i < out_rels; i++) 149656af918SBruce Richardson sw_event_release(p, i); 150decdc1cdSGage Eads 151decdc1cdSGage Eads /* Replenish credits if enough releases are performed */ 152decdc1cdSGage Eads if (p->inflight_credits >= credit_update_quanta * 2) { 153decdc1cdSGage Eads rte_atomic32_sub(&sw->inflights, credit_update_quanta); 154decdc1cdSGage Eads p->inflight_credits -= credit_update_quanta; 155decdc1cdSGage Eads } 156656af918SBruce Richardson } 157656af918SBruce Richardson 158656af918SBruce Richardson /* returns number of events actually dequeued */ 15986aed50aSBruce Richardson uint16_t ndeq = rte_event_ring_dequeue_burst(ring, ev, num, NULL); 160656af918SBruce Richardson if (unlikely(ndeq == 0)) { 161656af918SBruce Richardson p->zero_polls++; 162656af918SBruce Richardson p->total_polls++; 163656af918SBruce Richardson goto end; 164656af918SBruce Richardson } 165656af918SBruce Richardson 166ec36d881SGage Eads p->outstanding_releases += ndeq; 167656af918SBruce Richardson p->last_dequeue_burst_sz = ndeq; 168656af918SBruce Richardson p->last_dequeue_ticks = rte_get_timer_cycles(); 169656af918SBruce Richardson p->poll_buckets[(ndeq - 1) >> SW_DEQ_STAT_BUCKET_SHIFT]++; 170656af918SBruce Richardson p->total_polls++; 171656af918SBruce Richardson 172656af918SBruce Richardson end: 173656af918SBruce Richardson return ndeq; 174656af918SBruce Richardson } 175