common/sfc_efx/base: separate target EvQ and IRQ config
[dpdk.git] / drivers / common / sfc_efx / base / rhead_virtio.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2020-2021 Xilinx, Inc.
4  */
5
6 #include "efx.h"
7 #include "efx_impl.h"
8
9 #if EFSYS_OPT_RIVERHEAD && EFSYS_OPT_VIRTIO
10
11 /*
12  * Get function-local index of the associated VI from the
13  * virtqueue number queue 0 is reserved for MCDI
14  */
15 #define EFX_VIRTIO_GET_VI_INDEX(vq_num) (((vq_num) / 2) + 1)
16
17         __checkReturn   efx_rc_t
18 rhead_virtio_qstart(
19         __in            efx_virtio_vq_t *evvp,
20         __in            efx_virtio_vq_cfg_t *evvcp,
21         __in_opt        efx_virtio_vq_dyncfg_t *evvdp)
22
23 {
24         efx_nic_t *enp = evvp->evv_enp;
25         efx_mcdi_req_t req;
26         uint32_t vi_index;
27         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_INIT_QUEUE_REQ_LEN,
28                 MC_CMD_VIRTIO_INIT_QUEUE_RESP_LEN);
29         efx_rc_t rc;
30
31         EFX_STATIC_ASSERT(EFX_VIRTIO_VQ_TYPE_NET_RXQ ==
32                 MC_CMD_VIRTIO_INIT_QUEUE_REQ_NET_RXQ);
33         EFX_STATIC_ASSERT(EFX_VIRTIO_VQ_TYPE_NET_TXQ ==
34                 MC_CMD_VIRTIO_INIT_QUEUE_REQ_NET_TXQ);
35         EFX_STATIC_ASSERT(EFX_VIRTIO_VQ_TYPE_BLOCK ==
36                 MC_CMD_VIRTIO_INIT_QUEUE_REQ_BLOCK);
37
38         if (evvcp->evvc_type >= EFX_VIRTIO_VQ_NTYPES) {
39                 rc = EINVAL;
40                 goto fail1;
41         }
42
43         /* virtqueue size must be power of 2 */
44         if ((!ISP2(evvcp->evvc_vq_size)) ||
45             (evvcp->evvc_vq_size > EFX_VIRTIO_MAX_VQ_SIZE)) {
46                 rc = EINVAL;
47                 goto fail2;
48         }
49
50         if (evvdp != NULL) {
51                 if ((evvdp->evvd_vq_cidx > evvcp->evvc_vq_size) ||
52                     (evvdp->evvd_vq_pidx > evvcp->evvc_vq_size)) {
53                         rc = EINVAL;
54                         goto fail3;
55                 }
56         }
57
58         req.emr_cmd = MC_CMD_VIRTIO_INIT_QUEUE;
59         req.emr_in_buf = payload;
60         req.emr_in_length = MC_CMD_VIRTIO_INIT_QUEUE_REQ_LEN;
61         req.emr_out_buf = payload;
62         req.emr_out_length = MC_CMD_VIRTIO_INIT_QUEUE_RESP_LEN;
63
64         MCDI_IN_SET_BYTE(req, VIRTIO_INIT_QUEUE_REQ_QUEUE_TYPE,
65                 evvcp->evvc_type);
66         MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_TARGET_VF,
67                 evvcp->evvc_target_vf);
68
69         vi_index = EFX_VIRTIO_GET_VI_INDEX(evvcp->evvc_vq_num);
70         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INSTANCE, vi_index);
71
72         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_SIZE,
73                 evvcp->evvc_vq_size);
74
75         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_DESC_TBL_ADDR_LO,
76                 evvcp->evvc_desc_tbl_addr & 0xFFFFFFFF);
77         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_DESC_TBL_ADDR_HI,
78                 evvcp->evvc_desc_tbl_addr >> 32);
79
80         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_AVAIL_RING_ADDR_LO,
81                 evvcp->evvc_avail_ring_addr & 0xFFFFFFFF);
82         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_AVAIL_RING_ADDR_HI,
83                 evvcp->evvc_avail_ring_addr >> 32);
84
85         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_USED_RING_ADDR_LO,
86                 evvcp->evvc_used_ring_addr & 0xFFFFFFFF);
87         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_USED_RING_ADDR_HI,
88                 evvcp->evvc_used_ring_addr >> 32);
89
90         if (evvcp->evvc_use_pasid) {
91                 MCDI_IN_POPULATE_DWORD_1(req, VIRTIO_INIT_QUEUE_REQ_FLAGS,
92                         VIRTIO_INIT_QUEUE_REQ_USE_PASID, 1);
93                 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_PASID,
94                         evvcp->evvc_pas_id);
95         }
96
97         MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_MSIX_VECTOR,
98                 evvcp->evvc_msix_vector);
99
100         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_FEATURES_LO,
101                 evvcp->evcc_features & 0xFFFFFFFF);
102         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_FEATURES_HI,
103                 evvcp->evcc_features >> 32);
104
105         if (evvdp != NULL) {
106                 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INITIAL_PIDX,
107                         evvdp->evvd_vq_pidx);
108                 MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INITIAL_CIDX,
109                         evvdp->evvd_vq_cidx);
110         }
111
112         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_MPORT_SELECTOR,
113                 MAE_MPORT_SELECTOR_ASSIGNED);
114
115         efx_mcdi_execute(enp, &req);
116
117         if (req.emr_rc != 0) {
118                 rc = req.emr_rc;
119                 goto fail4;
120         }
121
122         evvp->evv_vi_index = vi_index;
123
124         return (0);
125
126 fail4:
127         EFSYS_PROBE(fail4);
128 fail3:
129         EFSYS_PROBE(fail3);
130 fail2:
131         EFSYS_PROBE(fail2);
132 fail1:
133         EFSYS_PROBE1(fail1, efx_rc_t, rc);
134
135         return (rc);
136 }
137
138         __checkReturn   efx_rc_t
139 rhead_virtio_qstop(
140         __in            efx_virtio_vq_t *evvp,
141         __out_opt       efx_virtio_vq_dyncfg_t *evvdp)
142 {
143         efx_mcdi_req_t req;
144         efx_nic_t *enp = evvp->evv_enp;
145         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_FINI_QUEUE_REQ_LEN,
146                 MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN);
147         efx_rc_t rc;
148
149         req.emr_cmd = MC_CMD_VIRTIO_FINI_QUEUE;
150         req.emr_in_buf = payload;
151         req.emr_in_length = MC_CMD_VIRTIO_FINI_QUEUE_REQ_LEN;
152         req.emr_out_buf = payload;
153         req.emr_out_length = MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN;
154
155         MCDI_IN_SET_BYTE(req, VIRTIO_FINI_QUEUE_REQ_QUEUE_TYPE, evvp->evv_type);
156         MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_TARGET_VF,
157                 evvp->evv_target_vf);
158         MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INSTANCE,
159                 evvp->evv_vi_index);
160
161         efx_mcdi_execute(enp, &req);
162
163         if (req.emr_rc != 0) {
164                 rc = req.emr_rc;
165                 goto fail1;
166         }
167
168         if (req.emr_out_length_used < MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN) {
169                 rc = EMSGSIZE;
170                 goto fail2;
171         }
172
173         if (evvdp != NULL) {
174                 evvdp->evvd_vq_pidx =
175                     MCDI_OUT_DWORD(req, VIRTIO_FINI_QUEUE_RESP_FINAL_PIDX);
176                 evvdp->evvd_vq_cidx =
177                     MCDI_OUT_DWORD(req, VIRTIO_FINI_QUEUE_RESP_FINAL_CIDX);
178         }
179
180         return (0);
181
182 fail2:
183         EFSYS_PROBE(fail2);
184 fail1:
185         EFSYS_PROBE1(fail1, efx_rc_t, rc);
186
187         return (rc);
188 }
189
190         __checkReturn   efx_rc_t
191 rhead_virtio_get_doorbell_offset(
192         __in            efx_virtio_vq_t *evvp,
193         __out           uint32_t *offsetp)
194 {
195         efx_nic_t *enp = evvp->evv_enp;
196         efx_mcdi_req_t req;
197         uint32_t type;
198         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_GET_DOORBELL_OFFSET_REQ_LEN,
199                 MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN);
200         efx_rc_t rc;
201
202         req.emr_cmd = MC_CMD_VIRTIO_GET_DOORBELL_OFFSET;
203         req.emr_in_buf = payload;
204         req.emr_in_length = MC_CMD_VIRTIO_GET_DOORBELL_OFFSET_REQ_LEN;
205         req.emr_out_buf = payload;
206         req.emr_out_length = MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN;
207
208         switch (evvp->evv_type) {
209         case EFX_VIRTIO_VQ_TYPE_NET_RXQ:
210         case EFX_VIRTIO_VQ_TYPE_NET_TXQ:
211                 type = MC_CMD_VIRTIO_GET_FEATURES_IN_NET;
212                 break;
213         case EFX_VIRTIO_VQ_TYPE_BLOCK:
214                 type = MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK;
215                 break;
216         default:
217                 rc = EINVAL;
218                 goto fail1;
219         }
220
221         MCDI_IN_SET_BYTE(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_DEVICE_ID,
222                 type);
223         MCDI_IN_SET_WORD(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_TARGET_VF,
224                 evvp->evv_target_vf);
225         MCDI_IN_SET_DWORD(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_INSTANCE,
226                 evvp->evv_vi_index);
227
228         efx_mcdi_execute(enp, &req);
229
230         if (req.emr_rc != 0) {
231                 rc = req.emr_rc;
232                 goto fail2;
233         }
234
235         switch (type) {
236         case MC_CMD_VIRTIO_GET_FEATURES_IN_NET:
237                 if (req.emr_out_length_used <
238                     MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN) {
239                         rc = EMSGSIZE;
240                         goto fail3;
241                 }
242
243                 if (evvp->evv_type == EFX_VIRTIO_VQ_TYPE_NET_RXQ) {
244                         *offsetp = MCDI_OUT_DWORD(req,
245                             VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_RX_DBL_OFFSET);
246                 } else if (evvp->evv_type == EFX_VIRTIO_VQ_TYPE_NET_TXQ) {
247                         *offsetp = MCDI_OUT_DWORD(req,
248                             VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_TX_DBL_OFFSET);
249                 }
250                 break;
251         case MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK:
252                 if (req.emr_out_length_used <
253                     MC_CMD_VIRTIO_GET_BLOCK_DOORBELL_OFFSET_RESP_LEN) {
254                         rc = EMSGSIZE;
255                         goto fail4;
256                 }
257
258                 *offsetp = MCDI_OUT_DWORD(req,
259                         VIRTIO_GET_BLOCK_DOORBELL_OFFSET_RESP_DBL_OFFSET);
260                 break;
261         default:
262                 EFSYS_ASSERT(0);
263                 rc = EINVAL;
264                 goto fail5;
265         }
266
267         return (0);
268
269 fail5:
270         EFSYS_PROBE(fail5);
271 fail4:
272         EFSYS_PROBE(fail4);
273 fail3:
274         EFSYS_PROBE(fail3);
275 fail2:
276         EFSYS_PROBE(fail2);
277 fail1:
278         EFSYS_PROBE1(fail1, efx_rc_t, rc);
279
280         return (rc);
281 }
282
283         __checkReturn   efx_rc_t
284 rhead_virtio_get_features(
285         __in            efx_nic_t *enp,
286         __in            efx_virtio_device_type_t type,
287         __out           uint64_t *featuresp)
288 {
289         efx_mcdi_req_t req;
290         uint32_t features_lo;
291         uint32_t features_hi;
292         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_GET_FEATURES_IN_LEN,
293                 MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN);
294         efx_rc_t rc;
295
296         EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_NET ==
297                 MC_CMD_VIRTIO_GET_FEATURES_IN_NET);
298         EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_BLOCK ==
299                 MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK);
300
301         req.emr_cmd = MC_CMD_VIRTIO_GET_FEATURES;
302         req.emr_in_buf = payload;
303         req.emr_in_length = MC_CMD_VIRTIO_GET_FEATURES_IN_LEN;
304         req.emr_out_buf = payload;
305         req.emr_out_length = MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN;
306
307         MCDI_IN_SET_DWORD(req, VIRTIO_GET_FEATURES_IN_DEVICE_ID, type);
308
309         efx_mcdi_execute(enp, &req);
310
311         if (req.emr_rc != 0) {
312                 rc = req.emr_rc;
313                 goto fail1;
314         }
315
316         if (req.emr_out_length_used < MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN) {
317                 rc = EMSGSIZE;
318                 goto fail2;
319         }
320
321         features_lo = MCDI_OUT_DWORD(req, VIRTIO_GET_FEATURES_OUT_FEATURES_LO);
322         features_hi = MCDI_OUT_DWORD(req, VIRTIO_GET_FEATURES_OUT_FEATURES_HI);
323         *featuresp = ((uint64_t)features_hi << 32) | features_lo;
324
325         return (0);
326
327 fail2:
328         EFSYS_PROBE(fail2);
329 fail1:
330         EFSYS_PROBE1(fail1, efx_rc_t, rc);
331
332         return (rc);
333 }
334
335         __checkReturn   efx_rc_t
336 rhead_virtio_verify_features(
337         __in            efx_nic_t *enp,
338         __in            efx_virtio_device_type_t type,
339         __in            uint64_t features)
340 {
341         efx_mcdi_req_t req;
342         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_TEST_FEATURES_IN_LEN,
343                 MC_CMD_VIRTIO_TEST_FEATURES_OUT_LEN);
344         efx_rc_t rc;
345
346         EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_NET ==
347                 MC_CMD_VIRTIO_GET_FEATURES_IN_NET);
348         EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_BLOCK ==
349                 MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK);
350
351         req.emr_cmd = MC_CMD_VIRTIO_TEST_FEATURES;
352         req.emr_in_buf = payload;
353         req.emr_in_length = MC_CMD_VIRTIO_TEST_FEATURES_IN_LEN;
354         req.emr_out_buf = payload;
355         req.emr_out_length = MC_CMD_VIRTIO_TEST_FEATURES_OUT_LEN;
356
357         MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_DEVICE_ID, type);
358
359         MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_FEATURES_LO,
360                 features & 0xFFFFFFFF);
361         MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_FEATURES_HI,
362                 ((features >> 32) & 0xFFFFFFFF));
363
364         efx_mcdi_execute(enp, &req);
365
366         if (req.emr_rc != 0) {
367                 rc = req.emr_rc;
368                 goto fail1;
369         }
370
371         return (0);
372
373 fail1:
374         EFSYS_PROBE1(fail1, efx_rc_t, rc);
375
376         return (rc);
377 }
378
379 #endif  /* EFSYS_OPT_RIVERHEAD && EFSYS_OPT_VIRTIO */