xref: /dpdk/drivers/common/sfc_efx/base/rhead_virtio.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
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 */
380