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

move suspend to dev config #78

Merged
merged 4 commits into from
Apr 26, 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
4 changes: 2 additions & 2 deletions drivers/common/virtio_mi/lm.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ virtio_vdpa_send_admin_command(struct virtadmin_ctl *avq,
result = virtio_vdpa_send_admin_command_split(avq, ctrl, dat_ctrl,
dlen, pkt_num);
if(result->status && (!(result->status & VIRTIO_ADMIN_CMD_STATUS_DNR_BIT))) {
DRV_LOG(DEBUG, "No:%d cmd status:0x%x, submit again after 100ms", i, result->status);
usleep(100000);
DRV_LOG(DEBUG, "No:%d cmd status:0x%x, submit again after 1s", i, result->status);
usleep(1000000);
}
else
break;
Expand Down
263 changes: 148 additions & 115 deletions drivers/vdpa/virtio/virtio_vdpa.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,20 +461,20 @@ 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)
static void*
virtio_vdpa_dev_notifier(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());
DRV_LOG(INFO, "%s vid %d dev notifier thread of vq id:%d start",
work->priv->vdev->device->name, work->priv->vid, work->vq_idx);

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());
DRV_LOG(ERR, "%s vid %d dev notifier thread failed use relay ret:%d vq id:%d",
work->priv->vdev->device->name, work->priv->vid, ret, work->vq_idx);

if (work->vq_idx == RTE_VHOST_QUEUE_ALL) {
nr_virtqs = rte_vhost_get_vring_num(work->priv->vid);
Expand All @@ -484,15 +484,17 @@ virtio_vdpa_dev_notifier_work(void *arg)
nr_virtqs = i + 1;
}
for(; i < nr_virtqs; i++) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
ret = virtio_vdpa_virtq_doorbell_relay_enable(work->priv, i);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
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());
DRV_LOG(ERR, "%s vid %d dev notifier relay of vq id:%d setup fail",
work->priv->vdev->device->name, work->priv->vid, i);
}
}
}
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());
DRV_LOG(INFO, "%s vid %d dev notifier work of vq id:%d finish",
work->priv->vdev->device->name, work->priv->vid, work->vq_idx);
/* 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);
Expand All @@ -507,7 +509,7 @@ virtio_vdpa_dev_notifier_work(void *arg)
}

rte_free(work);
return ret;
return NULL;
}

static void
Expand Down Expand Up @@ -1259,6 +1261,69 @@ virtio_vdpa_save_state_update_hwidx(struct virtio_vdpa_priv *priv, int num_vr, b
return ret;
}

static int
virtio_vdpa_dev_state_run(struct virtio_vdpa_priv *priv)
{
int ret;

if (priv->lm_status == VIRTIO_S_RUNNING) {
DRV_LOG(INFO, "%s vfid %d already running", priv->vdev->device->name, priv->vf_id);
return 0;
}

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed unfreeze ret:%d",
priv->vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
}
priv->lm_status = VIRTIO_S_QUIESCED;

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_RUNNING);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed unquiesced ret:%d",
priv->vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
}
priv->lm_status = VIRTIO_S_RUNNING;

return 0;
}

static int
virtio_vdpa_dev_state_freeze(struct virtio_vdpa_priv *priv)
{
int ret;

if (priv->lm_status == VIRTIO_S_FREEZED) {
DRV_LOG(INFO, "%s vfid %d already freezed", priv->vdev->device->name, priv->vf_id);
return 0;
}

if (priv->lm_status != VIRTIO_S_QUIESCED) {
ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d",
priv->vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_QUIESCED;
return -rte_errno;
}
priv->lm_status = VIRTIO_S_QUIESCED;
}

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_FREEZED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", priv->vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_FREEZED;
return -rte_errno;
}
priv->lm_status = VIRTIO_S_FREEZED;

return 0;
}

static int
virtio_vdpa_dev_close(int vid)
{
Expand All @@ -1281,6 +1346,19 @@ virtio_vdpa_dev_close(int vid)
DRV_LOG(INFO, "System time of dev close start (dev %s): %lu.%06lu",
vdev->device->name, start.tv_sec, start.tv_usec);

if (priv->is_notify_thread_started) {
void *status;
ret = pthread_cancel(priv->notify_tid);
if (ret) {
DRV_LOG(ERR, "failed to cancel notify_ctrl thread: %s",rte_strerror(ret));
}
ret = pthread_join(priv->notify_tid, &status);
if (ret) {
DRV_LOG(ERR, "failed to join terminated notify_ctrl thread: %s", rte_strerror(ret));
}
priv->is_notify_thread_started = false;
}

virtio_vdpa_doorbell_relay_disable(priv);
if (!priv->configured) {
DRV_LOG(ERR, "vDPA device: %s isn't configured.", vdev->device->name);
Expand All @@ -1289,19 +1367,11 @@ virtio_vdpa_dev_close(int vid)

priv->configured = false;

/* Suspend */
ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", vdev->device->name, priv->vf_id, ret);
// Don't return in device close, try to release all resource.
}
priv->lm_status = VIRTIO_S_QUIESCED;

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_FREEZED);
ret = virtio_vdpa_dev_state_freeze(priv);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", vdev->device->name, priv->vf_id, ret);
DRV_LOG(ERR, "%s vfid %d failed close state modify ret:%d",
vdev->device->name, priv->vf_id, ret);
}
priv->lm_status = VIRTIO_S_FREEZED;

