xref: /dpdk/drivers/common/sfc_efx/base/rhead_virtio.c (revision 05308e34bf849f4f0c3a23d5b8d6b6bd66ab1a39)
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 	req.emr_cmd = MC_CMD_VIRTIO_INIT_QUEUE;
51 	req.emr_in_buf = payload;
52 	req.emr_in_length = MC_CMD_VIRTIO_INIT_QUEUE_REQ_LEN;
53 	req.emr_out_buf = payload;
54 	req.emr_out_length = MC_CMD_VIRTIO_INIT_QUEUE_RESP_LEN;
55 
56 	MCDI_IN_SET_BYTE(req, VIRTIO_INIT_QUEUE_REQ_QUEUE_TYPE,
57 		evvcp->evvc_type);
58 	MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_TARGET_VF,
59 		evvcp->evvc_target_vf);
60 
61 	vi_index = EFX_VIRTIO_GET_VI_INDEX(evvcp->evvc_vq_num);
62 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INSTANCE, vi_index);
63 
64 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_SIZE,
65 		evvcp->evvc_vq_size);
66 
67 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_DESC_TBL_ADDR_LO,
68 		evvcp->evvc_desc_tbl_addr & 0xFFFFFFFF);
69 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_DESC_TBL_ADDR_HI,
70 		evvcp->evvc_desc_tbl_addr >> 32);
71 
72 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_AVAIL_RING_ADDR_LO,
73 		evvcp->evvc_avail_ring_addr & 0xFFFFFFFF);
74 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_AVAIL_RING_ADDR_HI,
75 		evvcp->evvc_avail_ring_addr >> 32);
76 
77 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_USED_RING_ADDR_LO,
78 		evvcp->evvc_used_ring_addr & 0xFFFFFFFF);
79 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_USED_RING_ADDR_HI,
80 		evvcp->evvc_used_ring_addr >> 32);
81 
82 	if (evvcp->evvc_use_pasid) {
83 		MCDI_IN_POPULATE_DWORD_1(req, VIRTIO_INIT_QUEUE_REQ_FLAGS,
84 			VIRTIO_INIT_QUEUE_REQ_USE_PASID, 1);
85 		MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_PASID,
86 			evvcp->evvc_pas_id);
87 	}
88 
89 	MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_MSIX_VECTOR,
90 		evvcp->evvc_msix_vector);
91 
92 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_FEATURES_LO,
93 		evvcp->evcc_features & 0xFFFFFFFF);
94 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_FEATURES_HI,
95 		evvcp->evcc_features >> 32);
96 
97 	if (evvdp != NULL) {
98 		MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INITIAL_AVAIL_IDX,
99 			evvdp->evvd_vq_avail_idx);
100 		MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INITIAL_USED_IDX,
101 			evvdp->evvd_vq_used_idx);
102 	}
103 
104 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_MPORT_SELECTOR,
105 		MAE_MPORT_SELECTOR_ASSIGNED);
106 
107 	efx_mcdi_execute(enp, &req);
108 
109 	if (req.emr_rc != 0) {
110 		rc = req.emr_rc;
111 		goto fail3;
112 	}
113 
114 	evvp->evv_vi_index = vi_index;
115 
116 	return (0);
117 
118 fail3:
119 	EFSYS_PROBE(fail3);
120 fail2:
121 	EFSYS_PROBE(fail2);
122 fail1:
123 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
124 
125 	return (rc);
126 }
127 
128 	__checkReturn   efx_rc_t
rhead_virtio_qstop(__in efx_virtio_vq_t * evvp,__out_opt efx_virtio_vq_dyncfg_t * evvdp)129 rhead_virtio_qstop(
130 	__in		efx_virtio_vq_t *evvp,
131 	__out_opt	efx_virtio_vq_dyncfg_t *evvdp)
132 {
133 	efx_mcdi_req_t req;
134 	efx_nic_t *enp = evvp->evv_enp;
135 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_FINI_QUEUE_REQ_LEN,
136 		MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN);
137 	efx_rc_t rc;
138 
139 	req.emr_cmd = MC_CMD_VIRTIO_FINI_QUEUE;
140 	req.emr_in_buf = payload;
141 	req.emr_in_length = MC_CMD_VIRTIO_FINI_QUEUE_REQ_LEN;
142 	req.emr_out_buf = payload;
143 	req.emr_out_length = MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN;
144 
145 	MCDI_IN_SET_BYTE(req, VIRTIO_FINI_QUEUE_REQ_QUEUE_TYPE, evvp->evv_type);
146 	MCDI_IN_SET_WORD(req, VIRTIO_INIT_QUEUE_REQ_TARGET_VF,
147 		evvp->evv_target_vf);
148 	MCDI_IN_SET_DWORD(req, VIRTIO_INIT_QUEUE_REQ_INSTANCE,
149 		evvp->evv_vi_index);
150 
151 	efx_mcdi_execute(enp, &req);
152 
153 	if (req.emr_rc != 0) {
154 		rc = req.emr_rc;
155 		goto fail1;
156 	}
157 
158 	if (req.emr_out_length_used < MC_CMD_VIRTIO_FINI_QUEUE_RESP_LEN) {
159 		rc = EMSGSIZE;
160 		goto fail2;
161 	}
162 
163 	if (evvdp != NULL) {
164 		evvdp->evvd_vq_avail_idx =
165 		    MCDI_OUT_DWORD(req, VIRTIO_FINI_QUEUE_RESP_FINAL_AVAIL_IDX);
166 		evvdp->evvd_vq_used_idx =
167 		    MCDI_OUT_DWORD(req, VIRTIO_FINI_QUEUE_RESP_FINAL_USED_IDX);
168 	}
169 
170 	return (0);
171 
172 fail2:
173 	EFSYS_PROBE(fail2);
174 fail1:
175 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
176 
177 	return (rc);
178 }
179 
180 	__checkReturn	efx_rc_t
rhead_virtio_get_doorbell_offset(__in efx_virtio_vq_t * evvp,__out uint32_t * offsetp)181 rhead_virtio_get_doorbell_offset(
182 	__in		efx_virtio_vq_t *evvp,
183 	__out		uint32_t *offsetp)
184 {
185 	efx_nic_t *enp = evvp->evv_enp;
186 	efx_mcdi_req_t req;
187 	uint32_t type;
188 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_GET_DOORBELL_OFFSET_REQ_LEN,
189 		MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN);
190 	efx_rc_t rc;
191 
192 	req.emr_cmd = MC_CMD_VIRTIO_GET_DOORBELL_OFFSET;
193 	req.emr_in_buf = payload;
194 	req.emr_in_length = MC_CMD_VIRTIO_GET_DOORBELL_OFFSET_REQ_LEN;
195 	req.emr_out_buf = payload;
196 	req.emr_out_length = MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN;
197 
198 	switch (evvp->evv_type) {
199 	case EFX_VIRTIO_VQ_TYPE_NET_RXQ:
200 	case EFX_VIRTIO_VQ_TYPE_NET_TXQ:
201 		type = MC_CMD_VIRTIO_GET_FEATURES_IN_NET;
202 		break;
203 	case EFX_VIRTIO_VQ_TYPE_BLOCK:
204 		type = MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK;
205 		break;
206 	default:
207 		rc = EINVAL;
208 		goto fail1;
209 	}
210 
211 	MCDI_IN_SET_BYTE(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_DEVICE_ID,
212 		type);
213 	MCDI_IN_SET_WORD(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_TARGET_VF,
214 		evvp->evv_target_vf);
215 	MCDI_IN_SET_DWORD(req, VIRTIO_GET_DOORBELL_OFFSET_REQ_INSTANCE,
216 		evvp->evv_vi_index);
217 
218 	efx_mcdi_execute(enp, &req);
219 
220 	if (req.emr_rc != 0) {
221 		rc = req.emr_rc;
222 		goto fail2;
223 	}
224 
225 	switch (type) {
226 	case MC_CMD_VIRTIO_GET_FEATURES_IN_NET:
227 		if (req.emr_out_length_used <
228 		    MC_CMD_VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_LEN) {
229 			rc = EMSGSIZE;
230 			goto fail3;
231 		}
232 
233 		if (evvp->evv_type == EFX_VIRTIO_VQ_TYPE_NET_RXQ) {
234 			*offsetp = MCDI_OUT_DWORD(req,
235 			    VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_RX_DBL_OFFSET);
236 		} else if (evvp->evv_type == EFX_VIRTIO_VQ_TYPE_NET_TXQ) {
237 			*offsetp = MCDI_OUT_DWORD(req,
238 			    VIRTIO_GET_NET_DOORBELL_OFFSET_RESP_TX_DBL_OFFSET);
239 		}
240 		break;
241 	case MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK:
242 		if (req.emr_out_length_used <
243 		    MC_CMD_VIRTIO_GET_BLOCK_DOORBELL_OFFSET_RESP_LEN) {
244 			rc = EMSGSIZE;
245 			goto fail4;
246 		}
247 
248 		*offsetp = MCDI_OUT_DWORD(req,
249 			VIRTIO_GET_BLOCK_DOORBELL_OFFSET_RESP_DBL_OFFSET);
250 		break;
251 	default:
252 		EFSYS_ASSERT(0);
253 		rc = EINVAL;
254 		goto fail5;
255 	}
256 
257 	return (0);
258 
259 fail5:
260 	EFSYS_PROBE(fail5);
261 fail4:
262 	EFSYS_PROBE(fail4);
263 fail3:
264 	EFSYS_PROBE(fail3);
265 fail2:
266 	EFSYS_PROBE(fail2);
267 fail1:
268 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
269 
270 	return (rc);
271 }
272 
273 	__checkReturn	efx_rc_t
rhead_virtio_get_features(__in efx_nic_t * enp,__in efx_virtio_device_type_t type,__out uint64_t * featuresp)274 rhead_virtio_get_features(
275 	__in		efx_nic_t *enp,
276 	__in		efx_virtio_device_type_t type,
277 	__out		uint64_t *featuresp)
278 {
279 	efx_mcdi_req_t req;
280 	uint32_t features_lo;
281 	uint32_t features_hi;
282 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_GET_FEATURES_IN_LEN,
283 		MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN);
284 	efx_rc_t rc;
285 
286 	EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_NET ==
287 		MC_CMD_VIRTIO_GET_FEATURES_IN_NET);
288 	EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_BLOCK ==
289 		MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK);
290 
291 	req.emr_cmd = MC_CMD_VIRTIO_GET_FEATURES;
292 	req.emr_in_buf = payload;
293 	req.emr_in_length = MC_CMD_VIRTIO_GET_FEATURES_IN_LEN;
294 	req.emr_out_buf = payload;
295 	req.emr_out_length = MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN;
296 
297 	MCDI_IN_SET_DWORD(req, VIRTIO_GET_FEATURES_IN_DEVICE_ID, type);
298 
299 	efx_mcdi_execute(enp, &req);
300 
301 	if (req.emr_rc != 0) {
302 		rc = req.emr_rc;
303 		goto fail1;
304 	}
305 
306 	if (req.emr_out_length_used < MC_CMD_VIRTIO_GET_FEATURES_OUT_LEN) {
307 		rc = EMSGSIZE;
308 		goto fail2;
309 	}
310 
311 	features_lo = MCDI_OUT_DWORD(req, VIRTIO_GET_FEATURES_OUT_FEATURES_LO);
312 	features_hi = MCDI_OUT_DWORD(req, VIRTIO_GET_FEATURES_OUT_FEATURES_HI);
313 	*featuresp = ((uint64_t)features_hi << 32) | features_lo;
314 
315 	return (0);
316 
317 fail2:
318 	EFSYS_PROBE(fail2);
319 fail1:
320 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
321 
322 	return (rc);
323 }
324 
325 	__checkReturn	efx_rc_t
rhead_virtio_verify_features(__in efx_nic_t * enp,__in efx_virtio_device_type_t type,__in uint64_t features)326 rhead_virtio_verify_features(
327 	__in		efx_nic_t *enp,
328 	__in		efx_virtio_device_type_t type,
329 	__in		uint64_t features)
330 {
331 	efx_mcdi_req_t req;
332 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_VIRTIO_TEST_FEATURES_IN_LEN,
333 		MC_CMD_VIRTIO_TEST_FEATURES_OUT_LEN);
334 	efx_rc_t rc;
335 
336 	EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_NET ==
337 		MC_CMD_VIRTIO_GET_FEATURES_IN_NET);
338 	EFX_STATIC_ASSERT(EFX_VIRTIO_DEVICE_TYPE_BLOCK ==
339 		MC_CMD_VIRTIO_GET_FEATURES_IN_BLOCK);
340 
341 	req.emr_cmd = MC_CMD_VIRTIO_TEST_FEATURES;
342 	req.emr_in_buf = payload;
343 	req.emr_in_length = MC_CMD_VIRTIO_TEST_FEATURES_IN_LEN;
344 	req.emr_out_buf = payload;
345 	req.emr_out_length = MC_CMD_VIRTIO_TEST_FEATURES_OUT_LEN;
346 
347 	MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_DEVICE_ID, type);
348 
349 	MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_FEATURES_LO,
350 		features & 0xFFFFFFFF);
351 	MCDI_IN_SET_DWORD(req, VIRTIO_TEST_FEATURES_IN_FEATURES_HI,
352 		((features >> 32) & 0xFFFFFFFF));
353 
354 	efx_mcdi_execute(enp, &req);
355 
356 	if (req.emr_rc != 0) {
357 		rc = req.emr_rc;
358 		goto fail1;
359 	}
360 
361 	return (0);
362 
363 fail1:
364 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
365 
366 	return (rc);
367 }
368 
369 #endif	/* EFSYS_OPT_RIVERHEAD && EFSYS_OPT_VIRTIO */
370