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