b8a896ab97
Add an API to verify virtio features supported by device. Signed-off-by: Vijay Kumar Srivastava <vsrivast@xilinx.com> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
341 lines
6.1 KiB
C
341 lines
6.1 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
*
|
|
* Copyright(c) 2020-2021 Xilinx, Inc.
|
|
*/
|
|
|
|
#include "efx.h"
|
|
#include "efx_impl.h"
|
|
|
|
#if EFSYS_OPT_VIRTIO
|
|
|
|
#if EFSYS_OPT_RIVERHEAD
|
|
static const efx_virtio_ops_t __efx_virtio_rhead_ops = {
|
|
rhead_virtio_qstart, /* evo_virtio_qstart */
|
|
rhead_virtio_qstop, /* evo_virtio_qstop */
|
|
rhead_virtio_get_doorbell_offset, /* evo_get_doorbell_offset */
|
|
rhead_virtio_get_features, /* evo_get_features */
|
|
rhead_virtio_verify_features, /* evo_verify_features */
|
|
};
|
|
#endif /* EFSYS_OPT_RIVERHEAD */
|
|
|
|
__checkReturn efx_rc_t
|
|
efx_virtio_init(
|
|
__in efx_nic_t *enp)
|
|
{
|
|
const efx_virtio_ops_t *evop;
|
|
efx_rc_t rc;
|
|
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
|
|
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VIRTIO));
|
|
|
|
switch (enp->en_family) {
|
|
#if EFSYS_OPT_RIVERHEAD
|
|
case EFX_FAMILY_RIVERHEAD:
|
|
evop = &__efx_virtio_rhead_ops;
|
|
break;
|
|
#endif /* EFSYS_OPT_RIVERHEAD */
|
|
|
|
default:
|
|
EFSYS_ASSERT(0);
|
|
rc = ENOTSUP;
|
|
goto fail1;
|
|
}
|
|
|
|
enp->en_evop = evop;
|
|
enp->en_mod_flags |= EFX_MOD_VIRTIO;
|
|
|
|
return (0);
|
|
|
|
fail1:
|
|
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
|
|
|
enp->en_evop = NULL;
|
|
enp->en_mod_flags &= ~EFX_MOD_VIRTIO;
|
|
|
|
return (rc);
|
|
}
|
|
|
|
void
|
|
efx_virtio_fini(
|
|
__in efx_nic_t *enp)
|
|
{
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
|
|
|
|
enp->en_evop = NULL;
|
|
enp->en_mod_flags &= ~EFX_MOD_VIRTIO;
|
|
}
|
|
|
|
__checkReturn efx_rc_t
|
|
efx_virtio_qcreate(
|
|
__in efx_nic_t *enp,
|
|
__deref_out efx_virtio_vq_t **evvpp)
|
|
{
|
|
const efx_virtio_ops_t *evop = enp->en_evop;
|
|
efx_virtio_vq_t *evvp;
|
|
efx_rc_t rc;
|
|
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
|
|
|
|
/* Allocate a virtqueue object */
|
|
EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_virtio_vq_t), evvp);
|
|
if (evvp == NULL) {
|
|
rc = ENOMEM;
|
|
goto fail1;
|
|
}
|
|
|
|
evvp->evv_magic = EFX_VQ_MAGIC;
|
|
evvp->evv_enp = enp;
|
|
evvp->evv_state = EFX_VIRTIO_VQ_STATE_INITIALIZED;
|
|
|
|
*evvpp = evvp;
|
|
|
|
return (0);
|
|
|
|
fail1:
|
|
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
__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)
|
|
{
|
|
const efx_virtio_ops_t *evop;
|
|
efx_rc_t rc;
|
|
|
|
if ((evvcp == NULL) || (evvp == NULL)) {
|
|
rc = EINVAL;
|
|
goto fail1;
|
|
}
|
|
|
|
if (evvp->evv_state != EFX_VIRTIO_VQ_STATE_INITIALIZED) {
|
|
rc = EINVAL;
|
|
goto fail2;
|
|
}
|
|
|
|
evop = evvp->evv_enp->en_evop;
|
|
if (evop == NULL) {
|
|
rc = ENOTSUP;
|
|
goto fail3;
|
|
}
|
|
|
|
if ((rc = evop->evo_virtio_qstart(evvp, evvcp, evvdp)) != 0)
|
|
goto fail4;
|
|
|
|
evvp->evv_type = evvcp->evvc_type;
|
|
evvp->evv_target_vf = evvcp->evvc_target_vf;
|
|
evvp->evv_state = EFX_VIRTIO_VQ_STATE_STARTED;
|
|
|
|
return (0);
|
|
|
|
fail4:
|
|
EFSYS_PROBE(fail4);
|
|
fail3:
|
|
EFSYS_PROBE(fail3);
|
|
fail2:
|
|
EFSYS_PROBE(fail2);
|
|
fail1:
|
|
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
__checkReturn efx_rc_t
|
|
efx_virtio_qstop(
|
|
__in efx_virtio_vq_t *evvp,
|
|
__out_opt efx_virtio_vq_dyncfg_t *evvdp)
|
|
{
|
|
efx_nic_t *enp;
|
|
const efx_virtio_ops_t *evop;
|
|
efx_rc_t rc;
|
|
|
|
if (evvp == NULL) {
|
|
rc = EINVAL;
|
|
goto fail1;
|
|
}
|
|
|
|
enp = evvp->evv_enp;
|
|
evop = enp->en_evop;
|
|
|
|
EFSYS_ASSERT3U(evvp->evv_magic, ==, EFX_VQ_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
|
|
|
|
if (evop == NULL) {
|
|
rc = ENOTSUP;
|
|
goto fail2;
|
|
}
|
|
|
|
if (evvp->evv_state != EFX_VIRTIO_VQ_STATE_STARTED) {
|
|
rc = EINVAL;
|
|
goto fail3;
|
|
}
|
|
|
|
if ((rc = evop->evo_virtio_qstop(evvp, evvdp)) != 0)
|
|
goto fail4;
|
|
|
|
evvp->evv_state = EFX_VIRTIO_VQ_STATE_INITIALIZED;
|
|
|
|
return 0;
|
|
|
|
fail4:
|
|
EFSYS_PROBE(fail4);
|
|
fail3:
|
|
EFSYS_PROBE(fail3);
|
|
fail2:
|
|
EFSYS_PROBE(fail2);
|
|
fail1:
|
|
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
void
|
|
efx_virtio_qdestroy(
|
|
__in efx_virtio_vq_t *evvp)
|
|
{
|
|
efx_nic_t *enp;
|
|
|
|
if (evvp == NULL)
|
|
return;
|
|
|
|
enp = evvp->evv_enp;
|
|
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
|
|
if (evvp->evv_state == EFX_VIRTIO_VQ_STATE_INITIALIZED) {
|
|
/* Free the virtqueue object */
|
|
EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_virtio_vq_t), evvp);
|
|
}
|
|
}
|
|
|
|
__checkReturn efx_rc_t
|
|
efx_virtio_get_doorbell_offset(
|
|
__in efx_virtio_vq_t *evvp,
|
|
__out uint32_t *offsetp)
|
|
{
|
|
efx_nic_t *enp;
|
|
const efx_virtio_ops_t *evop;
|
|
efx_rc_t rc;
|
|
|
|
if ((evvp == NULL) || (offsetp == NULL)) {
|
|
rc = EINVAL;
|
|
goto fail1;
|
|
}
|
|
|
|
enp = evvp->evv_enp;
|
|
evop = enp->en_evop;
|
|
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
|
|
|
|
if (evop == NULL) {
|
|
rc = ENOTSUP;
|
|
goto fail2;
|
|
}
|
|
|
|
if ((rc = evop->evo_get_doorbell_offset(evvp, offsetp)) != 0)
|
|
goto fail3;
|
|
|
|
return (0);
|
|
|
|
fail3:
|
|
EFSYS_PROBE(fail3);
|
|
fail2:
|
|
EFSYS_PROBE(fail2);
|
|
fail1:
|
|
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
__checkReturn efx_rc_t
|
|
efx_virtio_get_features(
|
|
__in efx_nic_t *enp,
|
|
__in efx_virtio_device_type_t type,
|
|
__out uint64_t *featuresp)
|
|
{
|
|
const efx_virtio_ops_t *evop = enp->en_evop;
|
|
efx_rc_t rc;
|
|
|
|
if (featuresp == NULL) {
|
|
rc = EINVAL;
|
|
goto fail1;
|
|
}
|
|
|
|
if (type >= EFX_VIRTIO_DEVICE_NTYPES) {
|
|
rc = EINVAL;
|
|
goto fail2;
|
|
}
|
|
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
|
|
|
|
if (evop == NULL) {
|
|
rc = ENOTSUP;
|
|
goto fail3;
|
|
}
|
|
|
|
if ((rc = evop->evo_get_features(enp, type, featuresp)) != 0)
|
|
goto fail4;
|
|
|
|
return (0);
|
|
|
|
fail4:
|
|
EFSYS_PROBE(fail4);
|
|
fail3:
|
|
EFSYS_PROBE(fail3);
|
|
fail2:
|
|
EFSYS_PROBE(fail2);
|
|
fail1:
|
|
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
__checkReturn efx_rc_t
|
|
efx_virtio_verify_features(
|
|
__in efx_nic_t *enp,
|
|
__in efx_virtio_device_type_t type,
|
|
__in uint64_t features)
|
|
{
|
|
const efx_virtio_ops_t *evop = enp->en_evop;
|
|
efx_rc_t rc;
|
|
|
|
if (type >= EFX_VIRTIO_DEVICE_NTYPES) {
|
|
rc = EINVAL;
|
|
goto fail1;
|
|
}
|
|
|
|
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
|
|
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VIRTIO);
|
|
|
|
if (evop == NULL) {
|
|
rc = ENOTSUP;
|
|
goto fail2;
|
|
}
|
|
|
|
if ((rc = evop->evo_verify_features(enp, type, features)) != 0)
|
|
goto fail3;
|
|
|
|
return (0);
|
|
|
|
fail3:
|
|
EFSYS_PROBE(fail3);
|
|
fail2:
|
|
EFSYS_PROBE(fail2);
|
|
fail1:
|
|
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
#endif /* EFSYS_OPT_VIRTIO */
|