Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause 2 : : * Copyright(c) 2017 Intel Corporation 3 : : */ 4 : : 5 : : #ifndef _IQ_CHUNK_H_ 6 : : #define _IQ_CHUNK_H_ 7 : : 8 : : #include <stdint.h> 9 : : #include <stdbool.h> 10 : : #include <rte_eventdev.h> 11 : : 12 : : struct __rte_cache_aligned sw_queue_chunk { 13 : : struct rte_event events[SW_EVS_PER_Q_CHUNK]; 14 : : struct sw_queue_chunk *next; 15 : : }; 16 : : 17 : : static __rte_always_inline bool 18 : : iq_empty(struct sw_iq *iq) 19 : : { 20 : : return (iq->count == 0); 21 : : } 22 : : 23 : : static __rte_always_inline uint16_t 24 : : iq_count(const struct sw_iq *iq) 25 : : { 26 [ + + - - : 9903 : return iq->count; + + ] 27 : : } 28 : : 29 : : static __rte_always_inline struct sw_queue_chunk * 30 : : iq_alloc_chunk(struct sw_evdev *sw) 31 : : { 32 : 323 : struct sw_queue_chunk *chunk = sw->chunk_list_head; 33 : 323 : sw->chunk_list_head = chunk->next; 34 : 323 : chunk->next = NULL; 35 : : return chunk; 36 : : } 37 : : 38 : : static __rte_always_inline void 39 : : iq_free_chunk(struct sw_evdev *sw, struct sw_queue_chunk *chunk) 40 : : { 41 : 1477 : chunk->next = sw->chunk_list_head; 42 : 1189 : sw->chunk_list_head = chunk; 43 : : } 44 : : 45 : : static __rte_always_inline void 46 : : iq_free_chunk_list(struct sw_evdev *sw, struct sw_queue_chunk *head) 47 : : { 48 [ + + ]: 576 : while (head) { 49 : : struct sw_queue_chunk *next; 50 : 288 : next = head->next; 51 : : iq_free_chunk(sw, head); 52 : : head = next; 53 : : } 54 : : } 55 : : 56 : : static __rte_always_inline void 57 : : iq_init(struct sw_evdev *sw, struct sw_iq *iq) 58 : : { 59 : 288 : iq->head = iq_alloc_chunk(sw); 60 : 288 : iq->tail = iq->head; 61 : 288 : iq->head_idx = 0; 62 : 288 : iq->tail_idx = 0; 63 : 288 : iq->count = 0; 64 : : } 65 : : 66 : : static __rte_always_inline void 67 : : iq_enqueue(struct sw_evdev *sw, struct sw_iq *iq, const struct rte_event *ev) 68 : : { 69 : 9455 : iq->tail->events[iq->tail_idx++] = *ev; 70 : 9455 : iq->count++; 71 : : 72 [ + + + + : 9455 : if (unlikely(iq->tail_idx == SW_EVS_PER_Q_CHUNK)) { + + - + ] 73 : : /* The number of chunks is defined in relation to the total 74 : : * number of inflight events and number of IQS such that 75 : : * allocation will always succeed. 76 : : */ 77 : : struct sw_queue_chunk *chunk = iq_alloc_chunk(sw); 78 : 35 : iq->tail->next = chunk; 79 : 35 : iq->tail = chunk; 80 : 35 : iq->tail_idx = 0; 81 : : } 82 : : } 83 : : 84 : : static __rte_always_inline void 85 : : iq_pop(struct sw_evdev *sw, struct sw_iq *iq) 86 : : { 87 : 11 : iq->head_idx++; 88 : 11 : iq->count--; 89 : : 90 [ - + ]: 11 : if (unlikely(iq->head_idx == SW_EVS_PER_Q_CHUNK)) { 91 : 0 : struct sw_queue_chunk *next = iq->head->next; 92 : : iq_free_chunk(sw, iq->head); 93 : 0 : iq->head = next; 94 : 0 : iq->head_idx = 0; 95 : : } 96 : : } 97 : : 98 : : static __rte_always_inline const struct rte_event * 99 : : iq_peek(struct sw_iq *iq) 100 : : { 101 : 11 : return &iq->head->events[iq->head_idx]; 102 : : } 103 : : 104 : : /* Note: the caller must ensure that count <= iq_count() */ 105 : : static __rte_always_inline uint16_t 106 : : iq_dequeue_burst(struct sw_evdev *sw, 107 : : struct sw_iq *iq, 108 : : struct rte_event *ev, 109 : : uint16_t count) 110 : : { 111 : : struct sw_queue_chunk *current; 112 : : uint16_t total, index; 113 : : 114 : 9288 : count = RTE_MIN(count, iq_count(iq)); 115 : : 116 : 9386 : current = iq->head; 117 : 9386 : index = iq->head_idx; 118 : : total = 0; 119 : : 120 : : /* Loop over the chunks */ 121 : 0 : while (1) { 122 : : struct sw_queue_chunk *next; 123 [ + - + - ]: 9609 : for (; index < SW_EVS_PER_Q_CHUNK;) { 124 : 9609 : ev[total++] = current->events[index++]; 125 : : 126 [ + + + + ]: 9609 : if (unlikely(total == count)) 127 : 9386 : goto done; 128 : : } 129 : : 130 : : /* Move to the next chunk */ 131 : 0 : next = current->next; 132 : : iq_free_chunk(sw, current); 133 : : current = next; 134 : : index = 0; 135 : : } 136 : : 137 : : done: 138 [ + + + + ]: 9386 : if (unlikely(index == SW_EVS_PER_Q_CHUNK)) { 139 : 35 : struct sw_queue_chunk *next = current->next; 140 : : iq_free_chunk(sw, current); 141 : 35 : iq->head = next; 142 : 35 : iq->head_idx = 0; 143 : : } else { 144 : 9351 : iq->head = current; 145 : 9351 : iq->head_idx = index; 146 : : } 147 : : 148 [ + + ]: 9386 : iq->count -= total; 149 : : 150 : : return total; 151 : : } 152 : : 153 : : static __rte_always_inline void 154 : : iq_put_back(struct sw_evdev *sw, 155 : : struct sw_iq *iq, 156 : : struct rte_event *ev, 157 : : unsigned int count) 158 : : { 159 : : /* Put back events that fit in the current head chunk. If necessary, 160 : : * put back events in a new head chunk. The caller must ensure that 161 : : * count <= SW_EVS_PER_Q_CHUNK, to ensure that at most one new head is 162 : : * needed. 163 : : */ 164 : 4187 : uint16_t avail_space = iq->head_idx; 165 : : 166 [ + - ]: 4187 : if (avail_space >= count) { 167 : 4187 : const uint16_t idx = avail_space - count; 168 : : uint16_t i; 169 : : 170 [ + + ]: 4352 : for (i = 0; i < count; i++) 171 : 165 : iq->head->events[idx + i] = ev[i]; 172 : : 173 : 4187 : iq->head_idx = idx; 174 : : } else if (avail_space < count) { 175 : 0 : const uint16_t remaining = count - avail_space; 176 : : struct sw_queue_chunk *new_head; 177 : : uint16_t i; 178 : : 179 [ # # ]: 0 : for (i = 0; i < avail_space; i++) 180 : 0 : iq->head->events[i] = ev[remaining + i]; 181 : : 182 : : new_head = iq_alloc_chunk(sw); 183 : 0 : new_head->next = iq->head; 184 : 0 : iq->head = new_head; 185 : 0 : iq->head_idx = SW_EVS_PER_Q_CHUNK - remaining; 186 : : 187 [ # # ]: 0 : for (i = 0; i < remaining; i++) 188 : 0 : iq->head->events[iq->head_idx + i] = ev[i]; 189 : : } 190 : : 191 : 4187 : iq->count += count; 192 : : } 193 : : 194 : : #endif /* _IQ_CHUNK_H_ */