ebbee31b5c5c2c7ab78dbdda02d90ecb0c5786ba
[dpdk.git] / drivers / net / avf / avf_vchnl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <errno.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <stdarg.h>
11 #include <inttypes.h>
12 #include <rte_byteorder.h>
13 #include <rte_common.h>
14
15 #include <rte_debug.h>
16 #include <rte_atomic.h>
17 #include <rte_eal.h>
18 #include <rte_ether.h>
19 #include <rte_ethdev.h>
20 #include <rte_dev.h>
21
22 #include "avf_log.h"
23 #include "base/avf_prototype.h"
24 #include "base/avf_adminq_cmd.h"
25 #include "base/avf_type.h"
26
27 #include "avf.h"
28
29 #define MAX_TRY_TIMES 200
30 #define ASQ_DELAY_MS  10
31
32 /* Read data in admin queue to get msg from pf driver */
33 static enum avf_status_code
34 avf_read_msg_from_pf(struct avf_adapter *adapter, uint16_t buf_len,
35                      uint8_t *buf)
36 {
37         struct avf_hw *hw = AVF_DEV_PRIVATE_TO_HW(adapter);
38         struct avf_info *vf = AVF_DEV_PRIVATE_TO_VF(adapter);
39         struct avf_arq_event_info event;
40         enum virtchnl_ops opcode;
41         int ret;
42
43         event.buf_len = buf_len;
44         event.msg_buf = buf;
45         ret = avf_clean_arq_element(hw, &event, NULL);
46         /* Can't read any msg from adminQ */
47         if (ret) {
48                 PMD_DRV_LOG(DEBUG, "Can't read msg from AQ");
49                 return ret;
50         }
51
52         opcode = (enum virtchnl_ops)rte_le_to_cpu_32(event.desc.cookie_high);
53         vf->cmd_retval = (enum virtchnl_status_code)rte_le_to_cpu_32(
54                         event.desc.cookie_low);
55
56         PMD_DRV_LOG(DEBUG, "AQ from pf carries opcode %u, retval %d",
57                     opcode, vf->cmd_retval);
58
59         if (opcode != vf->pend_cmd)
60                 PMD_DRV_LOG(WARNING, "command mismatch, expect %u, get %u",
61                             vf->pend_cmd, opcode);
62
63         return AVF_SUCCESS;
64 }
65
66 static int
67 avf_execute_vf_cmd(struct avf_adapter *adapter, struct avf_cmd_info *args)
68 {
69         struct avf_hw *hw = AVF_DEV_PRIVATE_TO_HW(adapter);
70         struct avf_info *vf = AVF_DEV_PRIVATE_TO_VF(adapter);
71         struct avf_arq_event_info event_info;
72         enum avf_status_code ret;
73         int err = 0;
74         int i = 0;
75
76         if (_atomic_set_cmd(vf, args->ops))
77                 return -1;
78
79         ret = avf_aq_send_msg_to_pf(hw, args->ops, AVF_SUCCESS,
80                                     args->in_args, args->in_args_size, NULL);
81         if (ret) {
82                 PMD_DRV_LOG(ERR, "fail to send cmd %d", args->ops);
83                 _clear_cmd(vf);
84                 return err;
85         }
86
87         switch (args->ops) {
88         case VIRTCHNL_OP_RESET_VF:
89                 /*no need to wait for response */
90                 _clear_cmd(vf);
91                 break;
92         case VIRTCHNL_OP_VERSION:
93         case VIRTCHNL_OP_GET_VF_RESOURCES:
94                 /* for init virtchnl ops, need to poll the response */
95                 do {
96                         ret = avf_read_msg_from_pf(adapter, args->out_size,
97                                                    args->out_buffer);
98                         if (ret == AVF_SUCCESS)
99                                 break;
100                         rte_delay_ms(ASQ_DELAY_MS);
101                 } while (i++ < MAX_TRY_TIMES);
102                 if (i >= MAX_TRY_TIMES ||
103                     vf->cmd_retval != VIRTCHNL_STATUS_SUCCESS) {
104                         err = -1;
105                         PMD_DRV_LOG(ERR, "No response or return failure (%d)"
106                                     " for cmd %d", vf->cmd_retval, args->ops);
107                 }
108                 _clear_cmd(vf);
109                 break;
110
111         default:
112                 /* For other virtchnl ops in running time,
113                  * wait for the cmd done flag.
114                  */
115                 do {
116                         if (vf->pend_cmd == VIRTCHNL_OP_UNKNOWN)
117                                 break;
118                         rte_delay_ms(ASQ_DELAY_MS);
119                         /* If don't read msg or read sys event, continue */
120                 } while (i++ < MAX_TRY_TIMES);
121                 /* If there's no response is received, clear command */
122                 if (i >= MAX_TRY_TIMES  ||
123                     vf->cmd_retval != VIRTCHNL_STATUS_SUCCESS) {
124                         err = -1;
125                         PMD_DRV_LOG(ERR, "No response or return failure (%d)"
126                                     " for cmd %d", vf->cmd_retval, args->ops);
127                         _clear_cmd(vf);
128                 }
129                 break;
130         }
131
132         return err;
133 }
134
135 void
136 avf_handle_virtchnl_msg(struct rte_eth_dev *dev)
137 {
138         struct avf_hw *hw = AVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
139         struct avf_info *vf = AVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
140         struct avf_arq_event_info info;
141         uint16_t pending, aq_opc;
142         enum virtchnl_ops msg_opc;
143         enum avf_status_code msg_ret;
144         int ret;
145
146         info.buf_len = AVF_AQ_BUF_SZ;
147         if (!vf->aq_resp) {
148                 PMD_DRV_LOG(ERR, "Buffer for adminq resp should not be NULL");
149                 return;
150         }
151         info.msg_buf = vf->aq_resp;
152
153         pending = 1;
154         while (pending) {
155                 ret = avf_clean_arq_element(hw, &info, &pending);
156
157                 if (ret != AVF_SUCCESS) {
158                         PMD_DRV_LOG(INFO, "Failed to read msg from AdminQ,"
159                                     "ret: %d", ret);
160                         break;
161                 }
162                 aq_opc = rte_le_to_cpu_16(info.desc.opcode);
163                 /* For the message sent from pf to vf, opcode is stored in
164                  * cookie_high of struct avf_aq_desc, while return error code
165                  * are stored in cookie_low, Which is done by PF driver.
166                  */
167                 msg_opc = (enum virtchnl_ops)rte_le_to_cpu_32(
168                                                   info.desc.cookie_high);
169                 msg_ret = (enum avf_status_code)rte_le_to_cpu_32(
170                                                   info.desc.cookie_low);
171                 switch (aq_opc) {
172                 case avf_aqc_opc_send_msg_to_vf:
173                         if (msg_opc == VIRTCHNL_OP_EVENT) {
174                                 /* TODO */
175                         } else {
176                                 /* read message and it's expected one */
177                                 if (msg_opc == vf->pend_cmd) {
178                                         vf->cmd_retval = msg_ret;
179                                         /* prevent compiler reordering */
180                                         rte_compiler_barrier();
181                                         _clear_cmd(vf);
182                                 } else
183                                         PMD_DRV_LOG(ERR, "command mismatch,"
184                                                     "expect %u, get %u",
185                                                     vf->pend_cmd, msg_opc);
186                                 PMD_DRV_LOG(DEBUG,
187                                             "adminq response is received,"
188                                             " opcode = %d", msg_opc);
189                         }
190                         break;
191                 default:
192                         PMD_DRV_LOG(ERR, "Request %u is not supported yet",
193                                     aq_opc);
194                         break;
195                 }
196         }
197 }
198
199 #define VIRTCHNL_VERSION_MAJOR_START 1
200 #define VIRTCHNL_VERSION_MINOR_START 1
201
202 /* Check API version with sync wait until version read from admin queue */
203 int
204 avf_check_api_version(struct avf_adapter *adapter)
205 {
206         struct avf_info *vf = AVF_DEV_PRIVATE_TO_VF(adapter);
207         struct virtchnl_version_info version, *pver;
208         struct avf_cmd_info args;
209         int err;
210
211         version.major = VIRTCHNL_VERSION_MAJOR;
212         version.minor = VIRTCHNL_VERSION_MINOR;
213
214         args.ops = VIRTCHNL_OP_VERSION;
215         args.in_args = (uint8_t *)&version;
216         args.in_args_size = sizeof(version);
217         args.out_buffer = vf->aq_resp;
218         args.out_size = AVF_AQ_BUF_SZ;
219
220         err = avf_execute_vf_cmd(adapter, &args);
221         if (err) {
222                 PMD_INIT_LOG(ERR, "Fail to execute command of OP_VERSION");
223                 return err;
224         }
225
226         pver = (struct virtchnl_version_info *)args.out_buffer;
227         vf->virtchnl_version = *pver;
228
229         if (vf->virtchnl_version.major < VIRTCHNL_VERSION_MAJOR_START ||
230             (vf->virtchnl_version.major == VIRTCHNL_VERSION_MAJOR_START &&
231              vf->virtchnl_version.minor < VIRTCHNL_VERSION_MINOR_START)) {
232                 PMD_INIT_LOG(ERR, "VIRTCHNL API version should not be lower"
233                              " than (%u.%u) to support Adapative VF",
234                              VIRTCHNL_VERSION_MAJOR_START,
235                              VIRTCHNL_VERSION_MAJOR_START);
236                 return -1;
237         } else if (vf->virtchnl_version.major > VIRTCHNL_VERSION_MAJOR ||
238                    (vf->virtchnl_version.major == VIRTCHNL_VERSION_MAJOR &&
239                     vf->virtchnl_version.minor > VIRTCHNL_VERSION_MINOR)) {
240                 PMD_INIT_LOG(ERR, "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
241                              vf->virtchnl_version.major,
242                              vf->virtchnl_version.minor,
243                              VIRTCHNL_VERSION_MAJOR,
244                              VIRTCHNL_VERSION_MINOR);
245                 return -1;
246         }
247
248         PMD_DRV_LOG(DEBUG, "Peer is supported PF host");
249         return 0;
250 }
251
252 int
253 avf_get_vf_resource(struct avf_adapter *adapter)
254 {
255         struct avf_hw *hw = AVF_DEV_PRIVATE_TO_HW(adapter);
256         struct avf_info *vf = AVF_DEV_PRIVATE_TO_VF(adapter);
257         struct avf_cmd_info args;
258         uint32_t caps, len;
259         int err, i;
260
261         args.ops = VIRTCHNL_OP_GET_VF_RESOURCES;
262         args.out_buffer = vf->aq_resp;
263         args.out_size = AVF_AQ_BUF_SZ;
264
265         /* TODO: basic offload capabilities, need to
266          * add advanced/optional offload capabilities
267          */
268
269         caps = AVF_BASIC_OFFLOAD_CAPS;
270
271         args.in_args = (uint8_t *)&caps;
272         args.in_args_size = sizeof(caps);
273
274         err = avf_execute_vf_cmd(adapter, &args);
275
276         if (err) {
277                 PMD_DRV_LOG(ERR, "Failed to execute command of "
278                                  "OP_GET_VF_RESOURCE");
279                 return -1;
280         }
281
282         len =  sizeof(struct virtchnl_vf_resource) +
283                       AVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource);
284
285         rte_memcpy(vf->vf_res, args.out_buffer,
286                    RTE_MIN(args.out_size, len));
287         /* parse  VF config message back from PF*/
288         avf_parse_hw_config(hw, vf->vf_res);
289         for (i = 0; i < vf->vf_res->num_vsis; i++) {
290                 if (vf->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
291                         vf->vsi_res = &vf->vf_res->vsi_res[i];
292         }
293
294         if (!vf->vsi_res) {
295                 PMD_INIT_LOG(ERR, "no LAN VSI found");
296                 return -1;
297         }
298
299         vf->vsi.vsi_id = vf->vsi_res->vsi_id;
300         vf->vsi.nb_qps = vf->vsi_res->num_queue_pairs;
301         vf->vsi.adapter = adapter;
302
303         return 0;
304 }