Merge patch series "UFS Advanced RPMB"
[linux-2.6-microblaze.git] / drivers / vfio / vfio_main.c
index e21ff96..5177bb0 100644 (file)
@@ -158,15 +158,15 @@ static void vfio_device_release(struct device *dev)
        vfio_release_device_set(device);
        ida_free(&vfio.device_ida, device->index);
 
-       /*
-        * kvfree() cannot be done here due to a life cycle mess in
-        * vfio-ccw. Before the ccw part is fixed all drivers are
-        * required to support @release and call vfio_free_device()
-        * from there.
-        */
-       device->ops->release(device);
+       if (device->ops->release)
+               device->ops->release(device);
+
+       kvfree(device);
 }
 
+static int vfio_init_device(struct vfio_device *device, struct device *dev,
+                           const struct vfio_device_ops *ops);
+
 /*
  * Allocate and initialize vfio_device so it can be registered to vfio
  * core.
@@ -205,11 +205,9 @@ EXPORT_SYMBOL_GPL(_vfio_alloc_device);
 
 /*
  * Initialize a vfio_device so it can be registered to vfio core.
- *
- * Only vfio-ccw driver should call this interface.
  */
-int vfio_init_device(struct vfio_device *device, struct device *dev,
-                    const struct vfio_device_ops *ops)
+static int vfio_init_device(struct vfio_device *device, struct device *dev,
+                           const struct vfio_device_ops *ops)
 {
        int ret;
 
@@ -241,18 +239,6 @@ out_uninit:
        ida_free(&vfio.device_ida, device->index);
        return ret;
 }
-EXPORT_SYMBOL_GPL(vfio_init_device);
-
-/*
- * The helper called by driver @release callback to free the device
- * structure. Drivers which don't have private data to clean can
- * simply use this helper as its @release.
- */
-void vfio_free_device(struct vfio_device *device)
-{
-       kvfree(device);
-}
-EXPORT_SYMBOL_GPL(vfio_free_device);
 
 static int __vfio_register_dev(struct vfio_device *device,
                               enum vfio_group_type type)
