Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / drivers / s390 / cio / cmf.c
index b2afad5..2a34eb5 100644 (file)
@@ -753,6 +753,17 @@ static void reset_cmb(struct ccw_device *cdev)
        cmf_generic_reset(cdev);
 }
 
+static int cmf_enabled(struct ccw_device *cdev)
+{
+       int enabled;
+
+       spin_lock_irq(cdev->ccwlock);
+       enabled = !!cdev->private->cmb;
+       spin_unlock_irq(cdev->ccwlock);
+
+       return enabled;
+}
+
 static struct attribute_group cmf_attr_group;
 
 static struct cmb_operations cmbops_basic = {
@@ -1153,13 +1164,8 @@ static ssize_t cmb_enable_show(struct device *dev,
                               char *buf)
 {
        struct ccw_device *cdev = to_ccwdev(dev);
-       int enabled;
 
-       spin_lock_irq(cdev->ccwlock);
-       enabled = !!cdev->private->cmb;
-       spin_unlock_irq(cdev->ccwlock);
-
-       return sprintf(buf, "%d\n", enabled);
+       return sprintf(buf, "%d\n", cmf_enabled(cdev));
 }
 
 static ssize_t cmb_enable_store(struct device *dev,
@@ -1199,15 +1205,20 @@ int ccw_set_cmf(struct ccw_device *cdev, int enable)
  *  @cdev:     The ccw device to be enabled
  *
  *  Returns %0 for success or a negative error value.
- *
+ *  Note: If this is called on a device for which channel measurement is already
+ *       enabled a reset of the measurement data is triggered.
  *  Context:
  *    non-atomic
  */
 int enable_cmf(struct ccw_device *cdev)
 {
-       int ret;
+       int ret = 0;
 
        device_lock(&cdev->dev);
+       if (cmf_enabled(cdev)) {
+               cmbops->reset(cdev);
+               goto out_unlock;
+       }
        get_device(&cdev->dev);
        ret = cmbops->alloc(cdev);
        if (ret)
@@ -1226,7 +1237,7 @@ int enable_cmf(struct ccw_device *cdev)
 out:
        if (ret)
                put_device(&cdev->dev);
-
+out_unlock:
        device_unlock(&cdev->dev);
        return ret;
 }