Skip to content

Commit

Permalink
vdpa/sfc: resolve race between libvhost and sfc_vdpa_pmd
Browse files Browse the repository at this point in the history
libvhost calls vdps_sfc_pmd's dev_conf() before prosessing
the VHOST_USER_SET_VRING_CALL message for the last VQ. So
this message is processed after dev_conf() returns.

However sfc_vdpa_pmd's dev_conf() spawns a thread to set
rte_vhost_host_notifier_ctrl() before returning control to
libvhost. This parallel thread in turn invokes get_notify_area().
To get the notify_area, sfc_vdpa_pmd needs to query the HW and
for this query it needs an enabled VQ.

But at the same time libvhost is processing the last
VHOST_USER_SET_VRING_CALL, and to do that it disables the last VQ.

Hence there is a race b/w the libvhost and sfc_vdpa_pmd

To resolve this race condition, query the HW and cache notify_area
inside dev_conf() instead of doing it the parallel thread.

Signed-off-by: Abhimanyu Saini <[email protected]>
  • Loading branch information
Abhimanyu Saini committed Jun 15, 2022
1 parent 3ee1b6d commit 3736e32
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 20 deletions.
39 changes: 19 additions & 20 deletions drivers/vdpa/sfc/sfc_vdpa_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ static int
sfc_vdpa_virtq_start(struct sfc_vdpa_ops_data *ops_data, int vq_num)
{
int rc;
uint32_t doorbell;
efx_virtio_vq_t *vq;
struct sfc_vdpa_vring_info vring;
efx_virtio_vq_cfg_t vq_cfg;
Expand Down Expand Up @@ -270,22 +271,35 @@ sfc_vdpa_virtq_start(struct sfc_vdpa_ops_data *ops_data, int vq_num)
/* Start virtqueue */
rc = efx_virtio_qstart(vq, &vq_cfg, &vq_dyncfg);
if (rc != 0) {
/* destroy virtqueue */
sfc_vdpa_err(ops_data->dev_handle,
"virtqueue start failed: %s",
rte_strerror(rc));
efx_virtio_qdestroy(vq);
goto fail_virtio_qstart;
}

sfc_vdpa_info(ops_data->dev_handle,
"virtqueue started successfully for vq_num %d", vq_num);

rc = efx_virtio_get_doorbell_offset(vq, &doorbell);
if (rc != 0) {
sfc_vdpa_err(ops_data->dev_handle,
"failed to get doorbell offset: %s",
rte_strerror(rc));
goto fail_doorbell;
}

/*
* Cache the bar_offset here for each VQ here, it will come
* in handy when sfc_vdpa_get_notify_area() is invoked.
*/
ops_data->vq_cxt[vq_num].doorbell = (void *)(uintptr_t)doorbell;
ops_data->vq_cxt[vq_num].enable = B_TRUE;

return rc;

fail_doorbell:
fail_virtio_qstart:
efx_virtio_qdestroy(vq);
fail_vring_info:
return rc;
}
Expand Down Expand Up @@ -792,8 +806,6 @@ sfc_vdpa_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
int ret;
efx_nic_t *nic;
int vfio_dev_fd;
efx_rc_t rc;
unsigned int bar_offset;
volatile void *doorbell;
struct rte_pci_device *pci_dev;
struct rte_vdpa_device *vdpa_dev;
Expand Down Expand Up @@ -824,19 +836,6 @@ sfc_vdpa_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
return -1;
}

if (ops_data->vq_cxt[qid].enable != B_TRUE) {
sfc_vdpa_err(dev, "vq is not enabled");
return -1;
}

rc = efx_virtio_get_doorbell_offset(ops_data->vq_cxt[qid].vq,
&bar_offset);
if (rc != 0) {
sfc_vdpa_err(dev, "failed to get doorbell offset: %s",
rte_strerror(rc));
return rc;
}

reg.index = sfc_vdpa_adapter_by_dev_handle(dev)->mem_bar.esb_rid;
ret = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, &reg);
if (ret != 0) {
Expand All @@ -845,7 +844,8 @@ sfc_vdpa_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
return ret;
}

*offset = reg.offset + bar_offset;
/* Use bar_offset that was cached during sfc_vdpa_virtq_start() */
*offset = reg.offset + (uint64_t)ops_data->vq_cxt[qid].doorbell;

len = (1U << encp->enc_vi_window_shift) / 2;
if (len >= sysconf(_SC_PAGESIZE)) {
Expand All @@ -859,8 +859,7 @@ sfc_vdpa_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
*offset);

pci_dev = sfc_vdpa_adapter_by_dev_handle(dev)->pdev;
doorbell = (uint8_t *)pci_dev->mem_resource[reg.index].addr +
bar_offset + reg.offset;
doorbell = (uint8_t *)pci_dev->mem_resource[reg.index].addr + *offset;

/*
* virtio-net driver in VM sends queue notifications before
Expand Down
1 change: 1 addition & 0 deletions drivers/vdpa/sfc/sfc_vdpa_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct sfc_vdpa_vring_info {
};

typedef struct sfc_vdpa_vq_context_s {
volatile void *doorbell;
uint8_t enable;
uint32_t pidx;
uint32_t cidx;
Expand Down

0 comments on commit 3736e32

Please sign in to comment.