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
rhead_virtio_qstart(__in efx_virtio_vq_t * evvp,__in efx_virtio_vq_cfg_t * evvcp,__in_opt efx_virtio_vq_dyncfg_t * evvdp)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
rhead_virtio_qstop(__in efx_virtio_vq_t * evvp,__out_opt efx_virtio_vq_dyncfg_t * evvdp)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
rhead_virtio_get_doorbell_offset(__in efx_virtio_vq_t * evvp,__out uint32_t * offsetp)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
rhead_virtio_get_features(__in efx_nic_t * enp,__in efx_virtio_device_type_t type,__out uint64_t * featuresp)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
rhead_virtio_verify_features(__in efx_nic_t * enp,__in efx_virtio_device_type_t type,__in uint64_t features)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 */
380