Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vdpa/virtio: replace doorbell relay with notifier #52

Merged
merged 2 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/common/virtio/version.map
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ INTERNAL {
virtio_pci_dev_state_queue_set;
virtio_pci_dev_state_queue_del;
virtio_pci_dev_state_interrupt_enable;
virtio_pci_dev_state_interrupt_enable_only;
virtio_pci_dev_state_interrupt_disable;
virtio_pci_dev_state_dev_status_set;
virtio_pci_dev_state_dump;
Expand Down
17 changes: 17 additions & 0 deletions drivers/common/virtio/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,23 @@ virtio_pci_dev_interrupts_free(struct virtio_pci_dev *vpdev)
return 0;
}

int
virtio_pci_dev_state_interrupt_enable_only(struct virtio_pci_dev *vpdev, int vec, void *state)
{
struct virtio_hw *hw = &vpdev->hw;
struct virtio_dev_queue_info *q_info;
struct virtio_dev_common_state *state_info;

if (vec == 0) {
state_info = state;
state_info->common_cfg.msix_config = 0;
} else {
q_info = hw->virtio_dev_sp_ops->get_queue_offset(state);
q_info[vec-1].q_cfg.queue_msix_vector = rte_cpu_to_le_16(vec);
}
return 0;
}

int
virtio_pci_dev_state_interrupt_enable(struct virtio_pci_dev *vpdev, int fd, int vec, void *state)
{
Expand Down
2 changes: 2 additions & 0 deletions drivers/common/virtio/virtio_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ void virtio_pci_dev_state_queue_del(struct virtio_pci_dev *vpdev, uint16_t qid,
__rte_internal
int virtio_pci_dev_state_interrupt_enable(struct virtio_pci_dev *vpdev, int fd, int vec, void *state);
__rte_internal
int virtio_pci_dev_state_interrupt_enable_only(struct virtio_pci_dev *vpdev, int vec, void *state);
__rte_internal
int virtio_pci_dev_state_interrupt_disable(struct virtio_pci_dev *vpdev, int vec, void *state);
__rte_internal
int virtio_pci_dev_interrupt_enable(struct virtio_pci_dev *vpdev, int fd, int vec);
Expand Down
107 changes: 81 additions & 26 deletions drivers/vdpa/virtio/virtio_vdpa.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,20 +337,7 @@ virtio_vdpa_virtq_handler(void *cb_arg)
}

virtio_pci_dev_queue_notify(priv->vpdev, virtq->index);
if (virtq->notifier_state == VIRTIO_VDPA_NOTIFIER_STATE_DISABLED) {
if (rte_vhost_host_notifier_ctrl(priv->vid, virtq->index, true)) {
DRV_LOG(ERR, "%s failed to set notify ctrl virtq %d: %s",
priv->vdev->device->name, virtq->index, strerror(errno));
virtq->notifier_state = VIRTIO_VDPA_NOTIFIER_STATE_ERR;
} else
virtq->notifier_state = VIRTIO_VDPA_NOTIFIER_STATE_ENABLED;
DRV_LOG(INFO, "%s virtq %u notifier state is %s",
priv->vdev->device->name,
virtq->index,
virtq->notifier_state ==
VIRTIO_VDPA_NOTIFIER_STATE_ENABLED ? "enabled" :
"disabled");
}

DRV_LOG(DEBUG, "%s ring virtq %u doorbell i:%d",
priv->vdev->device->name, virtq->index, i);
}
Expand Down Expand Up @@ -382,7 +369,7 @@ virtio_vdpa_virtq_doorbell_relay_disable(struct virtio_vdpa_priv *priv,
}
rte_intr_instance_free(intr_handle);
priv->vrings[vq_idx]->intr_handle = NULL;
priv->vrings[vq_idx]->notifier_state = VIRTIO_VDPA_NOTIFIER_STATE_DISABLED;
priv->vrings[vq_idx]->notifier_state = VIRTIO_VDPA_NOTIFIER_RELAY_DISABLED;
return 0;
}

