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