iavf: new driver using new dev infra
[vpp.git] / src / plugins / dev_iavf / iavf.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/dev/dev.h>
7 #include <vnet/dev/pci.h>
8 #include <vnet/dev/counters.h>
9 #include <vppinfra/ring.h>
10 #include <dev_iavf/iavf.h>
11 #include <dev_iavf/virtchnl.h>
12 #include <dev_iavf/virtchnl_funcs.h>
13 #include <vnet/ethernet/ethernet.h>
14 #include <vnet/plugin/plugin.h>
15 #include <vpp/app/version.h>
16
17 VLIB_REGISTER_LOG_CLASS (iavf_log, static) = {
18   .class_name = "iavf",
19   .subclass_name = "init",
20 };
21
22 static const u32 driver_cap_flags =
23   /**/ VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
24   /**/ VIRTCHNL_VF_LARGE_NUM_QPAIRS |
25   /**/ VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF |
26   /**/ VIRTCHNL_VF_OFFLOAD_FDIR_PF |
27   /**/ VIRTCHNL_VF_OFFLOAD_L2 |
28   /**/ VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
29   /**/ VIRTCHNL_VF_OFFLOAD_RSS_PF |
30   /**/ VIRTCHNL_VF_OFFLOAD_RX_POLLING |
31   /**/ VIRTCHNL_VF_OFFLOAD_VLAN |
32   /**/ VIRTCHNL_VF_OFFLOAD_VLAN_V2 |
33   /**/ VIRTCHNL_VF_OFFLOAD_WB_ON_ITR |
34   /**/ 0;
35
36 static const virtchnl_version_info_t driver_virtchnl_version = {
37   .major = VIRTCHNL_VERSION_MAJOR,
38   .minor = VIRTCHNL_VERSION_MINOR,
39 };
40
41 #define _(f, n, s, d)                                                         \
42   { .name = #n, .desc = d, .severity = VL_COUNTER_SEVERITY_##s },
43
44 vlib_error_desc_t iavf_rx_node_counters[] = { foreach_iavf_rx_node_counter };
45 vlib_error_desc_t iavf_tx_node_counters[] = { foreach_iavf_tx_node_counter };
46 #undef _
47
48 vnet_dev_node_t iavf_rx_node = {
49   .error_counters = iavf_rx_node_counters,
50   .n_error_counters = ARRAY_LEN (iavf_rx_node_counters),
51   .format_trace = format_iavf_rx_trace,
52 };
53
54 vnet_dev_node_t iavf_tx_node = {
55   .error_counters = iavf_tx_node_counters,
56   .n_error_counters = ARRAY_LEN (iavf_tx_node_counters),
57 };
58
59 static struct
60 {
61   u16 device_id;
62   char *desc;
63 } iavf_dev_types[] = {
64   { 0x1889, "Intel(R) Adaptive Virtual Function" },
65   { 0x154c, "Intel(R) X710 Virtual Function" },
66   { 0x37cd, "Intel(R) X722 Virtual Function" },
67 };
68
69 static u8 *
70 iavf_probe (vlib_main_t *vm, vnet_dev_bus_index_t bus_index, void *dev_info)
71 {
72   vnet_dev_bus_pci_device_info_t *di = dev_info;
73
74   if (di->vendor_id != 0x8086)
75     return 0;
76
77   FOREACH_ARRAY_ELT (dt, iavf_dev_types)
78     {
79       if (dt->device_id == di->device_id)
80         return format (0, "%s", dt->desc);
81     }
82
83   return 0;
84 }
85
86 static vnet_dev_rv_t
87 iavf_reset (vlib_main_t *vm, vnet_dev_t *dev)
88 {
89   iavf_device_t *ad = vnet_dev_get_data (dev);
90   u32 n_tries = 50;
91
92   iavf_aq_init (vm, dev);
93   iavf_vc_op_reset_vf (vm, dev);
94
95   do
96     {
97       if (n_tries-- == 0)
98         return VNET_DEV_ERR_TIMEOUT;
99       vlib_process_suspend (vm, 0.02);
100     }
101   while ((iavf_reg_read (ad, VFGEN_RSTAT) & 3) != 2);
102
103   iavf_aq_init (vm, dev);
104   iavf_aq_poll_on (vm, dev);
105   return (VNET_DEV_OK);
106 }
107
108 static vnet_dev_rv_t
109 iavf_alloc (vlib_main_t *vm, vnet_dev_t *dev)
110 {
111   log_debug (dev, "alloc");
112   return iavf_aq_alloc (vm, dev);
113 }
114
115 static vnet_dev_rv_t
116 iavf_init (vlib_main_t *vm, vnet_dev_t *dev)
117 {
118   iavf_device_t *ad = vnet_dev_get_data (dev);
119   virtchnl_version_info_t ver;
120   virtchnl_vf_resource_t res;
121   vnet_dev_rv_t rv;
122
123   log_debug (dev, "init");
124
125   if ((rv = vnet_dev_pci_map_region (vm, dev, 0, &ad->bar0)))
126     return rv;
127
128   if ((rv = vnet_dev_pci_bus_master_enable (vm, dev)))
129     return rv;
130
131   if ((rv = iavf_reset (vm, dev)))
132     return rv;
133
134   if ((rv = iavf_vc_op_version (vm, dev, &driver_virtchnl_version, &ver)))
135     return rv;
136
137   if (ver.major != driver_virtchnl_version.major ||
138       ver.minor != driver_virtchnl_version.minor)
139     return VNET_DEV_ERR_UNSUPPORTED_DEVICE_VER;
140
141   if ((rv = iavf_vc_op_get_vf_resources (vm, dev, &driver_cap_flags, &res)))
142     return rv;
143
144   if (res.num_vsis != 1 || res.vsi_res[0].vsi_type != VIRTCHNL_VSI_SRIOV)
145     return VNET_DEV_ERR_UNSUPPORTED_DEVICE;
146
147   iavf_port_t iavf_port = {
148     .vf_cap_flags = res.vf_cap_flags,
149     .rss_key_size = res.rss_key_size,
150     .rss_lut_size = res.rss_lut_size,
151     .max_vectors = res.max_vectors,
152     .vsi_id = res.vsi_res[0].vsi_id,
153     .num_qp = res.vsi_res[0].num_queue_pairs,
154   };
155
156   vnet_dev_port_add_args_t port_add_args = {
157     .port = {
158       .attr = {
159         .type = VNET_DEV_PORT_TYPE_ETHERNET,
160         .max_rx_queues = res.num_queue_pairs,
161         .max_tx_queues = res.num_queue_pairs,
162         .max_supported_frame_size = res.max_mtu,
163       },
164       .ops = {
165         .init = iavf_port_init,
166         .start = iavf_port_start,
167         .stop = iavf_port_stop,
168         .config_change = iavf_port_cfg_change,
169         .format_status = format_iavf_port_status,
170       },
171       .data_size = sizeof (iavf_port_t),
172       .initial_data = &iavf_port,
173     },
174     .rx_node = &iavf_rx_node,
175     .tx_node = &iavf_tx_node,
176     .rx_queue = {
177       .config = {
178         .data_size = sizeof (iavf_rxq_t),
179         .default_size = 512,
180         .multiplier = 32,
181         .min_size = 32,
182         .max_size = 4096,
183         .size_is_power_of_two = 1,
184       },
185       .ops = {
186         .alloc = iavf_rx_queue_alloc,
187         .free = iavf_rx_queue_free,
188       },
189     },
190     .tx_queue = {
191       .config = {
192         .data_size = sizeof (iavf_txq_t),
193         .default_size = 512,
194         .multiplier = 32,
195         .min_size = 32,
196         .max_size = 4096,
197         .size_is_power_of_two = 1,
198       },
199       .ops = {
200         .alloc = iavf_tx_queue_alloc,
201         .free = iavf_tx_queue_free,
202       },
203     },
204   };
205
206   vnet_dev_set_hw_addr_eth_mac (&port_add_args.port.attr.hw_addr,
207                                 res.vsi_res[0].default_mac_addr);
208
209   log_info (dev, "MAC address is %U", format_ethernet_address,
210             res.vsi_res[0].default_mac_addr);
211
212   if (vlib_get_n_threads () <= vnet_dev_get_pci_n_msix_interrupts (dev) - 1)
213     port_add_args.port.attr.caps.interrupt_mode = 1;
214   else
215     log_notice (dev,
216                 "number of threads (%u) bigger than number of interrupt lines "
217                 "(%u), interrupt mode disabled",
218                 vlib_get_n_threads (), res.max_vectors);
219
220   if (res.vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF)
221     {
222       if (res.rss_key_size < IAVF_MAX_RSS_KEY_SIZE)
223         {
224           log_notice (
225             dev, "unsupported RSS config provided by device, RSS disabled");
226         }
227       else
228         {
229           port_add_args.port.attr.caps.rss = 1;
230           if (res.rss_lut_size > IAVF_MAX_RSS_LUT_SIZE)
231             log_notice (dev, "device supports bigger RSS LUT than driver");
232         }
233     }
234
235   return vnet_dev_port_add (vm, dev, 0, &port_add_args);
236 }
237
238 static void
239 iavf_deinit (vlib_main_t *vm, vnet_dev_t *dev)
240 {
241   log_debug (dev, "deinit");
242   iavf_aq_poll_off (vm, dev);
243   iavf_aq_deinit (vm, dev);
244   iavf_aq_free (vm, dev);
245 }
246
247 static void
248 iavf_free (vlib_main_t *vm, vnet_dev_t *dev)
249 {
250   log_debug (dev, "free");
251   iavf_aq_free (vm, dev);
252 }
253
254 VNET_DEV_REGISTER_DRIVER (avf) = {
255   .name = "iavf",
256   .bus = "pci",
257   .device_data_sz = sizeof (iavf_device_t),
258   .runtime_temp_space_sz = sizeof (iavf_rt_data_t),
259   .ops = {
260     .alloc = iavf_alloc,
261     .init = iavf_init,
262     .deinit = iavf_deinit,
263     .free = iavf_free,
264     .probe = iavf_probe,
265   },
266 };
267
268 VLIB_PLUGIN_REGISTER () = {
269   .version = VPP_BUILD_VER,
270   .description = "dev_iavf",
271 };