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