summary refs log tree commit diff
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/cmf.c49
-rw-r--r--drivers/s390/cio/device.c2
2 files changed, 38 insertions, 13 deletions
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 3543c486dcdc..5eeb62c3f33a 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1226,41 +1226,66 @@ int enable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
+	device_lock(&cdev->dev);
 	ret = cmbops->alloc(cdev);
-	cmbops->reset(cdev);
 	if (ret)
-		return ret;
+		goto out;
+	cmbops->reset(cdev);
+	ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group);
+	if (ret) {
+		cmbops->free(cdev);
+		goto out;
+	}
 	ret = cmbops->set(cdev, 2);
 	if (ret) {
+		sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);
 		cmbops->free(cdev);
-		return ret;
 	}
-	ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group);
-	if (!ret)
-		return 0;
-	cmbops->set(cdev, 0);  //FIXME: this can fail
-	cmbops->free(cdev);
+out:
+	device_unlock(&cdev->dev);
 	return ret;
 }
 
 /**
- * disable_cmf() - switch off the channel measurement for a specific device
+ * __disable_cmf() - switch off the channel measurement for a specific device
  *  @cdev:	The ccw device to be disabled
  *
  *  Returns %0 for success or a negative error value.
  *
  *  Context:
- *    non-atomic
+ *    non-atomic, device_lock() held.
  */
-int disable_cmf(struct ccw_device *cdev)
+int __disable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
 	ret = cmbops->set(cdev, 0);
 	if (ret)
 		return ret;
-	cmbops->free(cdev);
+
 	sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);
+	cmbops->free(cdev);
+
+	return ret;
+}
+
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ *  @cdev:	The ccw device to be disabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
+{
+	int ret;
+
+	device_lock(&cdev->dev);
+	ret = __disable_cmf(cdev);
+	device_unlock(&cdev->dev);
+
 	return ret;
 }
 
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index dfef5e63cb7b..20b92c703944 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1797,7 +1797,7 @@ static void ccw_device_shutdown(struct device *dev)
 	cdev = to_ccwdev(dev);
 	if (cdev->drv && cdev->drv->shutdown)
 		cdev->drv->shutdown(cdev);
-	disable_cmf(cdev);
+	__disable_cmf(cdev);
 }
 
 static int ccw_device_pm_prepare(struct device *dev)