dev: new device driver infra
[vpp.git] / src / vnet / dev / dev.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2023 Cisco Systems, Inc.
3  */
4
5 #include "vppinfra/pool.h"
6 #include <vnet/vnet.h>
7 #include <vnet/ethernet/ethernet.h>
8 #include <vnet/dev/dev.h>
9 #include <vnet/dev/log.h>
10 #include <vnet/dev/counters.h>
11
12 VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
13   .class_name = "dev",
14 };
15
16 vnet_dev_main_t vnet_dev_main = { .next_rx_queue_thread = 1 };
17
18 vnet_dev_bus_t *
19 vnet_dev_find_device_bus (vlib_main_t *vm, vnet_dev_device_id_t id)
20 {
21   vnet_dev_main_t *dm = &vnet_dev_main;
22   vnet_dev_bus_t *bus;
23
24   pool_foreach (bus, dm->buses)
25     {
26       int n = strlen (bus->registration->name);
27       int l = strlen (id);
28       int dl = strlen (VNET_DEV_DEVICE_ID_PREFIX_DELIMITER);
29
30       if (l <= n + dl)
31         continue;
32
33       if (strncmp (bus->registration->name, id, n))
34         continue;
35
36       if (strncmp (VNET_DEV_DEVICE_ID_PREFIX_DELIMITER, id + n, dl))
37         continue;
38
39       return bus;
40     }
41
42   return 0;
43 }
44
45 void *
46 vnet_dev_get_device_info (vlib_main_t *vm, vnet_dev_device_id_t id)
47 {
48   vnet_dev_bus_t *bus;
49
50   bus = vnet_dev_find_device_bus (vm, id);
51   if (bus == 0)
52     return 0;
53
54   return bus->ops.get_device_info (vm, id);
55 }
56
57 vnet_dev_t *
58 vnet_dev_alloc (vlib_main_t *vm, vnet_dev_device_id_t id,
59                 vnet_dev_driver_t *driver)
60 {
61   vnet_dev_main_t *dm = &vnet_dev_main;
62   vnet_dev_t *dev = 0, **devp = 0;
63
64   dev = vnet_dev_alloc_with_data (sizeof (vnet_dev_t),
65                                   driver->registration->device_data_sz);
66
67   pool_get (dm->devices, devp);
68   devp[0] = dev;
69   dev->index = devp - dm->devices;
70   dev->driver_index = driver->index;
71   dev->ops = driver->registration->ops;
72   dev->bus_index = driver->bus_index;
73   clib_memcpy (dev->device_id, id, sizeof (dev->device_id));
74   hash_set (dm->device_index_by_id, dev->device_id, dev->index);
75
76   if ((vnet_dev_process_create (vm, dev)) == VNET_DEV_OK)
77     return dev;
78
79   vnet_dev_free (vm, dev);
80   return 0;
81 }
82
83 vnet_dev_rv_t
84 vnet_dev_init (vlib_main_t *vm, vnet_dev_t *dev)
85 {
86   vnet_dev_main_t *dm = &vnet_dev_main;
87   vnet_dev_bus_t *bus = pool_elt_at_index (dm->buses, dev->bus_index);
88   vnet_dev_rv_t rv;
89
90   vnet_dev_validate (vm, dev);
91
92   if ((rv = bus->ops.device_open (vm, dev)) != VNET_DEV_OK)
93     return rv;
94
95   if ((rv = dev->ops.alloc (vm, dev)) != VNET_DEV_OK)
96     {
97       log_err (dev, "device init failed [rv %d]", rv);
98       if (dev->ops.deinit)
99         dev->ops.deinit (vm, dev);
100       if (dev->ops.free)
101         dev->ops.free (vm, dev);
102       return rv;
103     }
104
105   if ((rv = dev->ops.init (vm, dev)) != VNET_DEV_OK)
106     {
107       log_err (dev, "device init failed [rv %d]", rv);
108       if (dev->ops.deinit)
109         dev->ops.deinit (vm, dev);
110       if (dev->ops.free)
111         dev->ops.free (vm, dev);
112       return rv;
113     }
114
115   dev->initialized = 1;
116   dev->not_first_init = 1;
117   return VNET_DEV_OK;
118 }
119
120 void
121 vnet_dev_deinit (vlib_main_t *vm, vnet_dev_t *dev)
122 {
123   ASSERT (dev->initialized == 1);
124   vnet_dev_bus_t *bus;
125
126   vnet_dev_validate (vm, dev);
127
128   foreach_vnet_dev_port (p, dev)
129     ASSERT (p->interface_created == 0);
130
131   if (dev->ops.deinit)
132     dev->ops.deinit (vm, dev);
133
134   bus = vnet_dev_get_bus (dev);
135   if (bus->ops.device_close)
136     bus->ops.device_close (vm, dev);
137
138   vnet_dev_process_quit (vm, dev);
139
140   dev->initialized = 0;
141 }
142
143 void
144 vnet_dev_free (vlib_main_t *vm, vnet_dev_t *dev)
145 {
146   vnet_dev_main_t *dm = &vnet_dev_main;
147
148   vnet_dev_validate (vm, dev);
149
150   ASSERT (dev->initialized == 0);
151
152   foreach_vnet_dev_port (p, dev)
153     vnet_dev_port_free (vm, p);
154
155   vec_free (dev->description);
156   pool_free (dev->ports);
157   pool_free (dev->periodic_ops);
158   hash_unset (dm->device_index_by_id, dev->device_id);
159   pool_put_index (dm->devices, dev->index);
160 }
161
162 vnet_dev_rv_t
163 vnet_dev_reset (vlib_main_t *vm, vnet_dev_t *dev)
164 {
165   vnet_dev_rv_t rv;
166
167   ASSERT (dev->initialized == 1);
168   vnet_dev_validate (vm, dev);
169
170   if (dev->ops.reset == 0)
171     return VNET_DEV_ERR_NOT_SUPPORTED;
172
173   if ((rv = dev->ops.reset (vm, dev)) != VNET_DEV_OK)
174     {
175       log_err (dev, "device reset failed [rv %d]", rv);
176       return rv;
177     }
178
179   return VNET_DEV_OK;
180 }
181
182 void
183 vnet_dev_detach (vlib_main_t *vm, vnet_dev_t *dev)
184 {
185   foreach_vnet_dev_port (p, dev)
186     if (p->interface_created)
187       vnet_dev_port_if_remove (vm, p);
188   vnet_dev_deinit (vm, dev);
189   vnet_dev_free (vm, dev);
190 }
191
192 vnet_dev_rv_t
193 vnet_dev_dma_mem_alloc (vlib_main_t *vm, vnet_dev_t *dev, u32 size, u32 align,
194                         void **pp)
195 {
196   vnet_dev_main_t *dm = &vnet_dev_main;
197   vnet_dev_bus_t *bus = pool_elt_at_index (dm->buses, dev->bus_index);
198   vnet_dev_rv_t rv;
199
200   vnet_dev_validate (vm, dev);
201
202   if (!bus->ops.dma_mem_alloc_fn)
203     return VNET_DEV_ERR_NOT_SUPPORTED;
204
205   rv = bus->ops.dma_mem_alloc_fn (vm, dev, size, align, pp);
206   if (rv == VNET_DEV_OK)
207     log_debug (dev, "%u bytes va %p dma-addr 0x%lx numa %u align %u", size,
208                *pp, vnet_dev_get_dma_addr (vm, dev, *pp), dev->numa_node,
209                align);
210   return rv;
211 }
212
213 void
214 vnet_dev_dma_mem_free (vlib_main_t *vm, vnet_dev_t *dev, void *p)
215 {
216   vnet_dev_main_t *dm = &vnet_dev_main;
217   vnet_dev_bus_t *bus = pool_elt_at_index (dm->buses, dev->bus_index);
218
219   vnet_dev_validate (vm, dev);
220
221   if (p == 0 || !bus->ops.dma_mem_free_fn)
222     return;
223
224   return bus->ops.dma_mem_free_fn (vm, dev, p);
225 }
226
227 clib_error_t *
228 vnet_dev_admin_up_down_fn (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
229 {
230   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
231   vlib_main_t *vm = vlib_get_main ();
232   vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
233   vnet_dev_rv_t rv = VNET_DEV_OK;
234   u32 is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
235
236   if (is_up && p->started == 0)
237     rv = vnet_dev_process_call_port_op (vm, p, vnet_dev_port_start);
238   else if (!is_up && p->started)
239     rv = vnet_dev_process_call_port_op_no_rv (vm, p, vnet_dev_port_stop);
240
241   if (rv != VNET_DEV_OK)
242     return clib_error_return (0, "failed to change port admin state: %U",
243                               format_vnet_dev_rv, rv);
244
245   return 0;
246 }
247
248 static void
249 vnet_dev_feature_update_cb (u32 sw_if_index, u8 arc_index, u8 is_enable,
250                             void *cb)
251 {
252   vlib_main_t *vm = vlib_get_main ();
253   vnet_main_t *vnm = vnet_get_main ();
254   vnet_feature_main_t *fm = &feature_main;
255   vnet_feature_config_main_t *cm;
256   vnet_dev_main_t *vdm = &vnet_dev_main;
257   vnet_dev_port_t *port;
258   vnet_hw_interface_t *hw;
259   u32 current_config_index = ~0;
260   u32 next_index = ~0;
261   int update_runtime = 0;
262
263   if (arc_index != vdm->eth_port_rx_feature_arc_index)
264     return;
265
266   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
267   port = vnet_dev_get_port_from_dev_instance (hw->dev_instance);
268
269   if (port == 0 || port->intf.sw_if_index != sw_if_index)
270     return;
271
272   if (vnet_have_features (arc_index, sw_if_index))
273     {
274       cm = &fm->feature_config_mains[arc_index];
275       current_config_index =
276         vec_elt (cm->config_index_by_sw_if_index, sw_if_index);
277       vnet_get_config_data (&cm->config_main, &current_config_index,
278                             &next_index, 0);
279       if (port->intf.feature_arc == 0 ||
280           port->intf.rx_next_index != next_index ||
281           port->intf.current_config_index != current_config_index)
282         {
283           port->intf.current_config_index = current_config_index;
284           port->intf.rx_next_index = next_index;
285           port->intf.feature_arc_index = arc_index;
286           port->intf.feature_arc = 1;
287           update_runtime = 1;
288         }
289     }
290   else
291     {
292       if (port->intf.feature_arc)
293         {
294           port->intf.current_config_index = 0;
295           port->intf.rx_next_index =
296             port->intf.redirect_to_node ?
297                     port->intf.redirect_to_node_next_index :
298                     vnet_dev_default_next_index_by_port_type[port->attr.type];
299           port->intf.feature_arc_index = 0;
300           port->intf.feature_arc = 0;
301           update_runtime = 1;
302         }
303     }
304
305   if (update_runtime)
306     {
307       foreach_vnet_dev_port_rx_queue (rxq, port)
308         vnet_dev_rx_queue_rt_request (
309           vm, rxq,
310           (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1,
311                                         .update_feature_arc = 1 });
312       log_debug (port->dev, "runtime update requested due to chgange in "
313                             "feature arc configuration");
314     }
315 }
316
317 static int
318 sort_driver_registrations (void *a0, void *a1)
319 {
320   vnet_dev_driver_registration_t **r0 = a0;
321   vnet_dev_driver_registration_t **r1 = a1;
322
323   if (r0[0]->priority > r1[0]->priority)
324     return -1;
325   else if (r0[0]->priority < r1[0]->priority)
326     return 1;
327
328   return 0;
329 }
330
331 static clib_error_t *
332 vnet_dev_main_init (vlib_main_t *vm)
333 {
334   vnet_dev_main_t *dm = &vnet_dev_main;
335   vnet_dev_driver_registration_t **drv = 0;
336   u32 temp_space_sz = 0;
337
338   dm->device_index_by_id = hash_create_string (0, sizeof (uword));
339
340   for (vnet_dev_bus_registration_t *r = dm->bus_registrations; r;
341        r = r->next_registration)
342     {
343       vnet_dev_bus_t *bus;
344       pool_get_zero (dm->buses, bus);
345       bus->registration = r;
346       bus->index = bus - dm->buses;
347       bus->ops = r->ops;
348       if (!r->device_data_size ||
349           r->device_data_size > STRUCT_SIZE_OF (vnet_dev_t, bus_data))
350         return clib_error_return (
351           0, "bus device data for bus '%s' is too big not specified", r->name);
352
353       log_debug (0, "bus '%s' registered", r->name);
354     }
355
356   for (vnet_dev_driver_registration_t *r = dm->driver_registrations; r;
357        r = r->next_registration)
358     vec_add1 (drv, r);
359
360   vec_sort_with_function (drv, sort_driver_registrations);
361
362   vec_foreach_pointer (r, drv)
363     {
364       vnet_dev_driver_t *driver;
365       vnet_dev_bus_t *bus;
366       vnet_device_class_t *dev_class;
367       int bus_index = -1;
368
369       pool_foreach (bus, dm->buses)
370         {
371           if (strcmp (bus->registration->name, r->bus) == 0)
372             {
373               bus_index = bus->index;
374               break;
375             }
376         }
377
378       if (bus_index < 0)
379         return clib_error_return (0, "unknown bus '%s'", r->bus);
380
381       pool_get_zero (dm->drivers, driver);
382       driver->registration = r;
383       driver->index = driver - dm->drivers;
384       driver->bus_index = bus_index;
385       driver->ops = r->ops;
386       dev_class = clib_mem_alloc (sizeof (vnet_device_class_t));
387       *dev_class = (vnet_device_class_t){
388         .name = r->name,
389         .format_device_name = format_vnet_dev_interface_name,
390         .format_device = format_vnet_dev_interface_info,
391         .admin_up_down_function = vnet_dev_admin_up_down_fn,
392         .rx_redirect_to_node = vnet_dev_set_interface_next_node,
393         .clear_counters = vnet_dev_clear_hw_interface_counters,
394         .rx_mode_change_function = vnet_dev_rx_mode_change_fn,
395         .mac_addr_change_function = vnet_dev_port_mac_change,
396         .mac_addr_add_del_function = vnet_dev_add_del_mac_address,
397         .flow_ops_function = vnet_dev_flow_ops_fn,
398         .set_rss_queues_function = vnet_dev_interface_set_rss_queues,
399       };
400       driver->dev_class_index = vnet_register_device_class (vm, dev_class);
401       log_debug (0, "driver '%s' registered on bus '%s'", r->name,
402                  bus->registration->name);
403
404       if (temp_space_sz < r->runtime_temp_space_sz)
405         temp_space_sz = r->runtime_temp_space_sz;
406     }
407
408   if (dm->startup_config)
409     log_debug (0, "startup config: %v", dm->startup_config);
410
411   vec_free (drv);
412
413   if (temp_space_sz > 0)
414     {
415       const u32 align = CLIB_CACHE_LINE_BYTES;
416       u32 sz = round_pow2 (temp_space_sz, align);
417       dm->log2_runtime_temp_space_sz =
418         get_lowest_set_bit_index (max_pow2 (sz));
419       sz = 1 << dm->log2_runtime_temp_space_sz;
420       sz *= vlib_get_n_threads ();
421       dm->runtime_temp_spaces = clib_mem_alloc_aligned (sz, align);
422       clib_memset (dm->runtime_temp_spaces, 0, sz);
423       log_debug (0,
424                  "requested %u bytes for runtime temp storage, allocated %u "
425                  "per thread (total %u)",
426                  temp_space_sz, 1 << dm->log2_runtime_temp_space_sz, sz);
427     }
428
429   vnet_feature_register (vnet_dev_feature_update_cb, 0);
430
431   return 0;
432 }
433
434 VLIB_INIT_FUNCTION (vnet_dev_main_init);
435
436 clib_error_t *
437 vnet_dev_num_workers_change (vlib_main_t *vm)
438 {
439   vnet_dev_main_t *dm = &vnet_dev_main;
440
441   if (dm->log2_runtime_temp_space_sz > 0)
442     {
443       const u32 align = CLIB_CACHE_LINE_BYTES;
444       uword sz =
445         (1ULL << dm->log2_runtime_temp_space_sz) * vlib_get_n_threads ();
446       if (dm->runtime_temp_spaces)
447         clib_mem_free (dm->runtime_temp_spaces);
448       dm->runtime_temp_spaces = clib_mem_alloc_aligned (sz, align);
449       clib_memset (dm->runtime_temp_spaces, 0, sz);
450       log_debug (0, "runtime temp storage resized to %u", sz);
451     }
452
453   return 0;
454 }
455
456 VLIB_NUM_WORKERS_CHANGE_FN (vnet_dev_num_workers_change);