ena: Amazon Elastic Network Adapter (ENA) native driver
[vpp.git] / src / plugins / dev_ena / queue.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright(c) 2023 Cisco Systems, Inc.
3  */
4
5 #include <vlib/vlib.h>
6 #include <vnet/dev/dev.h>
7
8 #include <dev_ena/ena.h>
9 #include <dev_ena/ena_inlines.h>
10
11 VLIB_REGISTER_LOG_CLASS (ena_log, static) = {
12   .class_name = "ena",
13   .subclass_name = "queue",
14 };
15
16 void
17 ena_rx_queue_free (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
18 {
19   ena_rxq_t *eq = vnet_dev_get_rx_queue_data (rxq);
20   vnet_dev_port_t *port = rxq->port;
21   vnet_dev_t *dev = port->dev;
22
23   ASSERT (rxq->started == 0);
24   ASSERT (eq->cq_created == 0);
25   ASSERT (eq->sq_created == 0);
26
27   log_debug (dev, "queue %u", rxq->queue_id);
28
29   foreach_pointer (p, eq->buffer_indices, eq->compl_sqe_indices)
30     if (p)
31       clib_mem_free (p);
32
33   foreach_pointer (p, eq->cqes, eq->sqes)
34     vnet_dev_dma_mem_free (vm, dev, p);
35 }
36
37 vnet_dev_rv_t
38 ena_rx_queue_alloc (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
39 {
40   vnet_dev_port_t *port = rxq->port;
41   vnet_dev_t *dev = port->dev;
42   ena_rxq_t *eq = vnet_dev_get_rx_queue_data (rxq);
43   u16 size = rxq->size;
44   vnet_dev_rv_t rv;
45
46   ASSERT (eq->buffer_indices == 0);
47   ASSERT (eq->compl_sqe_indices == 0);
48   ASSERT (eq->cqes == 0);
49   ASSERT (eq->sqes == 0);
50
51   log_debug (dev, "queue %u", rxq->queue_id);
52
53   eq->buffer_indices = clib_mem_alloc_aligned (
54     sizeof (eq->buffer_indices[0]) * size, CLIB_CACHE_LINE_BYTES);
55
56   eq->compl_sqe_indices = clib_mem_alloc_aligned (
57     sizeof (eq->compl_sqe_indices[0]) * size, CLIB_CACHE_LINE_BYTES);
58
59   if ((rv = vnet_dev_dma_mem_alloc (vm, dev, sizeof (eq->cqes[0]) * size, 0,
60                                     (void **) &eq->cqes)))
61     goto err;
62
63   if ((rv = vnet_dev_dma_mem_alloc (vm, dev, sizeof (eq->sqes[0]) * size, 0,
64                                     (void **) &eq->sqes)))
65     goto err;
66
67   return VNET_DEV_OK;
68
69 err:
70   ena_rx_queue_free (vm, rxq);
71   return rv;
72 }
73
74 void
75 ena_tx_queue_free (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
76 {
77   ena_txq_t *eq = vnet_dev_get_tx_queue_data (txq);
78   vnet_dev_port_t *port = txq->port;
79   vnet_dev_t *dev = port->dev;
80
81   ASSERT (txq->started == 0);
82
83   log_debug (dev, "queue %u", txq->queue_id);
84
85   foreach_pointer (p, eq->buffer_indices, eq->sqe_templates)
86     if (p)
87       clib_mem_free (p);
88
89   foreach_pointer (p, eq->cqes, eq->sqes)
90     vnet_dev_dma_mem_free (vm, dev, p);
91 }
92
93 vnet_dev_rv_t
94 ena_tx_queue_alloc (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
95 {
96   vnet_dev_port_t *port = txq->port;
97   vnet_dev_t *dev = port->dev;
98   ena_txq_t *eq = vnet_dev_get_tx_queue_data (txq);
99   u16 size = txq->size;
100   vnet_dev_rv_t rv;
101
102   ASSERT (eq->buffer_indices == 0);
103   ASSERT (eq->sqe_templates == 0);
104   ASSERT (eq->cqes == 0);
105   ASSERT (eq->sqes == 0);
106
107   log_debug (dev, "queue %u", txq->queue_id);
108
109   eq->buffer_indices = clib_mem_alloc_aligned (
110     sizeof (eq->buffer_indices[0]) * size, CLIB_CACHE_LINE_BYTES);
111   eq->sqe_templates = clib_mem_alloc_aligned (
112     sizeof (eq->sqe_templates[0]) * size, CLIB_CACHE_LINE_BYTES);
113
114   if ((rv = vnet_dev_dma_mem_alloc (vm, dev, sizeof (eq->cqes[0]) * size, 0,
115                                     (void **) &eq->cqes)))
116     goto err;
117
118   if ((rv = vnet_dev_dma_mem_alloc (vm, dev, sizeof (eq->sqes[0]) * size, 0,
119                                     (void **) &eq->sqes)))
120     goto err;
121
122   return VNET_DEV_OK;
123
124 err:
125   ena_tx_queue_free (vm, txq);
126   return rv;
127 }
128
129 vnet_dev_rv_t
130 ena_rx_queue_start (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
131 {
132   ena_rxq_t *eq = vnet_dev_get_rx_queue_data (rxq);
133   vnet_dev_port_t *port = rxq->port;
134   vnet_dev_t *dev = port->dev;
135   ena_device_t *ed = vnet_dev_get_data (dev);
136   u16 buffer_size = vnet_dev_get_rx_queue_buffer_data_size (vm, rxq);
137   u16 size = rxq->size;
138   vnet_dev_rv_t rv;
139
140   /* Create Completion Queue */
141   ena_aq_create_cq_resp_t cqresp;
142   ena_aq_create_cq_cmd_t cqcmd = {
143     .interrupt_mode_enabled = 1,
144     .cq_entry_size_words = sizeof (ena_rx_cdesc_t) / 4,
145     .cq_depth = size,
146     .msix_vector = ~0,
147   };
148
149   ena_set_mem_addr (vm, dev, &cqcmd.cq_ba, eq->cqes);
150   if ((rv = ena_aq_create_cq (vm, dev, &cqcmd, &cqresp)))
151     {
152       log_err (dev, "queue %u cq creation failed", rxq->queue_id);
153       goto error;
154     }
155
156   eq->cq_idx = cqresp.cq_idx;
157   eq->cq_created = 1;
158
159   log_debug (dev, "queue %u cq %u created", rxq->queue_id, eq->cq_idx);
160
161   /* Create Submission Queue */
162   ena_aq_create_sq_resp_t sqresp;
163   ena_aq_create_sq_cmd_t sqcmd = {
164     .sq_direction = ENA_ADMIN_SQ_DIRECTION_RX,
165     .placement_policy = ENA_ADMIN_SQ_PLACEMENT_POLICY_HOST,
166     .completion_policy = ENA_ADMIN_SQ_COMPLETION_POLICY_DESC,
167     .is_physically_contiguous = 1,
168     .sq_depth = size,
169     .cq_idx = cqresp.cq_idx,
170   };
171
172   ena_set_mem_addr (vm, dev, &sqcmd.sq_ba, eq->sqes);
173   if ((rv = ena_aq_create_sq (vm, dev, &sqcmd, &sqresp)))
174     {
175       log_err (dev, "queue %u sq creation failed", rxq->queue_id);
176       goto error;
177     }
178
179   eq->sq_idx = sqresp.sq_idx;
180   eq->sq_db = (u32 *) ((u8 *) ed->reg_bar + sqresp.sq_doorbell_offset);
181   eq->sq_created = 1;
182
183   log_debug (dev, "queue %u sq %u created, sq_db %p", rxq->queue_id,
184              eq->sq_idx, eq->sq_db);
185
186   for (int i = 0; i < size; i++)
187     {
188       eq->sqes[i] = (ena_rx_desc_t){
189         .lo = {
190           .length = buffer_size,
191           .comp_req = 1,
192           .first = 1,
193           .last = 1,
194           .reserved5 = 1, /* ena_com says MBO */
195           .req_id = i,
196         },
197       };
198       eq->buffer_indices[i] = VLIB_BUFFER_INVALID_INDEX;
199       eq->compl_sqe_indices[i] = i;
200     }
201
202   eq->sq_next = 0;
203   eq->n_compl_sqes = size;
204
205   return VNET_DEV_OK;
206
207 error:
208   ena_rx_queue_stop (vm, rxq);
209   return rv;
210 }
211
212 vnet_dev_rv_t
213 ena_tx_queue_start (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
214 {
215   ena_txq_t *eq = vnet_dev_get_tx_queue_data (txq);
216   vnet_dev_port_t *port = txq->port;
217   vnet_dev_t *dev = port->dev;
218   ena_device_t *ed = vnet_dev_get_data (dev);
219   u16 size = txq->size;
220   vnet_dev_rv_t rv;
221
222   /* Create Completion Queue */
223   ena_aq_create_cq_resp_t cqresp;
224   ena_aq_create_cq_cmd_t cqcmd = {
225     .interrupt_mode_enabled = 1,
226     .cq_entry_size_words = sizeof (ena_tx_cdesc_t) / 4,
227     .cq_depth = size,
228     .msix_vector = ~0,
229   };
230
231   ena_set_mem_addr (vm, dev, &cqcmd.cq_ba, eq->cqes);
232   if ((rv = ena_aq_create_cq (vm, dev, &cqcmd, &cqresp)))
233     {
234       log_err (dev, "queue %u cq creation failed", txq->queue_id);
235       goto error;
236     }
237
238   eq->cq_idx = cqresp.cq_idx;
239   eq->cq_created = 1;
240
241   log_debug (dev, "queue %u cq %u created", txq->queue_id, eq->cq_idx);
242
243   /* Create Submission Queue */
244   ena_aq_create_sq_resp_t sqresp;
245   ena_aq_create_sq_cmd_t sqcmd = {
246     .sq_direction = ENA_ADMIN_SQ_DIRECTION_TX,
247     .placement_policy = eq->llq ? ENA_ADMIN_SQ_PLACEMENT_POLICY_DEVICE :
248                                         ENA_ADMIN_SQ_PLACEMENT_POLICY_HOST,
249     .completion_policy = ENA_ADMIN_SQ_COMPLETION_POLICY_DESC,
250     .is_physically_contiguous = 1,
251     .sq_depth = size,
252     .cq_idx = cqresp.cq_idx,
253   };
254
255   if (eq->llq == 0)
256     ena_set_mem_addr (vm, dev, &sqcmd.sq_ba, eq->sqes);
257   if ((rv = ena_aq_create_sq (vm, dev, &sqcmd, &sqresp)))
258     {
259       log_err (dev, "queue %u sq creation failed", txq->queue_id);
260       goto error;
261     }
262
263   eq->sq_idx = sqresp.sq_idx;
264   eq->sq_db = (u32 *) ((u8 *) ed->reg_bar + sqresp.sq_doorbell_offset);
265   eq->sq_created = 1;
266
267   log_debug (dev, "queue %u sq %u created, sq_db %p", txq->queue_id,
268              eq->sq_idx, eq->sq_db);
269
270   for (u32 i = 0; i < size; i++)
271     {
272       eq->sqe_templates[i] =
273         (ena_tx_desc_t){ .req_id_lo = i, .req_id_hi = i >> 10, .comp_req = 1 }
274           .as_u64x2[0];
275
276       eq->buffer_indices[i] = VLIB_BUFFER_INVALID_INDEX;
277     }
278
279   eq->sq_head = 0;
280   eq->sq_tail = 0;
281   eq->cq_next = 0;
282
283 #if 0
284   if (txq->llq)
285     txq->llq_descs =
286       (ena_tx_llq_desc128_t *) ((u8 *) ed->mem_bar +
287                                 sqresp.llq_descriptors_offset);
288 #endif
289
290   log_debug (dev, "queue %u sq %u created, sq_db %p llq_desc %p",
291              txq->queue_id, eq->sq_idx, eq->sq_db,
292              eq->llq ? eq->llq_descs : 0);
293   return VNET_DEV_OK;
294
295 error:
296   ena_tx_queue_stop (vm, txq);
297   return rv;
298 }
299
300 static void
301 ena_free_sq_buffer_indices (vlib_main_t *vm, u32 *sq_buffer_indices,
302                             u32 n_desc)
303 {
304   u32 *to = sq_buffer_indices;
305
306   for (u32 *from = to; from < sq_buffer_indices + n_desc; from++)
307     if (from[0] != VLIB_BUFFER_INVALID_INDEX)
308       to++[0] = from[0];
309
310   if (to - sq_buffer_indices > 0)
311     vlib_buffer_free (vm, sq_buffer_indices, to - sq_buffer_indices);
312 }
313
314 void
315 ena_rx_queue_stop (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
316 {
317   ena_rxq_t *eq = vnet_dev_get_rx_queue_data (rxq);
318   vnet_dev_t *dev = rxq->port->dev;
319   vnet_dev_rv_t rv;
320
321   if (eq->sq_created)
322     {
323       ena_aq_destroy_sq_cmd_t cmd = {
324         .sq_idx = eq->sq_idx,
325         .sq_direction = ENA_ADMIN_SQ_DIRECTION_TX,
326       };
327
328       if ((rv = ena_aq_destroy_sq (vm, dev, &cmd)))
329         log_err (dev, "queue %u failed to destroy sq %u", rxq->queue_id,
330                  eq->sq_idx);
331       eq->sq_created = 0;
332     };
333
334   if (eq->cq_created)
335     {
336       ena_aq_destroy_cq_cmd_t cmd = {
337         .cq_idx = eq->cq_idx,
338       };
339
340       if ((rv = ena_aq_destroy_cq (vm, dev, &cmd)))
341         log_err (dev, "queue %u failed to destroy cq %u", rxq->queue_id,
342                  eq->cq_idx);
343       eq->cq_created = 0;
344     };
345
346   if (eq->n_compl_sqes < rxq->size)
347     ena_free_sq_buffer_indices (vm, eq->buffer_indices, rxq->size);
348 }
349
350 void
351 ena_tx_queue_stop (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
352 {
353   ena_txq_t *eq = vnet_dev_get_tx_queue_data (txq);
354   vnet_dev_t *dev = txq->port->dev;
355   vnet_dev_rv_t rv;
356
357   if (eq->sq_created)
358     {
359       ena_aq_destroy_sq_cmd_t cmd = {
360         .sq_idx = eq->sq_idx,
361         .sq_direction = ENA_ADMIN_SQ_DIRECTION_TX,
362       };
363
364       if ((rv = ena_aq_destroy_sq (vm, dev, &cmd)))
365         log_err (dev, "queue %u failed to destroy sq %u", txq->queue_id,
366                  eq->sq_idx);
367       eq->sq_created = 0;
368     };
369
370   if (eq->cq_created)
371     {
372       ena_aq_destroy_cq_cmd_t cmd = {
373         .cq_idx = eq->cq_idx,
374       };
375
376       if ((rv = ena_aq_destroy_cq (vm, dev, &cmd)))
377         log_err (dev, "queue %u failed to destroy cq %u", txq->queue_id,
378                  eq->cq_idx);
379       eq->cq_created = 0;
380     };
381
382   if (eq->sq_head != eq->sq_tail)
383     ena_free_sq_buffer_indices (vm, eq->buffer_indices, txq->size);
384 }