Expand Down Expand Up @@ -441,6 +428,52 @@ virtio_vdpa_virtq_doorbell_relay_enable(struct virtio_vdpa_priv *priv, int vq_id
return -EINVAL;
}

static int
virtio_vdpa_dev_notifier_work(void *arg)
{
int ret;
struct virtio_vdpa_notifier_work *work = arg;
uint16_t nr_virtqs, i;

DRV_LOG(INFO, "%s vid %d dev notifier work of vq id:%d core:%d start",
work->priv->vdev->device->name, work->priv->vid, work->vq_idx, rte_lcore_id());

ret = rte_vhost_host_notifier_ctrl(work->priv->vid, work->vq_idx, true);
if (ret) {
DRV_LOG(ERR, "%s vid %d dev notifier work failed use relay ret:%d vq id:%d core:%d",
work->priv->vdev->device->name, work->priv->vid, ret, work->vq_idx, rte_lcore_id());

if (work->vq_idx == RTE_VHOST_QUEUE_ALL) {
nr_virtqs = rte_vhost_get_vring_num(work->priv->vid);
i = 0;
} else {
i = work->vq_idx;
nr_virtqs = i + 1;
}
for(; i < nr_virtqs; i++) {
ret = virtio_vdpa_virtq_doorbell_relay_enable(work->priv, i);
if (ret) {
DRV_LOG(ERR, "%s vid %d dev notifier relay of vq id:%d core:%d setup fail",
work->priv->vdev->device->name, work->priv->vid, i, rte_lcore_id());
}
work->priv->vrings[i]->notifier_state = VIRTIO_VDPA_NOTIFIER_RELAY_ENABLED;
}
}
DRV_LOG(INFO, "%s vid %d dev notifier work of vq id:%d core:%d finish",
work->priv->vdev->device->name, work->priv->vid, work->vq_idx, rte_lcore_id());
/* Notify device anyway, in case loss doorbell */
if (work->vq_idx == RTE_VHOST_QUEUE_ALL) {
nr_virtqs = rte_vhost_get_vring_num(work->priv->vid);
i = 0;
for(; i < nr_virtqs; i++)
virtio_pci_dev_queue_notify(work->priv->vpdev, i);
} else
virtio_pci_dev_queue_notify(work->priv->vpdev, work->vq_idx);

rte_free(work);
return ret;
}

static int
virtio_vdpa_virtq_disable(struct virtio_vdpa_priv *priv, int vq_idx)
{
Expand All @@ -457,10 +490,13 @@ virtio_vdpa_virtq_disable(struct virtio_vdpa_priv *priv, int vq_idx)
}
}

