1 /* SPDX-License-Identifier: Apache-2.0
2 * Copyright (c) 2023 Cisco Systems, Inc.
5 #include "vppinfra/pool.h"
7 #include <vnet/ethernet/ethernet.h>
8 #include <vnet/dev/dev.h>
9 #include <vnet/dev/counters.h>
10 #include <vnet/dev/log.h>
11 #include <vnet/dev/api.h>
13 VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
15 .subclass_name = "api",
19 _vnet_dev_queue_size_validate (u32 size, vnet_dev_queue_config_t c)
21 if (size < c.min_size)
23 if (size > c.max_size)
25 if (c.size_is_power_of_two && count_set_bits (size) != 1)
27 if (c.multiplier && size % c.multiplier)
34 vnet_dev_api_attach (vlib_main_t *vm, vnet_dev_api_attach_args_t *args)
36 vnet_dev_main_t *dm = &vnet_dev_main;
38 vnet_dev_rv_t rv = VNET_DEV_OK;
40 vnet_dev_driver_t *driver;
41 void *bus_dev_info = 0;
44 log_debug (0, "%s driver %s flags '%U' args '%v'", args->device_id,
45 args->driver_name, format_vnet_dev_flags, &args->flags,
48 if (vnet_dev_by_id (args->device_id))
49 return VNET_DEV_ERR_ALREADY_IN_USE;
51 bus = vnet_dev_find_device_bus (vm, args->device_id);
54 log_err (dev, "unknown bus");
55 rv = VNET_DEV_ERR_INVALID_BUS;
59 bus_dev_info = vnet_dev_get_device_info (vm, args->device_id);
62 log_err (dev, "invalid or unsupported device id");
63 rv = VNET_DEV_ERR_INVALID_DEVICE_ID;
67 vec_foreach (driver, dm->drivers)
69 if (args->driver_name[0] &&
70 strcmp (args->driver_name, driver->registration->name))
72 if (driver->ops.probe &&
73 (dev_desc = driver->ops.probe (vm, bus->index, bus_dev_info)))
79 log_err (dev, "driver not available for %s", args->device_id);
80 rv = VNET_DEV_ERR_DRIVER_NOT_AVAILABLE;
84 dev = vnet_dev_alloc (vm, args->device_id, driver);
87 log_err (dev, "dev alloc failed for %s", args->device_id);
88 rv = VNET_DEV_ERR_BUG;
91 dev->description = dev_desc;
93 if ((args->flags.e & VNET_DEV_F_NO_STATS) == 0)
96 log_debug (0, "found '%v'", dev->description);
98 rv = vnet_dev_process_call_op (vm, dev, vnet_dev_init);
102 bus->ops.free_device_info (vm, bus_dev_info);
104 if (rv != VNET_DEV_OK && dev)
105 vnet_dev_process_call_op_no_rv (vm, dev, vnet_dev_free);
111 vnet_dev_api_detach (vlib_main_t *vm, vnet_dev_api_detach_args_t *args)
113 vnet_dev_t *dev = vnet_dev_by_id (args->device_id);
115 log_debug (dev, "detach");
118 return vnet_dev_process_call_op_no_rv (vm, dev, vnet_dev_detach);
120 return VNET_DEV_ERR_NOT_FOUND;
124 vnet_dev_api_reset (vlib_main_t *vm, vnet_dev_api_reset_args_t *args)
126 vnet_dev_t *dev = vnet_dev_by_id (args->device_id);
128 log_debug (dev, "detach");
131 return VNET_DEV_ERR_NOT_FOUND;
134 return VNET_DEV_ERR_NOT_SUPPORTED;
136 return vnet_dev_process_call_op (vm, dev, vnet_dev_reset);
140 vnet_dev_api_create_port_if (vlib_main_t *vm,
141 vnet_dev_api_create_port_if_args_t *args)
143 vnet_dev_t *dev = vnet_dev_by_id (args->device_id);
144 vnet_dev_port_t *port = 0;
145 u16 n_threads = vlib_get_n_threads ();
146 int default_is_intr_mode;
149 "create_port_if: device '%s' port %u intf_name '%s' num_rx_q %u "
150 "num_tx_q %u rx_q_sz %u tx_q_sz %u, flags '%U' args '%v'",
151 args->device_id, args->port_id, args->intf_name,
152 args->num_rx_queues, args->num_tx_queues, args->rx_queue_size,
153 args->tx_queue_size, format_vnet_dev_port_flags, &args->flags,
157 return VNET_DEV_ERR_NOT_FOUND;
159 foreach_vnet_dev_port (p, dev)
160 if (p->port_id == args->port_id)
167 return VNET_DEV_ERR_INVALID_DEVICE_ID;
169 if (port->interface_created)
170 return VNET_DEV_ERR_ALREADY_EXISTS;
172 default_is_intr_mode = (args->flags.e & VNET_DEV_PORT_F_INTERRUPT_MODE) != 0;
173 if (default_is_intr_mode && port->attr.caps.interrupt_mode == 0)
175 log_err (dev, "interrupt mode requested and port doesn't support it");
176 return VNET_DEV_ERR_NOT_SUPPORTED;
179 if (args->num_rx_queues)
181 if (args->num_rx_queues > port->attr.max_rx_queues)
182 return VNET_DEV_ERR_INVALID_NUM_RX_QUEUES;
183 port->intf.num_rx_queues = args->num_rx_queues;
186 port->intf.num_rx_queues = clib_min (port->attr.max_tx_queues, 1);
188 if (args->num_tx_queues)
190 if (args->num_tx_queues > port->attr.max_tx_queues)
191 return VNET_DEV_ERR_INVALID_NUM_TX_QUEUES;
192 port->intf.num_tx_queues = args->num_tx_queues;
195 port->intf.num_tx_queues = clib_min (port->attr.max_tx_queues, n_threads);
197 if (args->rx_queue_size)
199 if (!_vnet_dev_queue_size_validate (args->rx_queue_size,
200 port->rx_queue_config))
201 return VNET_DEV_ERR_INVALID_RX_QUEUE_SIZE;
202 port->intf.rxq_sz = args->rx_queue_size;
205 port->intf.rxq_sz = port->rx_queue_config.default_size;
207 if (args->tx_queue_size)
209 if (!_vnet_dev_queue_size_validate (args->tx_queue_size,
210 port->tx_queue_config))
211 return VNET_DEV_ERR_INVALID_TX_QUEUE_SIZE;
212 port->intf.txq_sz = args->tx_queue_size;
215 port->intf.txq_sz = port->tx_queue_config.default_size;
217 clib_memcpy (port->intf.name, args->intf_name, sizeof (port->intf.name));
218 port->intf.default_is_intr_mode = default_is_intr_mode;
220 return vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_create);
224 vnet_dev_api_remove_port_if (vlib_main_t *vm,
225 vnet_dev_api_remove_port_if_args_t *args)
227 vnet_dev_main_t *dm = &vnet_dev_main;
228 vnet_main_t *vnm = vnet_get_main ();
229 vnet_sw_interface_t *si;
230 vnet_hw_interface_t *hi;
231 vnet_dev_port_t *port;
233 si = vnet_get_sw_interface_or_null (vnm, args->sw_if_index);
235 return VNET_DEV_ERR_UNKNOWN_INTERFACE;
237 hi = vnet_get_hw_interface_or_null (vnm, si->hw_if_index);
239 return VNET_DEV_ERR_UNKNOWN_INTERFACE;
241 if (pool_is_free_index (dm->ports_by_dev_instance, hi->dev_instance))
242 return VNET_DEV_ERR_UNKNOWN_INTERFACE;
244 port = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
246 if (port->intf.hw_if_index != si->hw_if_index)
247 return VNET_DEV_ERR_UNKNOWN_INTERFACE;
249 return vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_remove);