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