ret = virtio_vdpa_virtq_doorbell_relay_disable(priv, vq_idx);
if (ret) {
DRV_LOG(ERR, "%s doorbell relay disable failed ret:%d",
priv->vdev->device->name, ret);
if (priv->vrings[vq_idx]->notifier_state == VIRTIO_VDPA_NOTIFIER_RELAY_ENABLED) {
ret = virtio_vdpa_virtq_doorbell_relay_disable(priv, vq_idx);
if (ret) {
DRV_LOG(ERR, "%s doorbell relay disable failed ret:%d",
priv->vdev->device->name, ret);
}
priv->vrings[vq_idx]->notifier_state = VIRTIO_VDPA_NOTIFIER_RELAY_DISABLED;
}

if (priv->configured) {
Expand Down Expand Up @@ -583,13 +619,6 @@ virtio_vdpa_virtq_enable(struct virtio_vdpa_priv *priv, int vq_idx)
return -EINVAL;
}

ret = virtio_vdpa_virtq_doorbell_relay_enable(priv, vq_idx);
if (ret) {
DRV_LOG(ERR, "%s virtq doorbell relay failed ret:%d",
priv->vdev->device->name, ret);
return ret;
}

priv->vrings[vq_idx]->enable = true;
virtio_pci_dev_queue_notify(priv->vpdev, vq_idx);
return 0;
Expand Down Expand Up @@ -1144,6 +1173,7 @@ virtio_vdpa_dev_config(int vid)
struct virtio_vdpa_priv *priv =
virtio_vdpa_find_priv_resource_by_vdev(vdev);
uint16_t last_avail_idx, last_used_idx, nr_virtqs;
struct virtio_vdpa_notifier_work *notify_work;
uint64_t t_start = rte_rdtsc_precise();
uint64_t t_end;
int ret, i;
Expand Down Expand Up @@ -1235,6 +1265,25 @@ virtio_vdpa_dev_config(int vid)

DRV_LOG(INFO, "%s vid %d move to driver ok", vdev->device->name, vid);

virtio_vdpa_lcore_id = rte_get_next_lcore(virtio_vdpa_lcore_id, 1, 1);
notify_work = rte_zmalloc(NULL, sizeof(*notify_work), 0);
if (!notify_work) {
DRV_LOG(ERR, "%s vfid %d failed to alloc notify work", priv->vdev->device->name, priv->vf_id);
rte_errno = rte_errno ? rte_errno : ENOMEM;
return -rte_errno;
}

notify_work->priv = priv;
notify_work->vq_idx = RTE_VHOST_QUEUE_ALL;
DRV_LOG(INFO, "%s vfid %d launch all vq notifier work lcore:%d",
priv->vdev->device->name, priv->vf_id, virtio_vdpa_lcore_id);
ret = rte_eal_remote_launch(virtio_vdpa_dev_notifier_work, notify_work, virtio_vdpa_lcore_id);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed launch notifier work ret:%d lcore:%d",
priv->vdev->device->name, priv->vf_id, ret, virtio_vdpa_lcore_id);
rte_free(notify_work);
}

priv->configured = 1;
t_end = rte_rdtsc_precise();
DRV_LOG(INFO, "%s vid %d was configured, took %lu us.", vdev->device->name,
Expand Down Expand Up @@ -1352,6 +1401,12 @@ virtio_vdpa_dev_presetup_done(int vid)
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
}
ret = virtio_pci_dev_state_interrupt_enable_only(priv->vpdev, i + 1, priv->state_mz->addr);
if (ret) {
DRV_LOG(ERR, "%s error set interrupt map in pre-config ret:%d", vdev->device->name, ret);
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
}
}

virtio_pci_dev_state_dev_status_set(priv->state_mz->addr, VIRTIO_CONFIG_STATUS_ACK |
Expand Down
11 changes: 8 additions & 3 deletions drivers/vdpa/virtio/virtio_vdpa.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#define _VIRTIO_VDPA_H_

enum {
VIRTIO_VDPA_NOTIFIER_STATE_DISABLED,
VIRTIO_VDPA_NOTIFIER_STATE_ENABLED,
VIRTIO_VDPA_NOTIFIER_STATE_ERR
VIRTIO_VDPA_NOTIFIER_RELAY_DISABLED,
VIRTIO_VDPA_NOTIFIER_RELAY_ENABLED,
VIRTIO_VDPA_NOTIFIER_RELAY_ERR
};

struct virtio_vdpa_iommu_domain {
Expand Down Expand Up @@ -66,6 +66,11 @@ struct virtio_vdpa_priv {
bool mem_tbl_set;
};

struct virtio_vdpa_notifier_work {
struct virtio_vdpa_priv *priv;
uint16_t vq_idx;
};

#define VIRTIO_VDPA_REMOTE_STATE_DEFAULT_SIZE 8192
#define VIRTIO_VDPA_INTR_RETRIES_USEC 1000
#define VIRTIO_VDPA_INTR_RETRIES 256
Expand Down