u16 avail_idx;
        u16 used_idx;
        int fw_state;
+
+       u64 modified_fields;
+
        struct msi_map map;
 
        /* keep last in the struct */
        }
 }
 
-static int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int state)
+static bool modifiable_virtqueue_fields(struct mlx5_vdpa_virtqueue *mvq)
+{
+       /* Only state is always modifiable */
+       if (mvq->modified_fields & ~MLX5_VIRTQ_MODIFY_MASK_STATE)
+               return mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT ||
+                      mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND;
+
+       return true;
+}
+
+static int modify_virtqueue(struct mlx5_vdpa_net *ndev,
+                           struct mlx5_vdpa_virtqueue *mvq,
+                           int state)
 {
        int inlen = MLX5_ST_SZ_BYTES(modify_virtio_net_q_in);
        u32 out[MLX5_ST_SZ_DW(modify_virtio_net_q_out)] = {};
        if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_NONE)
                return 0;
 
+       if (!modifiable_virtqueue_fields(mvq))
+               return -EINVAL;
+
        if (!is_valid_state_change(mvq->fw_state, state))
                return -EINVAL;
 
        MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid);
 
        obj_context = MLX5_ADDR_OF(modify_virtio_net_q_in, in, obj_context);
-       MLX5_SET64(virtio_net_q_object, obj_context, modify_field_select,
-                  MLX5_VIRTQ_MODIFY_MASK_STATE);
-       MLX5_SET(virtio_net_q_object, obj_context, state, state);
+       if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_STATE)
+               MLX5_SET(virtio_net_q_object, obj_context, state, state);
+
+       MLX5_SET64(virtio_net_q_object, obj_context, modify_field_select, mvq->modified_fields);
        err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out));
        kfree(in);
        if (!err)
                mvq->fw_state = state;
 
+       mvq->modified_fields = 0;
+
        return err;
 }
 
+static int modify_virtqueue_state(struct mlx5_vdpa_net *ndev,
+                                 struct mlx5_vdpa_virtqueue *mvq,
+                                 unsigned int state)
+{
+       mvq->modified_fields |= MLX5_VIRTQ_MODIFY_MASK_STATE;
+       return modify_virtqueue(ndev, mvq, state);
+}
+
 static int counter_set_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
 {
        u32 in[MLX5_ST_SZ_DW(create_virtio_q_counters_in)] = {};
                goto err_vq;
 
        if (mvq->ready) {
-               err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
+               err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
                if (err) {
                        mlx5_vdpa_warn(&ndev->mvdev, "failed to modify to ready vq idx %d(%d)\n",
                                       idx, err);
        if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY)
                return;
 
-       if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND))
+       if (modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND))
                mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n");
 
        if (query_virtqueue(ndev, mvq, &attr)) {
                return;
 
        suspend_vq(ndev, mvq);
+       mvq->modified_fields = 0;
        destroy_virtqueue(ndev, mvq);
        dealloc_vector(ndev, mvq);
        counter_set_dealloc(ndev, mvq);
        if (!ready) {
                suspend_vq(ndev, mvq);
        } else {
-               err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
+               err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
                if (err) {
                        mlx5_vdpa_warn(mvdev, "modify VQ %d to ready failed (%d)\n", idx, err);
                        ready = false;
 {
        int i;
 
-       for (i = 0; i < ndev->mvdev.max_vqs; i++)
+       for (i = 0; i < ndev->mvdev.max_vqs; i++) {
                ndev->vqs[i].ready = false;
+               ndev->vqs[i].modified_fields = 0;
+       }
 
        ndev->mvdev.cvq.ready = false;
 }