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_VIRTIO
10
11 #if EFSYS_OPT_RIVERHEAD
12 static const efx_virtio_ops_t __efx_virtio_rhead_ops = {
13 rhead_virtio_qstart, /* evo_virtio_qstart */
14 rhead_virtio_qstop, /* evo_virtio_qstop */
15 rhead_virtio_get_doorbell_offset, /* evo_get_doorbell_offset */
16 rhead_virtio_get_features, /* evo_get_features */
17 rhead_virtio_verify_features, /* evo_verify_features */
18 };
19 #endif /* EFSYS_OPT_RIVERHEAD */
20
21 __checkReturn efx_rc_t
efx_virtio_init(__in efx_nic_t * enp)22 efx_virtio_init(
23 __in efx_nic_t *enp)
24 {
25 const efx_virtio_ops_t *evop;
26 efx_rc_t rc;
27
28 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
29 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
30 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VIRTIO));
31
32 switch (enp->en_family) {
33 #if EFSYS_OPT_RIVERHEAD
34 case EFX_FAMILY_RIVERHEAD:
35 evop = &__efx_virtio_rhead_ops;
36 break;
37 #endif /* EFSYS_OPT_RIVERHEAD */
38
39 default:
40 EFSYS_ASSERT(0);
41 rc = ENOTSUP;
42 goto fail1;
43 }
44
45 enp->en_evop = evop;
46 enp->en_mod_flags |= EFX_MOD_VIRTIO;
47
48 return (0);
49
50 fail1:
51 EFSYS_PROBE1(fail1, efx_rc_t, rc);
52
53 enp->en_evop = NULL;
54 enp->en_mod_flags &= ~EFX_MOD_VIRTIO;
55
56 return (rc);
57 }
58
59 void
efx_virtio_fini(__in efx_nic_t * enp)60 efx_virtio_fini(
61 __in efx_nic_t *enp)
62 {
63 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
64 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
65 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
66
67 enp->en_evop = NULL;
68 enp->en_mod_flags &= ~EFX_MOD_VIRTIO;
69 }
70
71 __checkReturn efx_rc_t
efx_virtio_qcreate(__in efx_nic_t * enp,__deref_out efx_virtio_vq_t ** evvpp)72 efx_virtio_qcreate(
73 __in efx_nic_t *enp,
74 __deref_out efx_virtio_vq_t **evvpp)
75 {
76 const efx_virtio_ops_t *evop = enp->en_evop;
77 efx_virtio_vq_t *evvp;
78 efx_rc_t rc;
79
80 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
81 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
82
83 /* Allocate a virtqueue object */
84 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_virtio_vq_t), evvp);
85 if (evvp == NULL) {
86 rc = ENOMEM;
87 goto fail1;
88 }
89
90 evvp->evv_magic = EFX_VQ_MAGIC;
91 evvp->evv_enp = enp;
92 evvp->evv_state = EFX_VIRTIO_VQ_STATE_INITIALIZED;
93
94 *evvpp = evvp;
95
96 return (0);
97
98 fail1:
99 EFSYS_PROBE1(fail1, efx_rc_t, rc);
100
101 return (rc);
102 }
103
104 __checkReturn efx_rc_t
efx_virtio_qstart(__in efx_virtio_vq_t * evvp,__in efx_virtio_vq_cfg_t * evvcp,__in_opt efx_virtio_vq_dyncfg_t * evvdp)105 efx_virtio_qstart(
106 __in efx_virtio_vq_t *evvp,
107 __in efx_virtio_vq_cfg_t *evvcp,
108 __in_opt efx_virtio_vq_dyncfg_t *evvdp)
109 {
110 const efx_virtio_ops_t *evop;
111 efx_rc_t rc;
112
113 if ((evvcp == NULL) || (evvp == NULL)) {
114 rc = EINVAL;
115 goto fail1;
116 }
117
118 if (evvp->evv_state != EFX_VIRTIO_VQ_STATE_INITIALIZED) {
119 rc = EINVAL;
120 goto fail2;
121 }
122
123 evop = evvp->evv_enp->en_evop;
124 if (evop == NULL) {
125 rc = ENOTSUP;
126 goto fail3;
127 }
128
129 if ((rc = evop->evo_virtio_qstart(evvp, evvcp, evvdp)) != 0)
130 goto fail4;
131
132 evvp->evv_type = evvcp->evvc_type;
133 evvp->evv_target_vf = evvcp->evvc_target_vf;
134 evvp->evv_state = EFX_VIRTIO_VQ_STATE_STARTED;
135
136 return (0);
137
138 fail4:
139 EFSYS_PROBE(fail4);
140 fail3:
141 EFSYS_PROBE(fail3);
142 fail2:
143 EFSYS_PROBE(fail2);
144 fail1:
145 EFSYS_PROBE1(fail1, efx_rc_t, rc);
146
147 return (rc);
148 }
149
150 __checkReturn efx_rc_t
efx_virtio_qstop(__in efx_virtio_vq_t * evvp,__out_opt efx_virtio_vq_dyncfg_t * evvdp)151 efx_virtio_qstop(
152 __in efx_virtio_vq_t *evvp,
153 __out_opt efx_virtio_vq_dyncfg_t *evvdp)
154 {
155 efx_nic_t *enp;
156 const efx_virtio_ops_t *evop;
157 efx_rc_t rc;
158
159 if (evvp == NULL) {
160 rc = EINVAL;
161 goto fail1;
162 }
163
164 enp = evvp->evv_enp;
165 evop = enp->en_evop;
166
167 EFSYS_ASSERT3U(evvp->evv_magic, ==, EFX_VQ_MAGIC);
168 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
169 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
170
171 if (evop == NULL) {
172 rc = ENOTSUP;
173 goto fail2;
174 }
175
176 if (evvp->evv_state != EFX_VIRTIO_VQ_STATE_STARTED) {
177 rc = EINVAL;
178 goto fail3;
179 }
180
181 if ((rc = evop->evo_virtio_qstop(evvp, evvdp)) != 0)
182 goto fail4;
183
184 evvp->evv_state = EFX_VIRTIO_VQ_STATE_INITIALIZED;
185
186 return 0;
187
188 fail4:
189 EFSYS_PROBE(fail4);
190 fail3:
191 EFSYS_PROBE(fail3);
192 fail2:
193 EFSYS_PROBE(fail2);
194 fail1:
195 EFSYS_PROBE1(fail1, efx_rc_t, rc);
196
197 return (rc);
198 }
199
200 void
efx_virtio_qdestroy(__in efx_virtio_vq_t * evvp)201 efx_virtio_qdestroy(
202 __in efx_virtio_vq_t *evvp)
203 {
204 efx_nic_t *enp;
205
206 if (evvp == NULL)
207 return;
208
209 enp = evvp->evv_enp;
210
211 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
212
213 if (evvp->evv_state == EFX_VIRTIO_VQ_STATE_INITIALIZED) {
214 /* Free the virtqueue object */
215 EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_virtio_vq_t), evvp);
216 }
217 }
218
219 __checkReturn efx_rc_t
efx_virtio_get_doorbell_offset(__in efx_virtio_vq_t * evvp,__out uint32_t * offsetp)220 efx_virtio_get_doorbell_offset(
221 __in efx_virtio_vq_t *evvp,
222 __out uint32_t *offsetp)
223 {
224 efx_nic_t *enp;
225 const efx_virtio_ops_t *evop;
226 efx_rc_t rc;
227
228 if ((evvp == NULL) || (offsetp == NULL)) {
229 rc = EINVAL;
230 goto fail1;
231 }
232
233 enp = evvp->evv_enp;
234 evop = enp->en_evop;
235
236 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
237 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
238
239 if (evop == NULL) {
240 rc = ENOTSUP;
241 goto fail2;
242 }
243
244 if ((rc = evop->evo_get_doorbell_offset(evvp, offsetp)) != 0)
245 goto fail3;
246
247 return (0);
248
249 fail3:
250 EFSYS_PROBE(fail3);
251 fail2:
252 EFSYS_PROBE(fail2);
253 fail1:
254 EFSYS_PROBE1(fail1, efx_rc_t, rc);
255
256 return (rc);
257 }
258
259 __checkReturn efx_rc_t
efx_virtio_get_features(__in efx_nic_t * enp,__in efx_virtio_device_type_t type,__out uint64_t * featuresp)260 efx_virtio_get_features(
261 __in efx_nic_t *enp,
262 __in efx_virtio_device_type_t type,
263 __out uint64_t *featuresp)
264 {
265 const efx_virtio_ops_t *evop = enp->en_evop;
266 efx_rc_t rc;
267
268 if (featuresp == NULL) {
269 rc = EINVAL;
270 goto fail1;
271 }
272
273 if (type >= EFX_VIRTIO_DEVICE_NTYPES) {
274 rc = EINVAL;
275 goto fail2;
276 }
277
278 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
279 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
280
281 if (evop == NULL) {
282 rc = ENOTSUP;
283 goto fail3;
284 }
285
286 if ((rc = evop->evo_get_features(enp, type, featuresp)) != 0)
287 goto fail4;
288
289 return (0);
290
291 fail4:
292 EFSYS_PROBE(fail4);
293 fail3:
294 EFSYS_PROBE(fail3);
295 fail2:
296 EFSYS_PROBE(fail2);
297 fail1:
298 EFSYS_PROBE1(fail1, efx_rc_t, rc);
299
300 return (rc);
301 }
302
303 __checkReturn efx_rc_t
efx_virtio_verify_features(__in efx_nic_t * enp,__in efx_virtio_device_type_t type,__in uint64_t features)304 efx_virtio_verify_features(
305 __in efx_nic_t *enp,
306 __in efx_virtio_device_type_t type,
307 __in uint64_t features)
308 {
309 const efx_virtio_ops_t *evop = enp->en_evop;
310 efx_rc_t rc;
311
312 if (type >= EFX_VIRTIO_DEVICE_NTYPES) {
313 rc = EINVAL;
314 goto fail1;
315 }
316
317 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
318 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
319
320 if (evop == NULL) {
321 rc = ENOTSUP;
322 goto fail2;
323 }
324
325 if ((rc = evop->evo_verify_features(enp, type, features)) != 0)
326 goto fail3;
327
328 return (0);
329
330 fail3:
331 EFSYS_PROBE(fail3);
332 fail2:
333 EFSYS_PROBE(fail2);
334 fail1:
335 EFSYS_PROBE1(fail1, efx_rc_t, rc);
336
337 return (rc);
338 }
339
340 #endif /* EFSYS_OPT_VIRTIO */
341