Merge tag 'char-misc-5.15-rc1-lkdtm' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / vdpa / virtio_pci / vp_vdpa.c
index c76ebb5..5bcd002 100644 (file)
@@ -189,10 +189,20 @@ static void vp_vdpa_set_status(struct vdpa_device *vdpa, u8 status)
        }
 
        vp_modern_set_status(mdev, status);
+}
+
+static int vp_vdpa_reset(struct vdpa_device *vdpa)
+{
+       struct vp_vdpa *vp_vdpa = vdpa_to_vp(vdpa);
+       struct virtio_pci_modern_device *mdev = &vp_vdpa->mdev;
+       u8 s = vp_vdpa_get_status(vdpa);
+
+       vp_modern_set_status(mdev, 0);
 
-       if (!(status & VIRTIO_CONFIG_S_DRIVER_OK) &&
-           (s & VIRTIO_CONFIG_S_DRIVER_OK))
+       if (s & VIRTIO_CONFIG_S_DRIVER_OK)
                vp_vdpa_free_irq(vp_vdpa);
+
+       return 0;
 }
 
 static u16 vp_vdpa_get_vq_num_max(struct vdpa_device *vdpa)
@@ -210,13 +220,49 @@ static int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid,
        return -EOPNOTSUPP;
 }
 
+static int vp_vdpa_set_vq_state_split(struct vdpa_device *vdpa,
+                                     const struct vdpa_vq_state *state)
+{
+       const struct vdpa_vq_state_split *split = &state->split;
+
+       if (split->avail_index == 0)
+               return 0;
+
+       return -EOPNOTSUPP;
+}
+
+static int vp_vdpa_set_vq_state_packed(struct vdpa_device *vdpa,
+                                      const struct vdpa_vq_state *state)
+{
+       const struct vdpa_vq_state_packed *packed = &state->packed;
+
+       if (packed->last_avail_counter == 1 &&
+           packed->last_avail_idx == 0 &&
+           packed->last_used_counter == 1 &&
+           packed->last_used_idx == 0)
+               return 0;
+
+       return -EOPNOTSUPP;
+}
+
 static int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid,
                                const struct vdpa_vq_state *state)
 {
-       /* Note that this is not supported by virtio specification, so
-        * we return -ENOPOTSUPP here. This means we can't support live
-        * migration, vhost device start/stop.
+       struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
+
+       /* Note that this is not supported by virtio specification.
+        * But if the state is by chance equal to the device initial
+        * state, we can let it go.
         */
+       if ((vp_modern_get_status(mdev) & VIRTIO_CONFIG_S_FEATURES_OK) &&
+           !vp_modern_get_queue_enable(mdev, qid)) {
+               if (vp_modern_get_driver_features(mdev) &
+                   BIT_ULL(VIRTIO_F_RING_PACKED))
+                       return vp_vdpa_set_vq_state_packed(vdpa, state);
+               else
+                       return vp_vdpa_set_vq_state_split(vdpa, state);
+       }
+
        return -EOPNOTSUPP;
 }
 
@@ -362,6 +408,7 @@ static const struct vdpa_config_ops vp_vdpa_ops = {
        .set_features   = vp_vdpa_set_features,
        .get_status     = vp_vdpa_get_status,
        .set_status     = vp_vdpa_set_status,
+       .reset          = vp_vdpa_reset,
        .get_vq_num_max = vp_vdpa_get_vq_num_max,
        .get_vq_state   = vp_vdpa_get_vq_state,
        .get_vq_notification = vp_vdpa_get_vq_notification,
@@ -399,10 +446,10 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return ret;
 
        vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa,
-                                   dev, &vp_vdpa_ops, NULL);
-       if (vp_vdpa == NULL) {
+                                   dev, &vp_vdpa_ops, NULL, false);
+       if (IS_ERR(vp_vdpa)) {
                dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n");
-               return -ENOMEM;
+               return PTR_ERR(vp_vdpa);
        }
 
        mdev = &vp_vdpa->mdev;
@@ -442,6 +489,7 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                        vp_modern_map_vq_notify(mdev, i,
                                                &vp_vdpa->vring[i].notify_pa);
                if (!vp_vdpa->vring[i].notify) {
+                       ret = -EINVAL;
                        dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i);
                        goto err;
                }