rte_vhost_get_negotiated_features(vid, &features);
if (RTE_VHOST_NEED_LOG(features)) {
Expand Down Expand Up @@ -1389,6 +1459,7 @@ virtio_vdpa_dev_config(int vid)
uint16_t last_avail_idx, last_used_idx, nr_virtqs;
struct virtio_vdpa_notifier_work *notify_work;
struct vdpa_vf_with_devargs vf_dev;
struct rte_vhost_vring vq;
int ret, i, vhost_sock_fd;
struct timeval start, end;
bool compare = true;
Expand Down Expand Up @@ -1462,28 +1533,44 @@ virtio_vdpa_dev_config(int vid)
compare = virtio_pci_dev_state_compare(priv->vpdev, priv->state_mz->addr,
priv->state_size, priv->state_mz_remote->addr,
priv->state_mz_remote->len);
if (!compare) {
ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_QUIESCED;
return -rte_errno;
}

priv->lm_status = VIRTIO_S_QUIESCED;
}

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_FREEZED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_FREEZED;
return -rte_errno;
}
if ((!priv->restore) || (!compare)) {

priv->lm_status = VIRTIO_S_FREEZED;
ret = virtio_vdpa_dev_state_freeze(priv);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed state modify ret:%d", vdev->device->name, priv->vf_id, ret);
return ret;
}
}

if ((!priv->restore) || (!compare)) {
/* In case of recovery, hw idx might changed and device is ready before dev config.
* If we use idx from qemu, it will lag behind, so read from memory to get idx
*/
if (!compare) {
for (i = 0; i < nr_virtqs; i++) {
if (!priv->vrings[i]->conf_enable)
continue;
ret = rte_vhost_get_vhost_vring(vid, i, &vq);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed get vring ret:%d",
vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
}
DRV_LOG(INFO, "%s vid %d qid %d recover last_avail_idx:%d,last_used_idx:%d",
vdev->device->name, vid,
i, vq.used->idx, vq.used->idx);

ret = virtio_pci_dev_state_hw_idx_set(priv->vpdev, i ,
vq.used->idx,
vq.used->idx, priv->state_mz->addr);
if (ret) {
DRV_LOG(ERR, "%s error set dev state ret:%d", vdev->device->name, ret);
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
}
}
}
ret = virtio_vdpa_cmd_restore_state(priv->pf_priv, priv->vf_id, 0, priv->state_size, priv->state_mz->iova);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed restore state ret:%d", vdev->device->name, priv->vf_id, ret);
Expand All @@ -1492,44 +1579,36 @@ virtio_vdpa_dev_config(int vid)
return -rte_errno;
}

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed unfreeze ret:%d", vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
}
priv->lm_status = VIRTIO_S_QUIESCED;

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_RUNNING);
ret = virtio_vdpa_dev_state_run(priv);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed unquiesced ret:%d", vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : EINVAL;
return -rte_errno;
DRV_LOG(ERR, "%s vfid %d failed modify running ret:%d", vdev->device->name, priv->vf_id, ret);
return ret;
}
priv->lm_status = VIRTIO_S_RUNNING;
}

