dev: new device driver infra
[vpp.git] / src / vnet / dev / queue.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2023 Cisco Systems, Inc.
3  */
4
5 #include <vnet/vnet.h>
6 #include <vnet/ethernet/ethernet.h>
7 #include <vnet/dev/dev.h>
8 #include <vnet/dev/counters.h>
9 #include <vnet/dev/log.h>
10
11 VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
12   .class_name = "dev",
13   .subclass_name = "error",
14 };
15
16 void
17 vnet_dev_rx_queue_free (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
18 {
19   vnet_dev_port_t *port = rxq->port;
20   vnet_dev_t *dev = port->dev;
21   log_debug (dev, "queue %u", rxq->queue_id);
22   if (port->rx_queue_ops.free)
23     port->rx_queue_ops.free (vm, rxq);
24
25   vnet_dev_rx_queue_free_counters (vm, rxq);
26   pool_put_index (port->rx_queues, rxq->index);
27   clib_mem_free (rxq);
28 }
29
30 vnet_dev_rv_t
31 vnet_dev_rx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port,
32                          u16 queue_size)
33 {
34   vnet_dev_main_t *dm = &vnet_dev_main;
35   vnet_dev_rx_queue_t *rxq, **qp;
36   vnet_dev_t *dev = port->dev;
37   vnet_dev_rv_t rv = VNET_DEV_OK;
38   u16 n_threads = vlib_get_n_threads ();
39   u8 buffer_pool_index;
40
41   vnet_dev_port_validate (vm, port);
42
43   log_debug (dev, "port %u queue_size %u", port->port_id, queue_size);
44
45   if (pool_elts (port->rx_queues) == port->attr.max_rx_queues)
46     return VNET_DEV_ERR_NO_AVAIL_QUEUES;
47
48   rxq = vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t),
49                                   port->rx_queue_config.data_size);
50   pool_get (port->rx_queues, qp);
51   qp[0] = rxq;
52   rxq->enabled = 1;
53   rxq->port = port;
54   rxq->size = queue_size;
55   rxq->index = qp - port->rx_queues;
56
57   /* default queue id - can be changed by driver */
58   rxq->queue_id = qp - port->rx_queues;
59   ASSERT (rxq->queue_id < port->attr.max_rx_queues);
60
61   if (n_threads > 1)
62     {
63       rxq->rx_thread_index = dm->next_rx_queue_thread++;
64       if (dm->next_rx_queue_thread >= n_threads)
65         dm->next_rx_queue_thread = 1;
66     }
67
68   buffer_pool_index =
69     vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node);
70   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
71
72   rxq->buffer_template = bp->buffer_template;
73   vnet_buffer (&rxq->buffer_template)->sw_if_index[VLIB_TX] = ~0;
74
75   rxq->next_index = vnet_dev_default_next_index_by_port_type[port->attr.type];
76
77   if (port->rx_queue_ops.alloc)
78     rv = port->rx_queue_ops.alloc (vm, rxq);
79
80   if (rv != VNET_DEV_OK)
81     {
82       log_err (dev, "driver rejected rx queue add with rv %d", rv);
83       vnet_dev_rx_queue_free (vm, rxq);
84     }
85   else
86     log_debug (dev, "queue %u added, assigned to thread %u", rxq->queue_id,
87                rxq->rx_thread_index);
88
89   return rv;
90 }
91
92 vnet_dev_rv_t
93 vnet_dev_rx_queue_start (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
94 {
95   vnet_dev_rv_t rv = VNET_DEV_OK;
96   if (rxq->port->rx_queue_ops.start)
97     rv = rxq->port->rx_queue_ops.start (vm, rxq);
98
99   if (rv == VNET_DEV_OK)
100     rxq->started = 1;
101
102   return rv;
103 }
104
105 void
106 vnet_dev_rx_queue_stop (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
107 {
108   if (rxq->port->rx_queue_ops.stop)
109     rxq->port->rx_queue_ops.stop (vm, rxq);
110   vlib_node_set_state (vm, rxq->port->intf.rx_node_index,
111                        VLIB_NODE_STATE_DISABLED);
112   rxq->started = 0;
113 }
114
115 void
116 vnet_dev_tx_queue_free (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
117 {
118   vnet_dev_port_t *port = txq->port;
119   vnet_dev_t *dev = port->dev;
120
121   vnet_dev_port_validate (vm, port);
122
123   log_debug (dev, "queue %u", txq->queue_id);
124   if (port->tx_queue_ops.free)
125     port->tx_queue_ops.free (vm, txq);
126
127   clib_bitmap_free (txq->assigned_threads);
128   vnet_dev_tx_queue_free_counters (vm, txq);
129   pool_put_index (port->tx_queues, txq->index);
130   clib_mem_free (txq);
131 }
132
133 vnet_dev_rv_t
134 vnet_dev_tx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port,
135                          u16 queue_size)
136 {
137   vnet_dev_tx_queue_t *txq, **qp;
138   vnet_dev_t *dev = port->dev;
139   vnet_dev_rv_t rv = VNET_DEV_OK;
140
141   log_debug (dev, "port %u size %u", port->port_id, queue_size);
142
143   if (pool_elts (port->tx_queues) == port->attr.max_tx_queues)
144     return VNET_DEV_ERR_NO_AVAIL_QUEUES;
145
146   txq = vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t),
147                                   port->tx_queue_config.data_size);
148   pool_get (port->tx_queues, qp);
149   qp[0] = txq;
150   txq->enabled = 1;
151   txq->port = port;
152   txq->size = queue_size;
153   txq->index = qp - port->tx_queues;
154
155   /* default queue id - can be changed by driver */
156   txq->queue_id = qp - port->tx_queues;
157   ASSERT (txq->queue_id < port->attr.max_tx_queues);
158
159   if (port->tx_queue_ops.alloc)
160     rv = port->tx_queue_ops.alloc (vm, txq);
161
162   if (rv != VNET_DEV_OK)
163     {
164       log_err (dev, "driver rejected tx queue alloc with rv %d", rv);
165       vnet_dev_tx_queue_free (vm, txq);
166     }
167   else
168     log_debug (dev, "queue %u added", txq->queue_id);
169
170   return rv;
171 }
172
173 vnet_dev_rv_t
174 vnet_dev_tx_queue_start (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
175 {
176   vnet_dev_rv_t rv = VNET_DEV_OK;
177   if (txq->port->tx_queue_ops.start)
178     rv = txq->port->tx_queue_ops.start (vm, txq);
179
180   if (rv == VNET_DEV_OK)
181     txq->started = 1;
182
183   return rv;
184 }
185
186 void
187 vnet_dev_tx_queue_stop (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
188 {
189   if (txq->port->tx_queue_ops.stop)
190     txq->port->tx_queue_ops.stop (vm, txq);
191   txq->started = 0;
192 }
193
194 void
195 vnet_dev_rx_queue_add_counters (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq,
196                                 vnet_dev_counter_t *counters, u16 n_counters)
197 {
198   rxq->counter_main = vnet_dev_counters_alloc (
199     vm, counters, n_counters, "%s port %u rx-queue %u counters",
200     rxq->port->dev->device_id, rxq->port->port_id, rxq->queue_id);
201 }
202
203 void
204 vnet_dev_rx_queue_free_counters (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
205 {
206   if (rxq->counter_main)
207     vnet_dev_counters_free (vm, rxq->counter_main);
208 }
209
210 void
211 vnet_dev_tx_queue_add_counters (vlib_main_t *vm, vnet_dev_tx_queue_t *txq,
212                                 vnet_dev_counter_t *counters, u16 n_counters)
213 {
214   txq->counter_main = vnet_dev_counters_alloc (
215     vm, counters, n_counters, "%s port %u tx-queue %u counters",
216     txq->port->dev->device_id, txq->port->port_id, txq->queue_id);
217 }
218
219 void
220 vnet_dev_tx_queue_free_counters (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
221 {
222   if (!txq->counter_main)
223     return;
224
225   log_debug (txq->port->dev, "free");
226   vnet_dev_counters_free (vm, txq->counter_main);
227 }