@@ -504,7 +490,7 @@ int vfio_mig_get_next_state(struct vfio_device *device,
                            enum vfio_device_mig_state new_fsm,
                            enum vfio_device_mig_state *next_fsm)
 {
-       enum { VFIO_DEVICE_NUM_STATES = VFIO_DEVICE_STATE_RUNNING_P2P + 1 };
+       enum { VFIO_DEVICE_NUM_STATES = VFIO_DEVICE_STATE_PRE_COPY_P2P + 1 };
        /*
         * The coding in this table requires the driver to implement the
         * following FSM arcs:
@@ -519,30 +505,65 @@ int vfio_mig_get_next_state(struct vfio_device *device,
         *         RUNNING_P2P -> RUNNING
         *         RUNNING_P2P -> STOP
         *         STOP -> RUNNING_P2P
-        * Without P2P the driver must implement:
+        *
+        * If precopy is supported then the driver must support these additional
+        * FSM arcs:
+        *         RUNNING -> PRE_COPY
+        *         PRE_COPY -> RUNNING
+        *         PRE_COPY -> STOP_COPY
+        * However, if precopy and P2P are supported together then the driver
+        * must support these additional arcs beyond the P2P arcs above:
+        *         PRE_COPY -> RUNNING
+        *         PRE_COPY -> PRE_COPY_P2P
+        *         PRE_COPY_P2P -> PRE_COPY
+        *         PRE_COPY_P2P -> RUNNING_P2P
+        *         PRE_COPY_P2P -> STOP_COPY
+        *         RUNNING -> PRE_COPY
+        *         RUNNING_P2P -> PRE_COPY_P2P
+        *
+        * Without P2P and precopy the driver must implement:
         *         RUNNING -> STOP
         *         STOP -> RUNNING
         *
         * The coding will step through multiple states for some combination
         * transitions; if all optional features are supported, this means the
         * following ones:
+        *         PRE_COPY -> PRE_COPY_P2P -> STOP_COPY
+        *         PRE_COPY -> RUNNING -> RUNNING_P2P
+        *         PRE_COPY -> RUNNING -> RUNNING_P2P -> STOP
+        *         PRE_COPY -> RUNNING -> RUNNING_P2P -> STOP -> RESUMING
+        *         PRE_COPY_P2P -> RUNNING_P2P -> RUNNING
+        *         PRE_COPY_P2P -> RUNNING_P2P -> STOP
+        *         PRE_COPY_P2P -> RUNNING_P2P -> STOP -> RESUMING
         *         RESUMING -> STOP -> RUNNING_P2P
+        *         RESUMING -> STOP -> RUNNING_P2P -> PRE_COPY_P2P
         *         RESUMING -> STOP -> RUNNING_P2P -> RUNNING
+        *         RESUMING -> STOP -> RUNNING_P2P -> RUNNING -> PRE_COPY
         *         RESUMING -> STOP -> STOP_COPY
+        *         RUNNING -> RUNNING_P2P -> PRE_COPY_P2P
         *         RUNNING -> RUNNING_P2P -> STOP
         *         RUNNING -> RUNNING_P2P -> STOP -> RESUMING
         *         RUNNING -> RUNNING_P2P -> STOP -> STOP_COPY
+        *         RUNNING_P2P -> RUNNING -> PRE_COPY
         *         RUNNING_P2P -> STOP -> RESUMING
         *         RUNNING_P2P -> STOP -> STOP_COPY
+        *         STOP -> RUNNING_P2P -> PRE_COPY_P2P
         *         STOP -> RUNNING_P2P -> RUNNING
+        *         STOP -> RUNNING_P2P -> RUNNING -> PRE_COPY
         *         STOP_COPY -> STOP -> RESUMING
         *         STOP_COPY -> STOP -> RUNNING_P2P
         *         STOP_COPY -> STOP -> RUNNING_P2P -> RUNNING
+        *
+        *  The following transitions are blocked:
+        *         STOP_COPY -> PRE_COPY
+        *         STOP_COPY -> PRE_COPY_P2P
         */
        static const u8 vfio_from_fsm_table[VFIO_DEVICE_NUM_STATES][VFIO_DEVICE_NUM_STATES] = {
                [VFIO_DEVICE_STATE_STOP] = {
                        [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_RUNNING_P2P,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_RUNNING_P2P,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_RUNNING_P2P,
                        [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_STOP_COPY,
                        [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_RESUMING,
                        [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_RUNNING_P2P,
@@ -551,14 +572,38 @@ int vfio_mig_get_next_state(struct vfio_device *device,
                [VFIO_DEVICE_STATE_RUNNING] = {
                        [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_RUNNING_P2P,
                        [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_RUNNING,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_PRE_COPY,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_RUNNING_P2P,
                        [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_RUNNING_P2P,
                        [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_RUNNING_P2P,
                        [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_RUNNING_P2P,
                        [VFIO_DEVICE_STATE_ERROR] = VFIO_DEVICE_STATE_ERROR,
                },
+               [VFIO_DEVICE_STATE_PRE_COPY] = {
+                       [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_RUNNING,
+                       [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_RUNNING,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_PRE_COPY,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_PRE_COPY_P2P,
+                       [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_PRE_COPY_P2P,
+                       [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_RUNNING,
+                       [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_RUNNING,
+                       [VFIO_DEVICE_STATE_ERROR] = VFIO_DEVICE_STATE_ERROR,
+               },
+               [VFIO_DEVICE_STATE_PRE_COPY_P2P] = {
+                       [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_RUNNING_P2P,
+                       [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_RUNNING_P2P,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_PRE_COPY,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_PRE_COPY_P2P,
+                       [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_STOP_COPY,
+                       [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_RUNNING_P2P,
+                       [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_RUNNING_P2P,
+                       [VFIO_DEVICE_STATE_ERROR] = VFIO_DEVICE_STATE_ERROR,
+               },
                [VFIO_DEVICE_STATE_STOP_COPY] = {
                        [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_STOP,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_ERROR,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_ERROR,
                        [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_STOP_COPY,
                        [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_STOP,
@@ -567,6 +612,8 @@ int vfio_mig_get_next_state(struct vfio_device *device,
                [VFIO_DEVICE_STATE_RESUMING] = {
                        [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_STOP,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_STOP,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_RESUMING,
                        [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_STOP,
@@ -575,6 +622,8 @@ int vfio_mig_get_next_state(struct vfio_device *device,
                [VFIO_DEVICE_STATE_RUNNING_P2P] = {
                        [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_RUNNING,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_RUNNING,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_PRE_COPY_P2P,
                        [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_STOP,
                        [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_RUNNING_P2P,
@@ -583,6 +632,8 @@ int vfio_mig_get_next_state(struct vfio_device *device,
                [VFIO_DEVICE_STATE_ERROR] = {
                        [VFIO_DEVICE_STATE_STOP] = VFIO_DEVICE_STATE_ERROR,
                        [VFIO_DEVICE_STATE_RUNNING] = VFIO_DEVICE_STATE_ERROR,
+                       [VFIO_DEVICE_STATE_PRE_COPY] = VFIO_DEVICE_STATE_ERROR,
+                       [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_DEVICE_STATE_ERROR,
                        [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_DEVICE_STATE_ERROR,
                        [VFIO_DEVICE_STATE_RESUMING] = VFIO_DEVICE_STATE_ERROR,
                        [VFIO_DEVICE_STATE_RUNNING_P2P] = VFIO_DEVICE_STATE_ERROR,
@@ -593,6 +644,11 @@ int vfio_mig_get_next_state(struct vfio_device *device,
        static const unsigned int state_flags_table[VFIO_DEVICE_NUM_STATES] = {
                [VFIO_DEVICE_STATE_STOP] = VFIO_MIGRATION_STOP_COPY,
                [VFIO_DEVICE_STATE_RUNNING] = VFIO_MIGRATION_STOP_COPY,
+               [VFIO_DEVICE_STATE_PRE_COPY] =
+                       VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_PRE_COPY,
+               [VFIO_DEVICE_STATE_PRE_COPY_P2P] = VFIO_MIGRATION_STOP_COPY |
+                                                  VFIO_MIGRATION_P2P |
+                                                  VFIO_MIGRATION_PRE_COPY,
                [VFIO_DEVICE_STATE_STOP_COPY] = VFIO_MIGRATION_STOP_COPY,
                [VFIO_DEVICE_STATE_RESUMING] = VFIO_MIGRATION_STOP_COPY,
                [VFIO_DEVICE_STATE_RUNNING_P2P] =
@@ -704,6 +760,34 @@ out_copy:
        return 0;
 }
 
+static int
+vfio_ioctl_device_feature_migration_data_size(struct vfio_device *device,
+                                             u32 flags, void __user *arg,
+                                             size_t argsz)
+{
+       struct vfio_device_feature_mig_data_size data_size = {};
+       unsigned long stop_copy_length;
+       int ret;
+
+       if (!device->mig_ops)
+               return -ENOTTY;
+
+       ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_GET,
+                                sizeof(data_size));
+       if (ret != 1)
+               return ret;
+
+       ret = device->mig_ops->migration_get_data_size(device, &stop_copy_length);
+       if (ret)
+               return ret;
+
+       data_size.stop_copy_length = stop_copy_length;
+       if (copy_to_user(arg, &data_size, sizeof(data_size)))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int vfio_ioctl_device_feature_migration(struct vfio_device *device,
                                               u32 flags, void __user *arg,
                                               size_t argsz)
@@ -931,6 +1015,10 @@ static int vfio_ioctl_device_feature(struct vfio_device *device,
                return vfio_ioctl_device_feature_logging_report(
                        device, feature.flags, arg->data,
                        feature.argsz - minsz);
+       case VFIO_DEVICE_FEATURE_MIG_DATA_SIZE:
+               return vfio_ioctl_device_feature_migration_data_size(
+                       device, feature.flags, arg->data,
+                       feature.argsz - minsz);
        default:
                if (unlikely(!device->ops->device_feature))
                        return -EINVAL;
@@ -1260,6 +1348,10 @@ static int __init vfio_init(void)
        if (ret)
                return ret;
 
+       ret = vfio_virqfd_init();
+       if (ret)
+               goto err_virqfd;
+
        /* /sys/class/vfio-dev/vfioX */
        vfio.device_class = class_create(THIS_MODULE, "vfio-dev");
        if (IS_ERR(vfio.device_class)) {
@@ -1271,6 +1363,8 @@ static int __init vfio_init(void)
        return 0;
 
 err_dev_class:
+       vfio_virqfd_exit();
+err_virqfd:
        vfio_group_cleanup();
        return ret;
 }
@@ -1280,6 +1374,7 @@ static void __exit vfio_cleanup(void)
        ida_destroy(&vfio.device_ida);
        class_destroy(vfio.device_class);
        vfio.device_class = NULL;
+       vfio_virqfd_exit();
        vfio_group_cleanup();
        xa_destroy(&vfio_device_set_xa);
 }