priv->restore = false;
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);
DRV_LOG(ERR, "%s vfid %d failed to alloc notify thread", 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);
DRV_LOG(INFO, "%s vfid %d launch all vq notifier thread",
priv->vdev->device->name, priv->vf_id);
priv->is_notify_thread_started = false;
ret = pthread_create(&priv->notify_tid, NULL,virtio_vdpa_dev_notifier, notify_work);
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);
DRV_LOG(ERR, "%s vfid %d failed launch notifier thread ret:%d",
priv->vdev->device->name, priv->vf_id, ret);
rte_free(notify_work);
return -rte_errno;
}
priv->is_notify_thread_started = true;

priv->configured = 1;
gettimeofday(&end, NULL);
Expand Down Expand Up @@ -1710,28 +1789,16 @@ virtio_vdpa_dev_presetup_done(int vid)
VIRTIO_CONFIG_STATUS_FEATURES_OK |
VIRTIO_CONFIG_STATUS_DRIVER_OK);

if (priv->restore) {
ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_QUIESCED;
return -rte_errno;
}

priv->lm_status = VIRTIO_S_QUIESCED;

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_FREEZED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", vdev->device->name, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_FREEZED;
return -rte_errno;
}

priv->lm_status = VIRTIO_S_FREEZED;
/* No need to on stage2 when presetup, compare can be done on controller side */
priv->restore = false;
ret = virtio_vdpa_dev_state_freeze(priv);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed presetup state modify ret:%d",
vdev->device->name, priv->vf_id, ret);
return ret;
}

/* No need to on stage2 when presetup, compare can be done on controller side */
priv->restore = false;

ret = virtio_vdpa_cmd_restore_state(priv->pf_priv, priv->vf_id, 0,
priv->state_size, priv->state_mz->iova);
if (ret) {
Expand Down Expand Up @@ -2027,22 +2094,6 @@ virtio_vdpa_dev_do_remove(struct rte_pci_device *pci_dev, struct virtio_vdpa_pri
}
}

if (priv->lm_status == VIRTIO_S_FREEZED) {
ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed unfreeze ret:%d", pci_dev->name, priv->vf_id, ret);
}
priv->lm_status = VIRTIO_S_QUIESCED;
}

if (priv->lm_status == VIRTIO_S_QUIESCED) {
ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_RUNNING);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed unquiesced ret:%d", pci_dev->name, priv->vf_id, ret);
}
priv->lm_status = VIRTIO_S_RUNNING;
}

if (priv->vdev)
rte_vdpa_unregister_device(priv->vdev);

Expand Down Expand Up @@ -2410,25 +2461,7 @@ virtio_vdpa_dev_probe(struct rte_pci_driver *pci_drv __rte_unused,
mz_len = priv->state_mz_remote->len;
memset(priv->state_mz_remote->addr, 0, mz_len);

if (!priv->restore) {
ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_QUIESCED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", devname, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_QUIESCED;
goto error;
}

priv->lm_status = VIRTIO_S_QUIESCED;

ret = virtio_vdpa_cmd_set_status(priv->pf_priv, priv->vf_id, VIRTIO_S_FREEZED);
if (ret) {
DRV_LOG(ERR, "%s vfid %d failed suspend ret:%d", devname, priv->vf_id, ret);
rte_errno = rte_errno ? rte_errno : VFE_VDPA_ERR_ADD_VF_SET_STATUS_FREEZED;
goto error;
}

priv->lm_status = VIRTIO_S_FREEZED;
} else {
if (priv->restore) {
virtio_vdpa_save_state_update_hwidx(priv, 0, false);
}

Expand Down
Loading