Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2023 Napatech A/S
3 : : */
4 : :
5 : : #include <rte_common.h>
6 : : #include <rte_malloc.h>
7 : : #include <unistd.h>
8 : :
9 : : #include "ntos_drv.h"
10 : : #include "nt_util.h"
11 : : #include "ntnic_virt_queue.h"
12 : : #include "ntnic_mod_reg.h"
13 : : #include "ntlog.h"
14 : :
15 : : #define STRUCT_ALIGNMENT (4 * 1024LU)
16 : :
17 : : #define LAST_QUEUE 127
18 : : #define DISABLE 0
19 : : #define ENABLE 1
20 : : #define RX_AM_DISABLE DISABLE
21 : : #define RX_AM_ENABLE ENABLE
22 : : #define RX_UW_DISABLE DISABLE
23 : : #define RX_UW_ENABLE ENABLE
24 : : #define RX_Q_DISABLE DISABLE
25 : : #define RX_Q_ENABLE ENABLE
26 : : #define RX_AM_POLL_SPEED 5
27 : : #define RX_UW_POLL_SPEED 9
28 : : #define INIT_QUEUE 1
29 : :
30 : : #define TX_AM_DISABLE DISABLE
31 : : #define TX_AM_ENABLE ENABLE
32 : : #define TX_UW_DISABLE DISABLE
33 : : #define TX_UW_ENABLE ENABLE
34 : : #define TX_Q_DISABLE DISABLE
35 : : #define TX_Q_ENABLE ENABLE
36 : : #define TX_AM_POLL_SPEED 5
37 : : #define TX_UW_POLL_SPEED 8
38 : :
39 : : #define VIRTQ_AVAIL_F_NO_INTERRUPT 1
40 : :
41 : : #define vq_log_arg(vq, format, ...)
42 : :
43 : : /*
44 : : * Packed Ring helper macros
45 : : */
46 : : #define PACKED(vq_type) ((vq_type) == PACKED_RING ? 1 : 0)
47 : :
48 : : #define avail_flag(vq) ((vq)->avail_wrap_count ? VIRTQ_DESC_F_AVAIL : 0)
49 : : #define used_flag_inv(vq) ((vq)->avail_wrap_count ? 0 : VIRTQ_DESC_F_USED)
50 : :
51 : : #define inc_avail(vq, num) \
52 : : do { \
53 : : struct nthw_virt_queue *temp_vq = (vq); \
54 : : temp_vq->next_avail += (num); \
55 : : if (temp_vq->next_avail >= temp_vq->queue_size) { \
56 : : temp_vq->next_avail -= temp_vq->queue_size; \
57 : : temp_vq->avail_wrap_count ^= 1; \
58 : : } \
59 : : } while (0)
60 : :
61 : : #define inc_used(vq, num) do { \
62 : : struct nthw_virt_queue *temp_vq = (vq); \
63 : : temp_vq->next_used += (num); \
64 : : if (temp_vq->next_used >= temp_vq->queue_size) { \
65 : : temp_vq->next_used -= temp_vq->queue_size; \
66 : : temp_vq->used_wrap_count ^= 1; \
67 : : } \
68 : : } while (0)
69 : :
70 : : struct __rte_packed_begin virtq_avail {
71 : : uint16_t flags;
72 : : uint16_t idx;
73 : : uint16_t ring[]; /* Queue Size */
74 : : } __rte_packed_end;
75 : :
76 : : struct __rte_packed_begin virtq_used_elem {
77 : : /* Index of start of used descriptor chain. */
78 : : uint32_t id;
79 : : /* Total length of the descriptor chain which was used (written to) */
80 : : uint32_t len;
81 : : } __rte_packed_end;
82 : :
83 : : struct __rte_packed_begin virtq_used {
84 : : uint16_t flags;
85 : : uint16_t idx;
86 : : struct virtq_used_elem ring[]; /* Queue Size */
87 : : } __rte_packed_end;
88 : :
89 : : struct virtq_struct_layout_s {
90 : : size_t used_offset;
91 : : size_t desc_offset;
92 : : };
93 : :
94 : : enum nthw_virt_queue_usage {
95 : : NTHW_VIRTQ_UNUSED = 0,
96 : : NTHW_VIRTQ_UNMANAGED,
97 : : NTHW_VIRTQ_MANAGED
98 : : };
99 : :
100 : : /*
101 : : * Per-queue state. One instance is allocated per virt queue from hugepage
102 : : * memory on the NUMA node of the adapter, so the state touched in the
103 : : * Rx/Tx hot path lives next to the rings and packet buffers it describes,
104 : : * is visible to secondary processes and never shares a cache line with
105 : : * another queue.
106 : : */
107 : : struct __rte_cache_aligned nthw_virt_queue {
108 : : /* Pointers to virt-queue structs */
109 : : union {
110 : : struct {
111 : : /* SPLIT virtqueue */
112 : : struct virtq_avail *p_avail;
113 : : struct virtq_used *p_used;
114 : : struct virtq_desc *p_desc;
115 : : /* Control variables for virt-queue structs */
116 : : uint16_t am_idx;
117 : : uint16_t used_idx;
118 : : uint16_t cached_idx;
119 : : uint16_t tx_descr_avail_idx;
120 : : };
121 : : struct {
122 : : /* PACKED virtqueue */
123 : : struct pvirtq_event_suppress *driver_event;
124 : : struct pvirtq_event_suppress *device_event;
125 : : struct pvirtq_desc *desc;
126 : : struct {
127 : : uint16_t next;
128 : : uint16_t num;
129 : : } outs;
130 : : /*
131 : : * when in-order release used Tx packets from FPGA it may collapse
132 : : * into a batch. When getting new Tx buffers we may only need
133 : : * partial
134 : : */
135 : : uint16_t next_avail;
136 : : uint16_t next_used;
137 : : uint16_t avail_wrap_count;
138 : : uint16_t used_wrap_count;
139 : : };
140 : : };
141 : :
142 : : /* Array with packet buffers */
143 : : struct nthw_memory_descriptor *p_virtual_addr;
144 : :
145 : : /* Queue configuration info */
146 : : nthw_dbs_t *mp_nthw_dbs;
147 : :
148 : : enum nthw_virt_queue_usage usage;
149 : : uint16_t irq_vector;
150 : : uint16_t vq_type;
151 : : uint16_t in_order;
152 : :
153 : : uint16_t queue_size;
154 : : uint32_t index;
155 : : uint32_t am_enable;
156 : : uint32_t host_id;
157 : : uint32_t port; /* Only used by TX queues */
158 : : uint32_t virtual_port; /* Only used by TX queues */
159 : : uint32_t header;
160 : : /*
161 : : * Only used by TX queues:
162 : : * 0: VirtIO-Net header (12 bytes).
163 : : * 1: Napatech DVIO0 descriptor (12 bytes).
164 : : */
165 : : void *avail_struct_phys_addr;
166 : : void *used_struct_phys_addr;
167 : : void *desc_struct_phys_addr;
168 : : };
169 : :
170 : : struct pvirtq_struct_layout_s {
171 : : size_t driver_event_offset;
172 : : size_t device_event_offset;
173 : : };
174 : :
175 : : static int dbs_numa_node(const nthw_dbs_t *p_nthw_dbs)
176 : : {
177 : 0 : return p_nthw_dbs->mp_fpga->p_fpga_info->numa_node;
178 : : }
179 : :
180 : : /* Allocate a zeroed queue object and bind it to its DBS module */
181 : 0 : static struct nthw_virt_queue *dbs_alloc_virt_queue(nthw_dbs_t *p_nthw_dbs)
182 : : {
183 : 0 : struct nthw_virt_queue *vq = rte_zmalloc_socket("ntnic_vq",
184 : : sizeof(struct nthw_virt_queue), RTE_CACHE_LINE_SIZE,
185 : : dbs_numa_node(p_nthw_dbs));
186 : :
187 [ # # ]: 0 : if (vq != NULL)
188 : 0 : vq->mp_nthw_dbs = p_nthw_dbs;
189 : :
190 : 0 : return vq;
191 : : }
192 : :
193 : : /*
194 : : * Keep a private copy of the packet buffer descriptors. It is indexed on
195 : : * every Rx/Tx burst, so place it with the rest of the queue state.
196 : : */
197 : 0 : static int dbs_copy_packet_buffers(struct nthw_virt_queue *vq,
198 : : const struct nthw_memory_descriptor *p_packet_buffers, uint32_t n)
199 : : {
200 : 0 : size_t size = (size_t)n * sizeof(*p_packet_buffers);
201 : :
202 [ # # ]: 0 : if (n == 0)
203 : : return -1; /* don't allocate memory with size of 0 bytes */
204 : :
205 : 0 : vq->p_virtual_addr = rte_zmalloc_socket("ntnic_vq_bufs", size, RTE_CACHE_LINE_SIZE,
206 : 0 : dbs_numa_node(vq->mp_nthw_dbs));
207 : :
208 [ # # ]: 0 : if (vq->p_virtual_addr == NULL)
209 : : return -1;
210 : :
211 : : memcpy(vq->p_virtual_addr, p_packet_buffers, size);
212 : 0 : return 0;
213 : : }
214 : :
215 : 0 : static void dbs_free_virt_queue(struct nthw_virt_queue *vq)
216 : : {
217 [ # # ]: 0 : if (vq == NULL)
218 : : return;
219 : :
220 : 0 : rte_free(vq->p_virtual_addr);
221 : 0 : rte_free(vq);
222 : : }
223 : :
224 : 0 : static void dbs_init_rx_queue(nthw_dbs_t *p_nthw_dbs, uint32_t queue, uint32_t start_idx,
225 : : uint32_t start_ptr)
226 : : {
227 : : uint32_t busy;
228 : : uint32_t init;
229 : : uint32_t dummy;
230 : :
231 : : do {
232 : 0 : nthw_get_rx_init(p_nthw_dbs, &init, &dummy, &busy);
233 [ # # ]: 0 : } while (busy != 0);
234 : :
235 : 0 : nthw_set_rx_init(p_nthw_dbs, start_idx, start_ptr, INIT_QUEUE, queue);
236 : :
237 : : do {
238 : 0 : nthw_get_rx_init(p_nthw_dbs, &init, &dummy, &busy);
239 [ # # ]: 0 : } while (busy != 0);
240 : 0 : }
241 : :
242 : 0 : static void dbs_init_tx_queue(nthw_dbs_t *p_nthw_dbs, uint32_t queue, uint32_t start_idx,
243 : : uint32_t start_ptr)
244 : : {
245 : : uint32_t busy;
246 : : uint32_t init;
247 : : uint32_t dummy;
248 : :
249 : : do {
250 : 0 : nthw_get_tx_init(p_nthw_dbs, &init, &dummy, &busy);
251 [ # # ]: 0 : } while (busy != 0);
252 : :
253 : 0 : nthw_set_tx_init(p_nthw_dbs, start_idx, start_ptr, INIT_QUEUE, queue);
254 : :
255 : : do {
256 : 0 : nthw_get_tx_init(p_nthw_dbs, &init, &dummy, &busy);
257 [ # # ]: 0 : } while (busy != 0);
258 : 0 : }
259 : :
260 : 0 : static int nthw_virt_queue_init(struct fpga_info_s *p_fpga_info)
261 : : {
262 : : RTE_ASSERT(p_fpga_info);
263 : :
264 : 0 : nthw_fpga_t *const p_fpga = p_fpga_info->mp_fpga;
265 : : nthw_dbs_t *p_nthw_dbs;
266 : : int res = 0;
267 : : uint32_t i;
268 : :
269 : 0 : p_fpga_info->mp_nthw_dbs = NULL;
270 : :
271 : 0 : p_nthw_dbs = nthw_dbs_new();
272 : :
273 [ # # ]: 0 : if (p_nthw_dbs == NULL)
274 : : return -1;
275 : :
276 : 0 : res = nthw_dbs_init(NULL, p_fpga, 0);/* Check that DBS exists in FPGA */
277 : :
278 [ # # ]: 0 : if (res) {
279 : 0 : free(p_nthw_dbs);
280 : 0 : return res;
281 : : }
282 : :
283 : 0 : res = nthw_dbs_init(p_nthw_dbs, p_fpga, 0); /* Create DBS module */
284 : :
285 [ # # ]: 0 : if (res) {
286 : 0 : free(p_nthw_dbs);
287 : 0 : return res;
288 : : }
289 : :
290 : 0 : p_fpga_info->mp_nthw_dbs = p_nthw_dbs;
291 : :
292 : 0 : nthw_dbs_reset(p_nthw_dbs);
293 : :
294 [ # # ]: 0 : for (i = 0; i < NT_DBS_RX_QUEUES_MAX; ++i)
295 : 0 : dbs_init_rx_queue(p_nthw_dbs, i, 0, 0);
296 : :
297 [ # # ]: 0 : for (i = 0; i < NT_DBS_TX_QUEUES_MAX; ++i)
298 : 0 : dbs_init_tx_queue(p_nthw_dbs, i, 0, 0);
299 : :
300 : 0 : nthw_set_rx_control(p_nthw_dbs, LAST_QUEUE, RX_AM_DISABLE, RX_AM_POLL_SPEED, RX_UW_DISABLE,
301 : : RX_UW_POLL_SPEED, RX_Q_DISABLE);
302 : 0 : nthw_set_rx_control(p_nthw_dbs, LAST_QUEUE, RX_AM_ENABLE, RX_AM_POLL_SPEED, RX_UW_ENABLE,
303 : : RX_UW_POLL_SPEED, RX_Q_DISABLE);
304 : 0 : nthw_set_rx_control(p_nthw_dbs, LAST_QUEUE, RX_AM_ENABLE, RX_AM_POLL_SPEED, RX_UW_ENABLE,
305 : : RX_UW_POLL_SPEED, RX_Q_ENABLE);
306 : :
307 : 0 : nthw_set_tx_control(p_nthw_dbs, LAST_QUEUE, TX_AM_DISABLE, TX_AM_POLL_SPEED, TX_UW_DISABLE,
308 : : TX_UW_POLL_SPEED, TX_Q_DISABLE);
309 : 0 : nthw_set_tx_control(p_nthw_dbs, LAST_QUEUE, TX_AM_ENABLE, TX_AM_POLL_SPEED, TX_UW_ENABLE,
310 : : TX_UW_POLL_SPEED, TX_Q_DISABLE);
311 : 0 : nthw_set_tx_control(p_nthw_dbs, LAST_QUEUE, TX_AM_ENABLE, TX_AM_POLL_SPEED, TX_UW_ENABLE,
312 : : TX_UW_POLL_SPEED, TX_Q_ENABLE);
313 : :
314 : 0 : return 0;
315 : : }
316 : :
317 : : static struct virtq_struct_layout_s dbs_calc_struct_layout(uint32_t queue_size)
318 : : {
319 : : /* + sizeof(uint16_t); ("avail->used_event" is not used) */
320 : 0 : size_t avail_mem = sizeof(struct virtq_avail) + queue_size * sizeof(uint16_t);
321 : 0 : size_t avail_mem_aligned = ((avail_mem % STRUCT_ALIGNMENT) == 0)
322 : : ? avail_mem
323 : 0 : : STRUCT_ALIGNMENT * (avail_mem / STRUCT_ALIGNMENT + 1);
324 : :
325 : : /* + sizeof(uint16_t); ("used->avail_event" is not used) */
326 : 0 : size_t used_mem = sizeof(struct virtq_used) + queue_size * sizeof(struct virtq_used_elem);
327 : : size_t used_mem_aligned = ((used_mem % STRUCT_ALIGNMENT) == 0)
328 : : ? used_mem
329 : 0 : : STRUCT_ALIGNMENT * (used_mem / STRUCT_ALIGNMENT + 1);
330 : :
331 : : struct virtq_struct_layout_s virtq_layout;
332 : : virtq_layout.used_offset = avail_mem_aligned;
333 : 0 : virtq_layout.desc_offset = avail_mem_aligned + used_mem_aligned;
334 : :
335 : : return virtq_layout;
336 : : }
337 : :
338 : : static void dbs_initialize_avail_struct(void *addr, uint16_t queue_size,
339 : : uint16_t initial_avail_idx)
340 : : {
341 : : uint16_t i;
342 : : struct virtq_avail *p_avail = (struct virtq_avail *)addr;
343 : :
344 : 0 : p_avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
345 : 0 : p_avail->idx = initial_avail_idx;
346 : :
347 [ # # ]: 0 : for (i = 0; i < queue_size; ++i)
348 : 0 : p_avail->ring[i] = i;
349 : : }
350 : :
351 : : static void dbs_initialize_used_struct(void *addr, uint16_t queue_size)
352 : : {
353 : : int i;
354 : : struct virtq_used *p_used = (struct virtq_used *)addr;
355 : :
356 : 0 : p_used->flags = 1;
357 : 0 : p_used->idx = 0;
358 : :
359 [ # # ]: 0 : for (i = 0; i < queue_size; ++i) {
360 : 0 : p_used->ring[i].id = 0;
361 : 0 : p_used->ring[i].len = 0;
362 : : }
363 : : }
364 : :
365 : : static void
366 : : dbs_initialize_descriptor_struct(void *addr,
367 : : struct nthw_memory_descriptor *packet_buffer_descriptors,
368 : : uint16_t queue_size, uint16_t flgs)
369 : : {
370 [ # # ]: 0 : if (packet_buffer_descriptors) {
371 : : int i;
372 : : struct virtq_desc *p_desc = (struct virtq_desc *)addr;
373 : :
374 [ # # ]: 0 : for (i = 0; i < queue_size; ++i) {
375 : 0 : p_desc[i].addr = (uint64_t)packet_buffer_descriptors[i].phys_addr;
376 : 0 : p_desc[i].len = packet_buffer_descriptors[i].len;
377 : 0 : p_desc[i].flags = flgs;
378 : 0 : p_desc[i].next = 0;
379 : : }
380 : : }
381 : : }
382 : :
383 : : static void
384 : 0 : dbs_initialize_virt_queue_structs(void *avail_struct_addr, void *used_struct_addr,
385 : : void *desc_struct_addr,
386 : : struct nthw_memory_descriptor *packet_buffer_descriptors,
387 : : uint16_t queue_size, uint16_t initial_avail_idx, uint16_t flgs)
388 : : {
389 : 0 : dbs_initialize_avail_struct(avail_struct_addr, queue_size, initial_avail_idx);
390 : : dbs_initialize_used_struct(used_struct_addr, queue_size);
391 : : dbs_initialize_descriptor_struct(desc_struct_addr, packet_buffer_descriptors, queue_size,
392 : : flgs);
393 : 0 : }
394 : :
395 : : static uint8_t dbs_qsize_log2(uint16_t qsize)
396 : : {
397 : : uint8_t qs = 0;
398 : :
399 [ # # # # ]: 0 : while (qsize) {
400 : 0 : qsize = qsize >> 1;
401 : 0 : ++qs;
402 : : }
403 : :
404 : 0 : --qs;
405 : : return qs;
406 : : }
407 : :
408 : 0 : static int nthw_setup_rx_virt_queue(struct nthw_virt_queue *vq,
409 : : uint32_t index,
410 : : uint16_t start_idx,
411 : : uint16_t start_ptr,
412 : : void *avail_struct_phys_addr,
413 : : void *used_struct_phys_addr,
414 : : void *desc_struct_phys_addr,
415 : : uint16_t queue_size,
416 : : uint32_t host_id,
417 : : uint32_t header,
418 : : uint32_t vq_type,
419 : : int irq_vector,
420 : : uint8_t rx_deferred_start)
421 : : {
422 : 0 : nthw_dbs_t *p_nthw_dbs = vq->mp_nthw_dbs;
423 : 0 : uint32_t qs = dbs_qsize_log2(queue_size);
424 : : uint32_t int_enable;
425 : : uint32_t vec;
426 : : uint32_t istk;
427 : :
428 : : /*
429 : : * Setup DBS module - DSF00094
430 : : * 3. Configure the DBS.RX_DR_DATA memory; good idea to initialize all
431 : : * DBS_RX_QUEUES entries.
432 : : */
433 [ # # ]: 0 : if (nthw_set_rx_dr_data(p_nthw_dbs, index, (uint64_t)desc_struct_phys_addr,
434 : : host_id, qs, header, 0) != 0) {
435 : : return -1;
436 : : }
437 : :
438 : : /*
439 : : * 4. Configure the DBS.RX_UW_DATA memory; good idea to initialize all
440 : : * DBS_RX_QUEUES entries.
441 : : * Notice: We always start out with interrupts disabled (by setting the
442 : : * "irq_vector" argument to -1). Queues that require interrupts will have
443 : : * it enabled at a later time (after we have enabled vfio interrupts in
444 : : * the kernel).
445 : : */
446 : : int_enable = 0;
447 : : vec = 0;
448 : : istk = 0;
449 : 0 : NT_LOG_DBGX(DBG, NTNIC, "nthw_set_rx_uw_data int=0 irq_vector=%i", irq_vector);
450 : :
451 [ # # ]: 0 : if (nthw_set_rx_uw_data(p_nthw_dbs, index,
452 : : (uint64_t)used_struct_phys_addr,
453 : : host_id, qs, 0, int_enable, vec, istk) != 0) {
454 : : return -1;
455 : : }
456 : :
457 : : /*
458 : : * 2. Configure the DBS.RX_AM_DATA memory and enable the queues you plan to use;
459 : : * good idea to initialize all DBS_RX_QUEUES entries.
460 : : * Notice: We do this only for queues that don't require interrupts (i.e. if
461 : : * irq_vector < 0). Queues that require interrupts will have RX_AM_DATA enabled
462 : : * at a later time (after we have enabled vfio interrupts in the kernel).
463 : : */
464 [ # # ]: 0 : if (irq_vector < 0) {
465 [ # # ]: 0 : if (nthw_set_rx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr,
466 : : RX_AM_DISABLE, host_id, 0,
467 : : 0) != 0) {
468 : : return -1;
469 : : }
470 : : }
471 : :
472 : : /*
473 : : * 5. Initialize all RX queues (all DBS_RX_QUEUES of them) using the
474 : : * DBS.RX_INIT register.
475 : : */
476 : 0 : dbs_init_rx_queue(p_nthw_dbs, index, start_idx, start_ptr);
477 : :
478 : : /*
479 : : * 2. Configure the DBS.RX_AM_DATA memory and enable the queues you plan to use;
480 : : * good idea to initialize all DBS_RX_QUEUES entries.
481 : : */
482 : 0 : uint32_t enable = rx_deferred_start ? RX_AM_DISABLE : RX_AM_ENABLE;
483 [ # # ]: 0 : if (nthw_set_rx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr, enable,
484 : : host_id, 0, irq_vector >= 0 ? 1 : 0) != 0) {
485 : : return -1;
486 : : }
487 : :
488 : : /* Save queue state */
489 : 0 : vq->usage = NTHW_VIRTQ_UNMANAGED;
490 : 0 : vq->index = index;
491 : 0 : vq->queue_size = queue_size;
492 : 0 : vq->am_enable = (irq_vector < 0) ? RX_AM_ENABLE : RX_AM_DISABLE;
493 : 0 : vq->host_id = host_id;
494 : 0 : vq->avail_struct_phys_addr = avail_struct_phys_addr;
495 : 0 : vq->used_struct_phys_addr = used_struct_phys_addr;
496 : 0 : vq->desc_struct_phys_addr = desc_struct_phys_addr;
497 : 0 : vq->vq_type = vq_type;
498 : 0 : vq->in_order = 0; /* not used */
499 : 0 : vq->irq_vector = irq_vector;
500 : :
501 : 0 : return 0;
502 : : }
503 : :
504 : : static int dbs_wait_hw_queue_shutdown(struct nthw_virt_queue *vq, int rx);
505 : :
506 : 0 : static int dbs_wait_on_busy(struct nthw_virt_queue *vq, uint32_t *idle, int rx)
507 : : {
508 : : uint32_t busy;
509 : : uint32_t queue;
510 : : int err = 0;
511 : 0 : nthw_dbs_t *p_nthw_dbs = vq->mp_nthw_dbs;
512 : :
513 : : do {
514 [ # # ]: 0 : if (rx)
515 : 0 : err = nthw_get_rx_idle(p_nthw_dbs, idle, &queue, &busy);
516 : :
517 : : else
518 : 0 : err = nthw_get_tx_idle(p_nthw_dbs, idle, &queue, &busy);
519 [ # # # # ]: 0 : } while (!err && busy);
520 : :
521 : 0 : return err;
522 : : }
523 : :
524 : 0 : static int dbs_wait_hw_queue_shutdown(struct nthw_virt_queue *vq, int rx)
525 : : {
526 : : int err = 0;
527 : 0 : uint32_t idle = 0;
528 : 0 : nthw_dbs_t *p_nthw_dbs = vq->mp_nthw_dbs;
529 : :
530 : 0 : err = dbs_wait_on_busy(vq, &idle, rx);
531 : :
532 [ # # ]: 0 : if (err) {
533 [ # # ]: 0 : if (err == -ENOTSUP) {
534 : 0 : nthw_os_wait_usec(200000);
535 : 0 : return 0;
536 : : }
537 : :
538 : : return -1;
539 : : }
540 : :
541 : : do {
542 [ # # ]: 0 : if (rx)
543 : 0 : err = nthw_set_rx_idle(p_nthw_dbs, 1, vq->index);
544 : :
545 : : else
546 : 0 : err = nthw_set_tx_idle(p_nthw_dbs, 1, vq->index);
547 : :
548 [ # # ]: 0 : if (err)
549 : : return -1;
550 : :
551 [ # # ]: 0 : if (dbs_wait_on_busy(vq, &idle, rx) != 0)
552 : : return -1;
553 : :
554 [ # # ]: 0 : } while (idle == 0);
555 : :
556 : : return 0;
557 : : }
558 : :
559 : 0 : static int dbs_internal_release_rx_virt_queue(struct nthw_virt_queue *rxvq)
560 : : {
561 [ # # ]: 0 : if (rxvq == NULL)
562 : : return -1;
563 : :
564 : 0 : nthw_dbs_t *p_nthw_dbs = rxvq->mp_nthw_dbs;
565 : :
566 : : /* Clear UW */
567 : 0 : rxvq->used_struct_phys_addr = NULL;
568 : :
569 [ # # ]: 0 : if (nthw_set_rx_uw_data(p_nthw_dbs, rxvq->index, (uint64_t)rxvq->used_struct_phys_addr,
570 : 0 : rxvq->host_id, 0, PACKED(rxvq->vq_type), 0, 0, 0) != 0) {
571 : : return -1;
572 : : }
573 : :
574 : : /* Disable AM */
575 : 0 : rxvq->am_enable = RX_AM_DISABLE;
576 : :
577 [ # # ]: 0 : if (nthw_set_rx_am_data(p_nthw_dbs,
578 : : rxvq->index,
579 : 0 : (uint64_t)rxvq->avail_struct_phys_addr,
580 : : rxvq->am_enable,
581 : : rxvq->host_id,
582 : 0 : PACKED(rxvq->vq_type),
583 : : 0) != 0) {
584 : : return -1;
585 : : }
586 : :
587 : : /* Let the FPGA finish packet processing */
588 [ # # ]: 0 : if (dbs_wait_hw_queue_shutdown(rxvq, 1) != 0)
589 : : return -1;
590 : :
591 : : /* Clear rest of AM */
592 : 0 : rxvq->avail_struct_phys_addr = NULL;
593 : 0 : rxvq->host_id = 0;
594 : :
595 [ # # ]: 0 : if (nthw_set_rx_am_data(p_nthw_dbs,
596 : : rxvq->index,
597 : : (uint64_t)rxvq->avail_struct_phys_addr,
598 : : rxvq->am_enable,
599 : : rxvq->host_id,
600 : 0 : PACKED(rxvq->vq_type),
601 : : 0) != 0)
602 : : return -1;
603 : :
604 : : /* Clear DR */
605 : 0 : rxvq->desc_struct_phys_addr = NULL;
606 : :
607 [ # # ]: 0 : if (nthw_set_rx_dr_data(p_nthw_dbs,
608 : : rxvq->index,
609 : : (uint64_t)rxvq->desc_struct_phys_addr,
610 : : rxvq->host_id,
611 : : 0,
612 : : rxvq->header,
613 : 0 : PACKED(rxvq->vq_type)) != 0)
614 : : return -1;
615 : :
616 : : /* Initialize queue */
617 : 0 : dbs_init_rx_queue(p_nthw_dbs, rxvq->index, 0, 0);
618 : :
619 : : /* Reset queue state */
620 : 0 : rxvq->usage = NTHW_VIRTQ_UNUSED;
621 : 0 : rxvq->mp_nthw_dbs = p_nthw_dbs;
622 : 0 : rxvq->index = 0;
623 : 0 : rxvq->queue_size = 0;
624 : :
625 : 0 : return 0;
626 : : }
627 : :
628 : 0 : static int nthw_release_mngd_rx_virt_queue(struct nthw_virt_queue *rxvq)
629 : : {
630 : : int res;
631 : :
632 [ # # # # ]: 0 : if (rxvq == NULL || rxvq->usage != NTHW_VIRTQ_MANAGED)
633 : : return -1;
634 : :
635 : 0 : res = dbs_internal_release_rx_virt_queue(rxvq);
636 : :
637 : : /* The queue object is owned here; the caller must drop its handle */
638 : 0 : dbs_free_virt_queue(rxvq);
639 : :
640 : 0 : return res;
641 : : }
642 : :
643 : 0 : static int dbs_internal_release_tx_virt_queue(struct nthw_virt_queue *txvq)
644 : : {
645 [ # # ]: 0 : if (txvq == NULL)
646 : : return -1;
647 : :
648 : 0 : nthw_dbs_t *p_nthw_dbs = txvq->mp_nthw_dbs;
649 : :
650 : : /* Clear UW */
651 : 0 : txvq->used_struct_phys_addr = NULL;
652 : :
653 [ # # ]: 0 : if (nthw_set_tx_uw_data(p_nthw_dbs, txvq->index, (uint64_t)txvq->used_struct_phys_addr,
654 : 0 : txvq->host_id, 0, PACKED(txvq->vq_type), 0, 0, 0,
655 : 0 : txvq->in_order) != 0) {
656 : : return -1;
657 : : }
658 : :
659 : : /* Disable AM */
660 : 0 : txvq->am_enable = TX_AM_DISABLE;
661 : :
662 [ # # ]: 0 : if (nthw_set_tx_am_data(p_nthw_dbs,
663 : : txvq->index,
664 : 0 : (uint64_t)txvq->avail_struct_phys_addr,
665 : : txvq->am_enable,
666 : : txvq->host_id,
667 : 0 : PACKED(txvq->vq_type),
668 : : 0) != 0) {
669 : : return -1;
670 : : }
671 : :
672 : : /* Let the FPGA finish packet processing */
673 [ # # ]: 0 : if (dbs_wait_hw_queue_shutdown(txvq, 0) != 0)
674 : : return -1;
675 : :
676 : : /* Clear rest of AM */
677 : 0 : txvq->avail_struct_phys_addr = NULL;
678 : 0 : txvq->host_id = 0;
679 : :
680 [ # # ]: 0 : if (nthw_set_tx_am_data(p_nthw_dbs,
681 : : txvq->index,
682 : : (uint64_t)txvq->avail_struct_phys_addr,
683 : : txvq->am_enable,
684 : : txvq->host_id,
685 : 0 : PACKED(txvq->vq_type),
686 : : 0) != 0) {
687 : : return -1;
688 : : }
689 : :
690 : : /* Clear DR */
691 : 0 : txvq->desc_struct_phys_addr = NULL;
692 : 0 : txvq->port = 0;
693 : 0 : txvq->header = 0;
694 : :
695 [ # # ]: 0 : if (nthw_set_tx_dr_data(p_nthw_dbs,
696 : : txvq->index,
697 : : (uint64_t)txvq->desc_struct_phys_addr,
698 : : txvq->host_id,
699 : : 0,
700 : : txvq->port,
701 : : txvq->header,
702 : 0 : PACKED(txvq->vq_type)) != 0) {
703 : : return -1;
704 : : }
705 : :
706 : : /* Clear QP */
707 : 0 : txvq->virtual_port = 0;
708 : :
709 [ # # ]: 0 : if (nthw_dbs_set_tx_qp_data(p_nthw_dbs, txvq->index, txvq->virtual_port) != 0)
710 : : return -1;
711 : :
712 : : /* Initialize queue */
713 : 0 : dbs_init_tx_queue(p_nthw_dbs, txvq->index, 0, 0);
714 : :
715 : : /* Reset queue state */
716 : 0 : txvq->usage = NTHW_VIRTQ_UNUSED;
717 : 0 : txvq->mp_nthw_dbs = p_nthw_dbs;
718 : 0 : txvq->index = 0;
719 : 0 : txvq->queue_size = 0;
720 : :
721 : 0 : return 0;
722 : : }
723 : :
724 : 0 : static int nthw_release_mngd_tx_virt_queue(struct nthw_virt_queue *txvq)
725 : : {
726 : : int res;
727 : :
728 [ # # # # ]: 0 : if (txvq == NULL || txvq->usage != NTHW_VIRTQ_MANAGED)
729 : : return -1;
730 : :
731 : 0 : res = dbs_internal_release_tx_virt_queue(txvq);
732 : :
733 : : /* The queue object is owned here; the caller must drop its handle */
734 : 0 : dbs_free_virt_queue(txvq);
735 : :
736 : 0 : return res;
737 : : }
738 : :
739 : 0 : static int nthw_setup_tx_virt_queue(struct nthw_virt_queue *vq,
740 : : uint32_t index,
741 : : uint16_t start_idx,
742 : : uint16_t start_ptr,
743 : : void *avail_struct_phys_addr,
744 : : void *used_struct_phys_addr,
745 : : void *desc_struct_phys_addr,
746 : : uint16_t queue_size,
747 : : uint32_t host_id,
748 : : uint32_t port,
749 : : uint32_t virtual_port,
750 : : uint32_t header,
751 : : uint32_t vq_type,
752 : : int irq_vector,
753 : : uint32_t in_order,
754 : : uint8_t tx_deferred_start)
755 : : {
756 : 0 : nthw_dbs_t *p_nthw_dbs = vq->mp_nthw_dbs;
757 : : uint32_t int_enable;
758 : : uint32_t vec;
759 : : uint32_t istk;
760 : 0 : uint32_t qs = dbs_qsize_log2(queue_size);
761 : :
762 : : /*
763 : : * Setup DBS module - DSF00094
764 : : * 3. Configure the DBS.TX_DR_DATA memory; good idea to initialize all
765 : : * DBS_TX_QUEUES entries.
766 : : */
767 [ # # ]: 0 : if (nthw_set_tx_dr_data(p_nthw_dbs, index, (uint64_t)desc_struct_phys_addr,
768 : : host_id, qs, port, header, 0) != 0) {
769 : : return -1;
770 : : }
771 : :
772 : : /*
773 : : * 4. Configure the DBS.TX_UW_DATA memory; good idea to initialize all
774 : : * DBS_TX_QUEUES entries.
775 : : * Notice: We always start out with interrupts disabled (by setting the
776 : : * "irq_vector" argument to -1). Queues that require interrupts will have
777 : : * it enabled at a later time (after we have enabled vfio interrupts in the
778 : : * kernel).
779 : : */
780 : : int_enable = 0;
781 : : vec = 0;
782 : : istk = 0;
783 : :
784 [ # # ]: 0 : if (nthw_set_tx_uw_data(p_nthw_dbs, index,
785 : : (uint64_t)used_struct_phys_addr,
786 : : host_id, qs, 0, int_enable, vec, istk, in_order) != 0) {
787 : : return -1;
788 : : }
789 : :
790 : : /*
791 : : * 2. Configure the DBS.TX_AM_DATA memory and enable the queues you plan to use;
792 : : * good idea to initialize all DBS_TX_QUEUES entries.
793 : : */
794 [ # # ]: 0 : if (nthw_set_tx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr, TX_AM_DISABLE,
795 : : host_id, 0, irq_vector >= 0 ? 1 : 0) != 0) {
796 : : return -1;
797 : : }
798 : :
799 : : /*
800 : : * 5. Initialize all TX queues (all DBS_TX_QUEUES of them) using the
801 : : * DBS.TX_INIT register.
802 : : */
803 : 0 : dbs_init_tx_queue(p_nthw_dbs, index, start_idx, start_ptr);
804 : :
805 [ # # ]: 0 : if (nthw_dbs_set_tx_qp_data(p_nthw_dbs, index, virtual_port) != 0)
806 : : return -1;
807 : :
808 : : /*
809 : : * 2. Configure the DBS.TX_AM_DATA memory and enable the queues you plan to use;
810 : : * good idea to initialize all DBS_TX_QUEUES entries.
811 : : * Notice: We do this only for queues that don't require interrupts (i.e. if
812 : : * irq_vector < 0). Queues that require interrupts will have TX_AM_DATA
813 : : * enabled at a later time (after we have enabled vfio interrupts in the
814 : : * kernel).
815 : : */
816 [ # # ]: 0 : if (irq_vector < 0) {
817 : 0 : uint32_t enable = tx_deferred_start ? TX_AM_DISABLE : TX_AM_ENABLE;
818 [ # # ]: 0 : if (nthw_set_tx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr,
819 : : enable, host_id, 0, 0) != 0) {
820 : : return -1;
821 : : }
822 : : }
823 : :
824 : : /* Save queue state */
825 : 0 : vq->usage = NTHW_VIRTQ_UNMANAGED;
826 : 0 : vq->index = index;
827 : 0 : vq->queue_size = queue_size;
828 : 0 : vq->am_enable = (irq_vector < 0) ? TX_AM_ENABLE : TX_AM_DISABLE;
829 : 0 : vq->host_id = host_id;
830 : 0 : vq->port = port;
831 : 0 : vq->virtual_port = virtual_port;
832 : 0 : vq->avail_struct_phys_addr = avail_struct_phys_addr;
833 : 0 : vq->used_struct_phys_addr = used_struct_phys_addr;
834 : 0 : vq->desc_struct_phys_addr = desc_struct_phys_addr;
835 : 0 : vq->vq_type = vq_type;
836 : 0 : vq->in_order = in_order;
837 : 0 : vq->irq_vector = irq_vector;
838 : :
839 : 0 : return 0;
840 : : }
841 : :
842 : : static struct nthw_virt_queue *
843 [ # # ]: 0 : nthw_setup_mngd_rx_virt_queue_split(nthw_dbs_t *p_nthw_dbs,
844 : : uint32_t index,
845 : : uint32_t queue_size,
846 : : uint32_t host_id,
847 : : uint32_t header,
848 : : struct nthw_memory_descriptor *p_virt_struct_area,
849 : : struct nthw_memory_descriptor *p_packet_buffers,
850 : : int irq_vector,
851 : : uint8_t rx_deferred_start)
852 : : {
853 : : struct virtq_struct_layout_s virtq_struct_layout = dbs_calc_struct_layout(queue_size);
854 : 0 : struct nthw_virt_queue *vq = dbs_alloc_virt_queue(p_nthw_dbs);
855 : :
856 [ # # ]: 0 : if (vq == NULL)
857 : : return NULL;
858 : :
859 [ # # ]: 0 : dbs_initialize_virt_queue_structs(p_virt_struct_area->virt_addr,
860 : : (char *)p_virt_struct_area->virt_addr +
861 : : virtq_struct_layout.used_offset,
862 : 0 : (char *)p_virt_struct_area->virt_addr +
863 : : virtq_struct_layout.desc_offset,
864 : : p_packet_buffers,
865 : 0 : (uint16_t)queue_size,
866 : : p_packet_buffers ? (uint16_t)queue_size : 0,
867 : : VIRTQ_DESC_F_WRITE /* Rx */);
868 : :
869 : 0 : vq->p_avail = p_virt_struct_area->virt_addr;
870 : 0 : vq->p_used =
871 : : (void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.used_offset);
872 : 0 : vq->p_desc =
873 : : (void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.desc_offset);
874 : :
875 [ # # ]: 0 : vq->am_idx = p_packet_buffers ? (uint16_t)queue_size : 0;
876 : :
877 [ # # # # ]: 0 : if (p_packet_buffers &&
878 : 0 : dbs_copy_packet_buffers(vq, p_packet_buffers, queue_size) != 0) {
879 : 0 : dbs_free_virt_queue(vq);
880 : 0 : return NULL;
881 : : }
882 : :
883 [ # # ]: 0 : if (nthw_setup_rx_virt_queue(vq, index, 0, 0,
884 : : (void *)p_virt_struct_area->phys_addr,
885 : : (char *)p_virt_struct_area->phys_addr + virtq_struct_layout.used_offset,
886 : 0 : (char *)p_virt_struct_area->phys_addr + virtq_struct_layout.desc_offset,
887 : : (uint16_t)queue_size, host_id, header, SPLIT_RING, irq_vector,
888 : : rx_deferred_start) != 0) {
889 : 0 : dbs_free_virt_queue(vq);
890 : 0 : return NULL;
891 : : }
892 : :
893 : 0 : vq->usage = NTHW_VIRTQ_MANAGED;
894 : :
895 : 0 : return vq;
896 : : }
897 : :
898 : : static struct nthw_virt_queue *
899 [ # # ]: 0 : nthw_setup_mngd_tx_virt_queue_split(nthw_dbs_t *p_nthw_dbs,
900 : : uint32_t index,
901 : : uint32_t queue_size,
902 : : uint32_t host_id,
903 : : uint32_t port,
904 : : uint32_t virtual_port,
905 : : uint32_t header,
906 : : int irq_vector,
907 : : uint32_t in_order,
908 : : struct nthw_memory_descriptor *p_virt_struct_area,
909 : : struct nthw_memory_descriptor *p_packet_buffers,
910 : : uint8_t tx_deferred_start)
911 : : {
912 : : struct virtq_struct_layout_s virtq_struct_layout = dbs_calc_struct_layout(queue_size);
913 : 0 : struct nthw_virt_queue *vq = dbs_alloc_virt_queue(p_nthw_dbs);
914 : :
915 [ # # ]: 0 : if (vq == NULL)
916 : : return NULL;
917 : :
918 : 0 : dbs_initialize_virt_queue_structs(p_virt_struct_area->virt_addr,
919 : : (char *)p_virt_struct_area->virt_addr +
920 : : virtq_struct_layout.used_offset,
921 : 0 : (char *)p_virt_struct_area->virt_addr +
922 : : virtq_struct_layout.desc_offset,
923 : : p_packet_buffers,
924 : 0 : (uint16_t)queue_size,
925 : : 0,
926 : : 0 /* Tx */);
927 : :
928 : 0 : vq->p_avail = p_virt_struct_area->virt_addr;
929 : 0 : vq->p_used =
930 : : (void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.used_offset);
931 : 0 : vq->p_desc =
932 : : (void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.desc_offset);
933 : 0 : vq->queue_size = (uint16_t)queue_size;
934 : :
935 [ # # # # ]: 0 : if (p_packet_buffers &&
936 : 0 : dbs_copy_packet_buffers(vq, p_packet_buffers, queue_size) != 0) {
937 : 0 : dbs_free_virt_queue(vq);
938 : 0 : return NULL;
939 : : }
940 : :
941 [ # # ]: 0 : if (nthw_setup_tx_virt_queue(vq, index, 0, 0,
942 : : (void *)p_virt_struct_area->phys_addr,
943 : : (char *)p_virt_struct_area->phys_addr + virtq_struct_layout.used_offset,
944 : 0 : (char *)p_virt_struct_area->phys_addr + virtq_struct_layout.desc_offset,
945 : : (uint16_t)queue_size, host_id, port, virtual_port, header,
946 : : SPLIT_RING, irq_vector, in_order, tx_deferred_start) != 0) {
947 : 0 : dbs_free_virt_queue(vq);
948 : 0 : return NULL;
949 : : }
950 : :
951 : 0 : vq->usage = NTHW_VIRTQ_MANAGED;
952 : :
953 : 0 : return vq;
954 : : }
955 : :
956 : : /*
957 : : * Packed Ring
958 : : */
959 : 0 : static int nthw_setup_managed_virt_queue_packed(struct nthw_virt_queue *vq,
960 : : struct pvirtq_struct_layout_s *pvirtq_layout,
961 : : struct nthw_memory_descriptor *p_virt_struct_area,
962 : : struct nthw_memory_descriptor *p_packet_buffers,
963 : : uint16_t flags,
964 : : int rx)
965 : : {
966 : : /* page aligned */
967 : : RTE_ASSERT(((uintptr_t)p_virt_struct_area->phys_addr & 0xfff) == 0);
968 : : RTE_ASSERT(p_packet_buffers);
969 : :
970 : : /* clean canvas */
971 [ # # ]: 0 : if (p_virt_struct_area->virt_addr == NULL)
972 : : return -1;
973 : :
974 : 0 : memset(p_virt_struct_area->virt_addr, 0,
975 : 0 : sizeof(struct pvirtq_desc) * vq->queue_size +
976 : 0 : sizeof(struct pvirtq_event_suppress) * 2 + sizeof(int) * vq->queue_size);
977 : :
978 : 0 : pvirtq_layout->device_event_offset = sizeof(struct pvirtq_desc) * vq->queue_size;
979 : 0 : pvirtq_layout->driver_event_offset =
980 : 0 : pvirtq_layout->device_event_offset + sizeof(struct pvirtq_event_suppress);
981 : :
982 : 0 : vq->desc = p_virt_struct_area->virt_addr;
983 : 0 : vq->device_event = (void *)((uintptr_t)vq->desc + pvirtq_layout->device_event_offset);
984 : 0 : vq->driver_event = (void *)((uintptr_t)vq->desc + pvirtq_layout->driver_event_offset);
985 : :
986 : 0 : vq->next_avail = 0;
987 : 0 : vq->next_used = 0;
988 : 0 : vq->avail_wrap_count = 1;
989 : 0 : vq->used_wrap_count = 1;
990 : :
991 : : /*
992 : : * Only possible if FPGA always delivers in-order
993 : : * Buffer ID used is the index in the p_packet_buffers array
994 : : */
995 : : unsigned int i;
996 : : struct pvirtq_desc *p_desc = vq->desc;
997 : :
998 [ # # ]: 0 : for (i = 0; i < vq->queue_size; i++) {
999 [ # # ]: 0 : if (rx) {
1000 : 0 : p_desc[i].addr = (uint64_t)p_packet_buffers[i].phys_addr;
1001 : 0 : p_desc[i].len = p_packet_buffers[i].len;
1002 : : }
1003 : :
1004 : 0 : p_desc[i].id = i;
1005 : 0 : p_desc[i].flags = flags;
1006 : : }
1007 : :
1008 [ # # ]: 0 : if (rx)
1009 : 0 : vq->avail_wrap_count ^= 1; /* filled up available buffers for Rx */
1010 : : else
1011 : 0 : vq->used_wrap_count ^= 1; /* pre-fill free buffer IDs */
1012 : :
1013 [ # # ]: 0 : if (dbs_copy_packet_buffers(vq, p_packet_buffers, vq->queue_size) != 0)
1014 : : return -1;
1015 : :
1016 : : /* Not used yet by FPGA - make sure we disable */
1017 : 0 : vq->device_event->flags = RING_EVENT_FLAGS_DISABLE;
1018 : :
1019 : 0 : return 0;
1020 : : }
1021 : :
1022 : : static struct nthw_virt_queue *
1023 : 0 : nthw_setup_managed_rx_virt_queue_packed(nthw_dbs_t *p_nthw_dbs,
1024 : : uint32_t index,
1025 : : uint32_t queue_size,
1026 : : uint32_t host_id,
1027 : : uint32_t header,
1028 : : struct nthw_memory_descriptor *p_virt_struct_area,
1029 : : struct nthw_memory_descriptor *p_packet_buffers,
1030 : : int irq_vector,
1031 : : uint8_t rx_deferred_start)
1032 : : {
1033 : : struct pvirtq_struct_layout_s pvirtq_layout;
1034 : 0 : struct nthw_virt_queue *vq = dbs_alloc_virt_queue(p_nthw_dbs);
1035 : :
1036 [ # # ]: 0 : if (vq == NULL)
1037 : : return NULL;
1038 : :
1039 : : /* Set size and setup packed vq ring */
1040 : 0 : vq->queue_size = queue_size;
1041 : :
1042 : : /* Use Avail flag bit == 1 because wrap bit is initially set to 1 - and Used is inverse */
1043 [ # # ]: 0 : if (nthw_setup_managed_virt_queue_packed(vq, &pvirtq_layout, p_virt_struct_area,
1044 : : p_packet_buffers,
1045 : : VIRTQ_DESC_F_WRITE | VIRTQ_DESC_F_AVAIL, 1) != 0) {
1046 : 0 : dbs_free_virt_queue(vq);
1047 : 0 : return NULL;
1048 : : }
1049 : :
1050 [ # # ]: 0 : if (nthw_setup_rx_virt_queue(vq, index,
1051 : : 0x8000, 0, /* start wrap ring counter as 1 */
1052 : 0 : (void *)((uintptr_t)p_virt_struct_area->phys_addr +
1053 : 0 : pvirtq_layout.driver_event_offset),
1054 : 0 : (void *)((uintptr_t)p_virt_struct_area->phys_addr +
1055 : 0 : pvirtq_layout.device_event_offset),
1056 : : p_virt_struct_area->phys_addr, (uint16_t)queue_size, host_id,
1057 : : header, PACKED_RING, irq_vector, rx_deferred_start) != 0) {
1058 : 0 : dbs_free_virt_queue(vq);
1059 : 0 : return NULL;
1060 : : }
1061 : :
1062 : 0 : vq->usage = NTHW_VIRTQ_MANAGED;
1063 : 0 : return vq;
1064 : : }
1065 : :
1066 : : static struct nthw_virt_queue *
1067 : 0 : nthw_setup_managed_tx_virt_queue_packed(nthw_dbs_t *p_nthw_dbs,
1068 : : uint32_t index,
1069 : : uint32_t queue_size,
1070 : : uint32_t host_id,
1071 : : uint32_t port,
1072 : : uint32_t virtual_port,
1073 : : uint32_t header,
1074 : : int irq_vector,
1075 : : uint32_t in_order,
1076 : : struct nthw_memory_descriptor *p_virt_struct_area,
1077 : : struct nthw_memory_descriptor *p_packet_buffers,
1078 : : uint8_t tx_deferred_start)
1079 : : {
1080 : : struct pvirtq_struct_layout_s pvirtq_layout;
1081 : 0 : struct nthw_virt_queue *vq = dbs_alloc_virt_queue(p_nthw_dbs);
1082 : :
1083 [ # # ]: 0 : if (vq == NULL)
1084 : : return NULL;
1085 : :
1086 : : /* Set size and setup packed vq ring */
1087 : 0 : vq->queue_size = queue_size;
1088 : :
1089 [ # # ]: 0 : if (nthw_setup_managed_virt_queue_packed(vq, &pvirtq_layout, p_virt_struct_area,
1090 : : p_packet_buffers, 0, 0) != 0) {
1091 : 0 : dbs_free_virt_queue(vq);
1092 : 0 : return NULL;
1093 : : }
1094 : :
1095 [ # # ]: 0 : if (nthw_setup_tx_virt_queue(vq, index,
1096 : : 0x8000, 0, /* start wrap ring counter as 1 */
1097 : 0 : (void *)((uintptr_t)p_virt_struct_area->phys_addr +
1098 : 0 : pvirtq_layout.driver_event_offset),
1099 : 0 : (void *)((uintptr_t)p_virt_struct_area->phys_addr +
1100 : 0 : pvirtq_layout.device_event_offset),
1101 : : p_virt_struct_area->phys_addr, (uint16_t)queue_size, host_id,
1102 : : port, virtual_port, header, PACKED_RING, irq_vector, in_order,
1103 : : tx_deferred_start) != 0) {
1104 : 0 : dbs_free_virt_queue(vq);
1105 : 0 : return NULL;
1106 : : }
1107 : :
1108 : 0 : vq->usage = NTHW_VIRTQ_MANAGED;
1109 : 0 : return vq;
1110 : : }
1111 : :
1112 : : /*
1113 : : * Create a Managed Rx Virt Queue
1114 : : *
1115 : : * Notice: The queue will be created with interrupts disabled.
1116 : : * If interrupts are required, make sure to call nthw_enable_rx_virt_queue()
1117 : : * afterwards.
1118 : : */
1119 : : static struct nthw_virt_queue *
1120 : 0 : nthw_setup_mngd_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
1121 : : uint32_t index,
1122 : : uint32_t queue_size,
1123 : : uint32_t host_id,
1124 : : uint32_t header,
1125 : : struct nthw_memory_descriptor *p_virt_struct_area,
1126 : : struct nthw_memory_descriptor *p_packet_buffers,
1127 : : uint32_t vq_type,
1128 : : int irq_vector,
1129 : : uint8_t rx_deferred_start)
1130 : : {
1131 [ # # # ]: 0 : switch (vq_type) {
1132 : 0 : case SPLIT_RING:
1133 : 0 : return nthw_setup_mngd_rx_virt_queue_split(p_nthw_dbs, index, queue_size,
1134 : : host_id, header, p_virt_struct_area,
1135 : : p_packet_buffers, irq_vector, rx_deferred_start);
1136 : :
1137 : 0 : case PACKED_RING:
1138 : 0 : return nthw_setup_managed_rx_virt_queue_packed(p_nthw_dbs, index, queue_size,
1139 : : host_id, header, p_virt_struct_area,
1140 : : p_packet_buffers, irq_vector, rx_deferred_start);
1141 : :
1142 : : default:
1143 : : break;
1144 : : }
1145 : :
1146 : : return NULL;
1147 : : }
1148 : :
1149 : : /*
1150 : : * Create a Managed Tx Virt Queue
1151 : : *
1152 : : * Notice: The queue will be created with interrupts disabled.
1153 : : * If interrupts are required, make sure to call nthw_enable_tx_virt_queue()
1154 : : * afterwards.
1155 : : */
1156 : : static struct nthw_virt_queue *
1157 : 0 : nthw_setup_mngd_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
1158 : : uint32_t index,
1159 : : uint32_t queue_size,
1160 : : uint32_t host_id,
1161 : : uint32_t port,
1162 : : uint32_t virtual_port,
1163 : : uint32_t header,
1164 : : struct nthw_memory_descriptor *p_virt_struct_area,
1165 : : struct nthw_memory_descriptor *p_packet_buffers,
1166 : : uint32_t vq_type,
1167 : : int irq_vector,
1168 : : uint32_t in_order,
1169 : : uint8_t tx_deferred_start)
1170 : : {
1171 [ # # # ]: 0 : switch (vq_type) {
1172 : 0 : case SPLIT_RING:
1173 : 0 : return nthw_setup_mngd_tx_virt_queue_split(p_nthw_dbs, index, queue_size,
1174 : : host_id, port, virtual_port, header,
1175 : : irq_vector, in_order,
1176 : : p_virt_struct_area,
1177 : : p_packet_buffers, tx_deferred_start);
1178 : :
1179 : 0 : case PACKED_RING:
1180 : 0 : return nthw_setup_managed_tx_virt_queue_packed(p_nthw_dbs, index, queue_size,
1181 : : host_id, port, virtual_port, header,
1182 : : irq_vector, in_order,
1183 : : p_virt_struct_area,
1184 : : p_packet_buffers, tx_deferred_start);
1185 : :
1186 : : default:
1187 : : break;
1188 : : }
1189 : :
1190 : : return NULL;
1191 : : }
1192 : :
1193 : 0 : static int nthw_switch_rx_virt_queue(nthw_dbs_t *p_nthw_dbs, uint32_t index, uint32_t enable)
1194 : : {
1195 : 0 : return nthw_set_rx_am_data_enable(p_nthw_dbs, index, enable);
1196 : : }
1197 : :
1198 : 0 : static int nthw_switch_tx_virt_queue(nthw_dbs_t *p_nthw_dbs, uint32_t index, uint32_t enable)
1199 : : {
1200 : 0 : return nthw_set_tx_am_data_enable(p_nthw_dbs, index, enable);
1201 : : }
1202 : :
1203 : 0 : static uint16_t nthw_get_rx_packets(struct nthw_virt_queue *rxvq,
1204 : : uint16_t n,
1205 : : struct nthw_received_packets *rp,
1206 : : uint16_t *nb_pkts)
1207 : : {
1208 : : uint16_t segs = 0;
1209 : : uint16_t pkts = 0;
1210 : :
1211 [ # # ]: 0 : if (rxvq->vq_type == SPLIT_RING) {
1212 : : uint16_t i;
1213 : 0 : uint16_t entries_ready = (uint16_t)(rxvq->cached_idx - rxvq->used_idx);
1214 : :
1215 [ # # ]: 0 : if (entries_ready < n) {
1216 : : /* Look for more packets */
1217 : 0 : rxvq->cached_idx = rxvq->p_used->idx;
1218 : 0 : entries_ready = (uint16_t)(rxvq->cached_idx - rxvq->used_idx);
1219 : :
1220 [ # # ]: 0 : if (entries_ready == 0) {
1221 : 0 : *nb_pkts = 0;
1222 : 0 : return 0;
1223 : : }
1224 : :
1225 : : if (n > entries_ready)
1226 : : n = entries_ready;
1227 : : }
1228 : :
1229 : : /*
1230 : : * Give packets - make sure all packets are whole packets.
1231 : : * Valid because queue_size is always 2^n
1232 : : */
1233 : 0 : const uint16_t queue_mask = (uint16_t)(rxvq->queue_size - 1);
1234 : 0 : const uint32_t buf_len = rxvq->p_desc[0].len;
1235 : :
1236 : : uint16_t used = rxvq->used_idx;
1237 : :
1238 [ # # ]: 0 : for (i = 0; i < n; ++i) {
1239 : 0 : uint32_t id = rxvq->p_used->ring[used & queue_mask].id;
1240 : 0 : rp[i].addr = rxvq->p_virtual_addr[id].virt_addr;
1241 : 0 : rp[i].len = rxvq->p_used->ring[used & queue_mask].len;
1242 : :
1243 : 0 : uint32_t pkt_len = ((struct _pkt_hdr_rx *)rp[i].addr)->cap_len;
1244 : :
1245 [ # # ]: 0 : if (pkt_len > buf_len) {
1246 : : /* segmented */
1247 : 0 : int nbsegs = (pkt_len + buf_len - 1) / buf_len;
1248 : :
1249 [ # # ]: 0 : if (((int)i + nbsegs) > n) {
1250 : : /* don't have enough segments - break out */
1251 : : break;
1252 : : }
1253 : :
1254 : : int ii;
1255 : :
1256 [ # # ]: 0 : for (ii = 1; ii < nbsegs; ii++) {
1257 : 0 : ++i;
1258 : 0 : id = rxvq->p_used->ring[(used + ii) & queue_mask].id;
1259 : 0 : rp[i].addr = rxvq->p_virtual_addr[id].virt_addr;
1260 : 0 : rp[i].len =
1261 : 0 : rxvq->p_used->ring[(used + ii) & queue_mask].len;
1262 : : }
1263 : :
1264 : 0 : used += nbsegs;
1265 : :
1266 : : } else {
1267 : 0 : ++used;
1268 : : }
1269 : :
1270 : 0 : pkts++;
1271 : 0 : segs = i + 1;
1272 : : }
1273 : :
1274 : 0 : rxvq->used_idx = used;
1275 : :
1276 [ # # ]: 0 : } else if (rxvq->vq_type == PACKED_RING) {
1277 : : /* This requires in-order behavior from FPGA */
1278 : : int i;
1279 : :
1280 [ # # ]: 0 : for (i = 0; i < n; i++) {
1281 : 0 : struct pvirtq_desc *desc = &rxvq->desc[rxvq->next_used];
1282 : :
1283 : 0 : uint16_t flags = desc->flags;
1284 : 0 : uint8_t avail = !!(flags & VIRTQ_DESC_F_AVAIL);
1285 : 0 : uint8_t used = !!(flags & VIRTQ_DESC_F_USED);
1286 : :
1287 [ # # # # ]: 0 : if (avail != rxvq->used_wrap_count || used != rxvq->used_wrap_count)
1288 : : break;
1289 : :
1290 : 0 : rp[pkts].addr = rxvq->p_virtual_addr[desc->id].virt_addr;
1291 : 0 : rp[pkts].len = desc->len;
1292 : 0 : pkts++;
1293 : :
1294 [ # # ]: 0 : inc_used(rxvq, 1);
1295 : : }
1296 : :
1297 : : segs = pkts;
1298 : : }
1299 : :
1300 : 0 : *nb_pkts = pkts;
1301 : 0 : return segs;
1302 : : }
1303 : :
1304 : : /*
1305 : : * Put buffers back into Avail Ring
1306 : : */
1307 : 0 : static void nthw_release_rx_packets(struct nthw_virt_queue *rxvq, uint16_t n)
1308 : : {
1309 [ # # ]: 0 : if (rxvq->vq_type == SPLIT_RING) {
1310 : 0 : rxvq->am_idx = (uint16_t)(rxvq->am_idx + n);
1311 : 0 : rxvq->p_avail->idx = rxvq->am_idx;
1312 : :
1313 [ # # ]: 0 : } else if (rxvq->vq_type == PACKED_RING) {
1314 : : int i;
1315 : : /*
1316 : : * Defer flags update on first segment - due to serialization towards HW and
1317 : : * when jumbo segments are added
1318 : : */
1319 : :
1320 [ # # # # ]: 0 : uint16_t first_flags = VIRTQ_DESC_F_WRITE | avail_flag(rxvq) | used_flag_inv(rxvq);
1321 : 0 : struct pvirtq_desc *first_desc = &rxvq->desc[rxvq->next_avail];
1322 : :
1323 : 0 : uint32_t len = rxvq->p_virtual_addr[0].len; /* all same size */
1324 : :
1325 : : /* Optimization point: use in-order release */
1326 : :
1327 [ # # ]: 0 : for (i = 0; i < n; i++) {
1328 : 0 : struct pvirtq_desc *desc = &rxvq->desc[rxvq->next_avail];
1329 : :
1330 : 0 : desc->id = rxvq->next_avail;
1331 : 0 : desc->addr = (uint64_t)rxvq->p_virtual_addr[desc->id].phys_addr;
1332 : 0 : desc->len = len;
1333 : :
1334 [ # # ]: 0 : if (i)
1335 [ # # # # ]: 0 : desc->flags = VIRTQ_DESC_F_WRITE | avail_flag(rxvq) |
1336 : : used_flag_inv(rxvq);
1337 : :
1338 [ # # ]: 0 : inc_avail(rxvq, 1);
1339 : : }
1340 : :
1341 : : rte_rmb();
1342 : 0 : first_desc->flags = first_flags;
1343 : : }
1344 : 0 : }
1345 : :
1346 : 0 : static uint16_t nthw_get_tx_packets(struct nthw_virt_queue *txvq,
1347 : : uint16_t n,
1348 : : uint16_t *first_idx,
1349 : : struct nthw_cvirtq_desc *cvq,
1350 : : struct nthw_memory_descriptor **p_virt_addr)
1351 : : {
1352 : : int m = 0;
1353 : 0 : uint16_t queue_mask =
1354 : 0 : (uint16_t)(txvq->queue_size - 1); /* Valid because queue_size is always 2^n */
1355 : 0 : *p_virt_addr = txvq->p_virtual_addr;
1356 : :
1357 [ # # ]: 0 : if (txvq->vq_type == SPLIT_RING) {
1358 : 0 : cvq->s = txvq->p_desc;
1359 : 0 : cvq->vq_type = SPLIT_RING;
1360 : :
1361 : 0 : *first_idx = txvq->tx_descr_avail_idx;
1362 : :
1363 : : uint16_t entries_used =
1364 : 0 : (uint16_t)((txvq->tx_descr_avail_idx - txvq->cached_idx) & queue_mask);
1365 : 0 : uint16_t entries_ready = (uint16_t)(txvq->queue_size - 1 - entries_used);
1366 : :
1367 : : vq_log_arg(txvq,
1368 : : "ask %i: descrAvail %i, cachedidx %i, used: %i, ready %i used->idx %i",
1369 : : n, txvq->tx_descr_avail_idx, txvq->cached_idx, entries_used, entries_ready,
1370 : : txvq->p_used->idx);
1371 : :
1372 [ # # ]: 0 : if (entries_ready < n) {
1373 : : /*
1374 : : * Look for more packets.
1375 : : * Using the used_idx in the avail ring since they are held synchronous
1376 : : * because of in-order
1377 : : */
1378 : 0 : txvq->cached_idx =
1379 : 0 : txvq->p_avail->ring[(txvq->p_used->idx - 1) & queue_mask];
1380 : :
1381 : : vq_log_arg(txvq, "Update: get cachedidx %i (used_idx-1 %i)",
1382 : : txvq->cached_idx, (txvq->p_used->idx - 1) & queue_mask);
1383 : : entries_used =
1384 : 0 : (uint16_t)((txvq->tx_descr_avail_idx - txvq->cached_idx)
1385 : : & queue_mask);
1386 : 0 : entries_ready = (uint16_t)(txvq->queue_size - 1 - entries_used);
1387 : : vq_log_arg(txvq, "new used: %i, ready %i", entries_used, entries_ready);
1388 : :
1389 : : if (n > entries_ready)
1390 : : n = entries_ready;
1391 : : }
1392 : :
1393 [ # # ]: 0 : } else if (txvq->vq_type == PACKED_RING) {
1394 : : int i;
1395 : :
1396 : 0 : cvq->p = txvq->desc;
1397 : 0 : cvq->vq_type = PACKED_RING;
1398 : :
1399 [ # # ]: 0 : if (txvq->outs.num) {
1400 : 0 : *first_idx = txvq->outs.next;
1401 [ # # ]: 0 : uint16_t num = min(n, txvq->outs.num);
1402 : 0 : txvq->outs.next = (txvq->outs.next + num) & queue_mask;
1403 : 0 : txvq->outs.num -= num;
1404 : :
1405 [ # # ]: 0 : if (n == num)
1406 : : return n;
1407 : :
1408 : : m = num;
1409 : 0 : n -= num;
1410 : :
1411 : : } else {
1412 : 0 : *first_idx = txvq->next_used;
1413 : : }
1414 : :
1415 : : /* iterate the ring - this requires in-order behavior from FPGA */
1416 [ # # ]: 0 : for (i = 0; i < n; i++) {
1417 : 0 : struct pvirtq_desc *desc = &txvq->desc[txvq->next_used];
1418 : :
1419 : 0 : uint16_t flags = desc->flags;
1420 : 0 : uint8_t avail = !!(flags & VIRTQ_DESC_F_AVAIL);
1421 : 0 : uint8_t used = !!(flags & VIRTQ_DESC_F_USED);
1422 : :
1423 [ # # # # ]: 0 : if (avail != txvq->used_wrap_count || used != txvq->used_wrap_count) {
1424 : 0 : n = i;
1425 : 0 : break;
1426 : : }
1427 : :
1428 : 0 : uint16_t incr = (desc->id - txvq->next_used) & queue_mask;
1429 : 0 : i += incr;
1430 [ # # ]: 0 : inc_used(txvq, incr + 1);
1431 : : }
1432 : :
1433 [ # # ]: 0 : if (i > n) {
1434 : 0 : int outs_num = i - n;
1435 : 0 : txvq->outs.next = (txvq->next_used - outs_num) & queue_mask;
1436 : 0 : txvq->outs.num = outs_num;
1437 : : }
1438 : :
1439 : : } else {
1440 : : return 0;
1441 : : }
1442 : :
1443 : 0 : return m + n;
1444 : : }
1445 : :
1446 : 0 : static void nthw_release_tx_packets(struct nthw_virt_queue *txvq, uint16_t n, uint16_t n_segs[])
1447 : : {
1448 : : int i;
1449 : :
1450 [ # # ]: 0 : if (txvq->vq_type == SPLIT_RING) {
1451 : : /* Valid because queue_size is always 2^n */
1452 : 0 : uint16_t queue_mask = (uint16_t)(txvq->queue_size - 1);
1453 : :
1454 : : vq_log_arg(txvq, "pkts %i, avail idx %i, start at %i", n, txvq->am_idx,
1455 : : txvq->tx_descr_avail_idx);
1456 : :
1457 [ # # ]: 0 : for (i = 0; i < n; i++) {
1458 : 0 : int idx = txvq->am_idx & queue_mask;
1459 : 0 : txvq->p_avail->ring[idx] = txvq->tx_descr_avail_idx;
1460 : 0 : txvq->tx_descr_avail_idx =
1461 : 0 : (txvq->tx_descr_avail_idx + n_segs[i]) & queue_mask;
1462 : 0 : txvq->am_idx++;
1463 : : }
1464 : :
1465 : : /* Make sure the ring has been updated before HW reads index update */
1466 : : rte_mb();
1467 : 0 : txvq->p_avail->idx = txvq->am_idx;
1468 : : vq_log_arg(txvq, "new avail idx %i, descr_idx %i", txvq->p_avail->idx,
1469 : : txvq->tx_descr_avail_idx);
1470 : :
1471 [ # # ]: 0 : } else if (txvq->vq_type == PACKED_RING) {
1472 : : /*
1473 : : * Defer flags update on first segment - due to serialization towards HW and
1474 : : * when jumbo segments are added
1475 : : */
1476 : :
1477 [ # # # # ]: 0 : uint16_t first_flags = avail_flag(txvq) | used_flag_inv(txvq);
1478 : 0 : struct pvirtq_desc *first_desc = &txvq->desc[txvq->next_avail];
1479 : :
1480 [ # # ]: 0 : for (i = 0; i < n; i++) {
1481 : 0 : struct pvirtq_desc *desc = &txvq->desc[txvq->next_avail];
1482 : :
1483 : 0 : desc->id = txvq->next_avail;
1484 : 0 : desc->addr = (uint64_t)txvq->p_virtual_addr[desc->id].phys_addr;
1485 : :
1486 [ # # ]: 0 : if (i)
1487 : : /* bitwise-or here because next flags may already have been setup
1488 : : */
1489 [ # # # # ]: 0 : desc->flags |= avail_flag(txvq) | used_flag_inv(txvq);
1490 : :
1491 [ # # ]: 0 : inc_avail(txvq, 1);
1492 : : }
1493 : :
1494 : : /* Proper read barrier before FPGA may see first flags */
1495 : : rte_rmb();
1496 : 0 : first_desc->flags = first_flags;
1497 : : }
1498 : 0 : }
1499 : :
1500 : : static struct sg_ops_s sg_ops = {
1501 : : .nthw_setup_mngd_rx_virt_queue = nthw_setup_mngd_rx_virt_queue,
1502 : : .nthw_release_mngd_rx_virt_queue = nthw_release_mngd_rx_virt_queue,
1503 : : .nthw_setup_mngd_tx_virt_queue = nthw_setup_mngd_tx_virt_queue,
1504 : : .nthw_release_mngd_tx_virt_queue = nthw_release_mngd_tx_virt_queue,
1505 : : .nthw_switch_rx_virt_queue = nthw_switch_rx_virt_queue,
1506 : : .nthw_switch_tx_virt_queue = nthw_switch_tx_virt_queue,
1507 : : .nthw_get_rx_packets = nthw_get_rx_packets,
1508 : : .nthw_release_rx_packets = nthw_release_rx_packets,
1509 : : .nthw_get_tx_packets = nthw_get_tx_packets,
1510 : : .nthw_release_tx_packets = nthw_release_tx_packets,
1511 : : .nthw_virt_queue_init = nthw_virt_queue_init
1512 : : };
1513 : :
1514 : 0 : void nthw_sg_init(void)
1515 : : {
1516 : 0 : NT_LOG(INF, NTNIC, "SG ops initialized");
1517 : 0 : nthw_reg_sg_ops(&sg_ops);
1518 : 0 : }
|