iavf: new driver using new dev infra
[vpp.git] / src / plugins / dev_iavf / virtchnl.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 <dev_iavf/iavf.h>
10 #include <dev_iavf/virtchnl.h>
11 #include <dev_iavf/virtchnl_funcs.h>
12 #include <vnet/ethernet/ethernet.h>
13
14 VLIB_REGISTER_LOG_CLASS (iavf_log, static) = {
15   .class_name = "iavf",
16   .subclass_name = "virtchnl",
17 };
18
19 u8 *
20 format_virtchnl_op_name (u8 *s, va_list *args)
21 {
22   virtchnl_op_t op = va_arg (*args, virtchnl_op_t);
23   char *op_names[] = {
24 #define _(a, b) [a] = #b,
25     foreach_virtchnl_op
26 #undef _
27   };
28
29   if (op >= ARRAY_LEN (op_names) || op_names[op] == 0)
30     return format (s, "UNKNOWN(%u)", op);
31
32   return format (s, "%s", op_names[op]);
33 }
34
35 u8 *
36 format_virtchnl_status (u8 *s, va_list *args)
37 {
38   virtchnl_status_t c = va_arg (*args, virtchnl_status_t);
39
40   if (0)
41     ;
42 #define _(a, b) else if (c == a) return format (s, #b);
43   foreach_virtchnl_status
44 #undef _
45     return format (s, "UNKNOWN(%d)", c);
46 }
47
48 static u8 *
49 format_virtchnl_vlan_support_caps (u8 *s, va_list *args)
50 {
51   virtchnl_vlan_support_caps_t v = va_arg (*args, u32);
52   int not_first = 0;
53
54   char *strs[32] = {
55 #define _(a, b, c) [a] = c,
56     foreach_virtchnl_vlan_support_bit
57 #undef _
58   };
59
60   if (v == VIRTCHNL_VLAN_UNSUPPORTED)
61     return format (s, "unsupported");
62
63   for (int i = 0; i < 32; i++)
64     {
65       if ((v & (1 << i)) == 0)
66         continue;
67       if (not_first)
68         s = format (s, " ");
69       if (strs[i])
70         s = format (s, "%s", strs[i]);
71       else
72         s = format (s, "unknown(%u)", i);
73       not_first = 1;
74     }
75   return s;
76 }
77
78 static u8 *
79 format_virtchnl_op_req (u8 *s, va_list *args)
80 {
81   virtchnl_op_t op = va_arg (*args, virtchnl_op_t);
82   void *p = va_arg (*args, void *);
83   u32 indent = format_get_indent (s);
84
85   if (p == 0)
86     return format (s, "no data");
87
88   switch (op)
89     {
90     case VIRTCHNL_OP_VERSION:
91       {
92         virtchnl_version_info_t *r = p;
93         s = format (s, "version: %u.%u", r->major, r->minor);
94       }
95       break;
96     case VIRTCHNL_OP_GET_VF_RESOURCES:
97       {
98         u32 *r = p;
99         s = format (s, "%U", format_iavf_vf_cap_flags, *r);
100       }
101       break;
102     case VIRTCHNL_OP_ENABLE_QUEUES:
103     case VIRTCHNL_OP_DISABLE_QUEUES:
104     case VIRTCHNL_OP_GET_STATS:
105       {
106         virtchnl_queue_select_t *r = p;
107         s = format (s, "vsi %u rx 0x%x tx 0x%x", r->vsi_id, r->rx_queues,
108                     r->tx_queues);
109       }
110       break;
111     case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
112       {
113         virtchnl_vsi_queue_config_info_t *r = p;
114         s = format (s, "vsi %u num_qp %u", r->vsi_id, r->num_queue_pairs);
115         for (int i = 0; i < r->num_queue_pairs; i++)
116           {
117             virtchnl_rxq_info_t *ri = &r->qpair[i].rxq;
118             virtchnl_txq_info_t *ti = &r->qpair[i].txq;
119
120             s = format (s, "\n%U qpair %u", format_white_space, indent + 2, i);
121             s = format (s,
122                         "\n%U rx vsi %u queue %u dma_ring_addr 0x%lx "
123                         "ring_len %u data_sz %u max_pkt_sz %u",
124                         format_white_space, indent + 4, ri->vsi_id,
125                         ri->queue_id, ri->dma_ring_addr, ri->ring_len,
126                         ri->databuffer_size, ri->max_pkt_size);
127             s = format (
128               s, "\n%U tx vsi %u queue %u dma_ring_addr 0x%lx ring_len %u",
129               format_white_space, indent + 4, ti->vsi_id, ti->queue_id,
130               ti->dma_ring_addr, ti->ring_len);
131           }
132       }
133       break;
134     case VIRTCHNL_OP_CONFIG_IRQ_MAP:
135       {
136         virtchnl_irq_map_info_t *r = p;
137         s = format (s, "num_vectors %u", r->num_vectors);
138         for (int i = 0; i < r->num_vectors; i++)
139           {
140             virtchnl_vector_map_t *vecmap = r->vecmap + i;
141             s = format (s,
142                         "\n%Uvsi %u vector_id %u rxq_map 0x%04x txq_map "
143                         "0x%04x rxitr_idx %u txitr_idx %u",
144                         format_white_space, indent + 2, vecmap->vsi_id,
145                         vecmap->vector_id, vecmap->rxq_map, vecmap->txq_map,
146                         vecmap->rxitr_idx, vecmap->txitr_idx);
147           }
148       }
149       break;
150     case VIRTCHNL_OP_CONFIG_RSS_LUT:
151       {
152         virtchnl_rss_lut_t *r = p;
153         s = format (s, "vsi %u entries %u lut", r->vsi_id, r->lut_entries);
154         for (int i = 0; i < r->lut_entries; i++)
155           s = format (s, " %u", r->lut[i]);
156       }
157       break;
158     case VIRTCHNL_OP_CONFIG_RSS_KEY:
159       {
160         virtchnl_rss_key_t *r = p;
161         s = format (s, "vsi %u len %u key ", r->vsi_id, r->key_len);
162         for (int i = 0; i < r->key_len; i++)
163           s = format (s, "%02x", r->key[i]);
164       }
165       break;
166     case VIRTCHNL_OP_ADD_ETH_ADDR:
167     case VIRTCHNL_OP_DEL_ETH_ADDR:
168       {
169         virtchnl_ether_addr_list_t *r = p;
170         s = format (s, "vsi %u num_elements %u elts: ", r->vsi_id,
171                     r->num_elements);
172         for (int i = 0; i < r->num_elements; i++)
173           s = format (s, "%s%U%s%s", i ? ", " : "", format_ethernet_address,
174                       r->list[i].addr, r->list[i].primary ? " primary" : "",
175                       r->list[i].extra ? " extra" : "");
176       }
177       break;
178     case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
179       {
180         virtchnl_promisc_info_t *r = p;
181         s = format (
182           s, "promisc_info: vsi %u flags 0x%x (unicast %s multicast %s)",
183           r->vsi_id, r->flags,
184           r->flags & FLAG_VF_UNICAST_PROMISC ? "on" : "off",
185           r->flags & FLAG_VF_MULTICAST_PROMISC ? "on" : "off");
186       }
187       break;
188     case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2:
189       {
190         virtchnl_vlan_setting_t *r = p;
191         s = format (s,
192                     "vport %u outer_ethertype_setting 0x%x [%U] "
193                     "inner_ethertype_setting 0x%x [%U]",
194                     r->vport_id, r->outer_ethertype_setting,
195                     format_virtchnl_vlan_support_caps,
196                     r->outer_ethertype_setting, r->inner_ethertype_setting,
197                     format_virtchnl_vlan_support_caps,
198                     r->inner_ethertype_setting);
199       }
200       break;
201     default:
202       s = format (s, "unknown op 0x%04x", op);
203       break;
204     };
205   return s;
206 }
207 static u8 *
208 format_virtchnl_op_resp (u8 *s, va_list *args)
209 {
210   virtchnl_op_t op = va_arg (*args, virtchnl_op_t);
211   void *p = va_arg (*args, void *);
212   u32 indent = format_get_indent (s);
213
214   if (p == 0)
215     return format (s, "no data");
216
217   switch (op)
218     {
219     case VIRTCHNL_OP_VERSION:
220       {
221         virtchnl_version_info_t *r = p;
222         s = format (s, "version %u.%u", r->major, r->minor);
223       }
224       break;
225     case VIRTCHNL_OP_GET_VF_RESOURCES:
226       {
227         virtchnl_vf_resource_t *r = p;
228         s =
229           format (s,
230                   "vf_resource: num_vsis %u num_queue_pairs %u "
231                   "max_vectors %u max_mtu %u rss_key_size %u rss_lut_size %u",
232                   r->num_vsis, r->num_queue_pairs, r->max_vectors, r->max_mtu,
233                   r->rss_key_size, r->rss_lut_size);
234         s = format (s, "\n%Uvf_cap_flags 0x%x (%U)", format_white_space,
235                     indent + 2, r->vf_cap_flags, format_iavf_vf_cap_flags,
236                     r->vf_cap_flags);
237         for (int i = 0; i < r->num_vsis; i++)
238           s = format (s,
239                       "\n%Uvsi_resource[%u]: vsi %u num_qp %u vsi_type %u "
240                       "qset_handle %u default_mac_addr %U",
241                       format_white_space, indent + 2, i, r->vsi_res[i].vsi_id,
242                       r->vsi_res[i].num_queue_pairs, r->vsi_res[i].vsi_type,
243                       r->vsi_res[i].qset_handle, format_ethernet_address,
244                       r->vsi_res[i].default_mac_addr);
245       }
246       break;
247     case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS:
248       {
249         virtchnl_vlan_caps_t *r = p;
250         s = format (s, "filtering: ethertype_init 0x%x max_filters %u",
251                     r->filtering.ethertype_init, r->filtering.max_filters);
252         s = format (s, "\n%U outer [%U] inner [%U]", format_white_space,
253                     indent, format_virtchnl_vlan_support_caps,
254                     r->filtering.filtering_support.outer,
255                     format_virtchnl_vlan_support_caps,
256                     r->filtering.filtering_support.inner);
257         s = format (s, "\n%Uoffloads: ethertype_init 0x%x ethertype_match %u",
258                     format_white_space, indent, r->offloads.ethertype_init,
259                     r->offloads.ethertype_match);
260         s = format (s, "\n%U stripping outer [%U] stripping inner [%U]",
261                     format_white_space, indent,
262                     format_virtchnl_vlan_support_caps,
263                     r->offloads.stripping_support.outer,
264                     format_virtchnl_vlan_support_caps,
265                     r->offloads.stripping_support.inner);
266         s = format (s, "\n%U insertion outer [%U] inserion inner [%U]",
267                     format_white_space, indent,
268                     format_virtchnl_vlan_support_caps,
269                     r->offloads.insertion_support.outer,
270                     format_virtchnl_vlan_support_caps,
271                     r->offloads.insertion_support.inner);
272       }
273       break;
274     case VIRTCHNL_OP_GET_STATS:
275       {
276         virtchnl_eth_stats_t *r = p;
277         s = format (s,
278                     "rx: bytes %lu, unicast %lu, multicast %lu, broadcast "
279                     "%lu, discards %lu unknown_protocol %lu",
280                     r->rx_bytes, r->rx_unicast, r->rx_multicast,
281                     r->rx_broadcast, r->rx_discards, r->rx_unknown_protocol);
282         s = format (s, "\n%U", format_white_space, indent);
283         s = format (s,
284                     "tx: bytes %lu, unicast %lu, multicast %lu, broadcast "
285                     "%lu, discards %lu errors %lu",
286                     r->tx_bytes, r->tx_unicast, r->tx_multicast,
287                     r->tx_broadcast, r->tx_discards, r->tx_errors);
288       }
289       break;
290     default:
291       s = format (s, "unknown op 0x%04x", op);
292       break;
293     };
294   return s;
295 }
296
297 vnet_dev_rv_t
298 iavf_virtchnl_req (vlib_main_t *vm, vnet_dev_t *dev, iavf_virtchnl_req_t *r)
299 {
300   iavf_device_t *ad = vnet_dev_get_data (dev);
301   vnet_dev_rv_t rv;
302   iavf_aq_desc_t *d;
303   u8 *b;
304
305   log_debug (dev, "%U req:\n  %U", format_virtchnl_op_name, r->op,
306              format_virtchnl_op_req, r->op, r->req);
307
308   iavf_aq_desc_t txd = {
309     .opcode = IIAVF_AQ_DESC_OP_SEND_TO_PF,
310     .v_opcode = r->op,
311     .flags = { .si = 1 },
312   };
313
314   rv = iavf_aq_atq_enq (vm, dev, &txd, r->req, r->req_sz, 0.5);
315
316   if (rv != VNET_DEV_OK)
317     return rv;
318
319   if (r->no_reply)
320     return VNET_DEV_OK;
321
322 retry:
323   if (!iavf_aq_arq_next_acq (vm, dev, &d, &b, 1.0))
324     {
325       log_err (ad, "timeout waiting for virtchnl response");
326       return VNET_DEV_ERR_TIMEOUT;
327     }
328
329   if (d->v_opcode == VIRTCHNL_OP_EVENT)
330     {
331       if ((d->datalen != sizeof (virtchnl_pf_event_t)) ||
332           ((d->flags.buf) == 0))
333         {
334           log_err (dev, "event message error");
335           return VNET_DEV_ERR_BUG;
336         }
337
338       vec_add1 (ad->events, *(virtchnl_pf_event_t *) b);
339       iavf_aq_arq_next_rel (vm, dev);
340       goto retry;
341     }
342
343   if (d->v_opcode != r->op)
344     {
345       log_err (dev,
346                "unexpected response received [v_opcode = %u, expected %u, "
347                "v_retval %d]",
348                d->v_opcode, r->op, d->v_retval);
349       rv = VNET_DEV_ERR_BUG;
350       goto done;
351     }
352
353   r->status = d->v_retval;
354
355   if (d->v_retval)
356     {
357       log_err (dev, "error [v_opcode = %u, v_retval %d]", d->v_opcode,
358                d->v_retval);
359       rv = VNET_DEV_ERR_BUG;
360       goto done;
361     }
362
363   if (r->resp_sz && d->flags.buf)
364     clib_memcpy_fast (r->resp, b, r->resp_sz);
365
366 done:
367   iavf_aq_arq_next_rel (vm, dev);
368   if (rv == VNET_DEV_OK)
369     log_debug (dev, "%U resp:\n  %U", format_virtchnl_op_name, r->op,
370                format_virtchnl_op_resp, r->op, r->resp);
371   return rv;
372 }