diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2015-09-15 13:11:42 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-10-14 14:32:02 +0200 |
commit | 1bc6664bdfb949bc69a08113801e7d6acbf6bc3f (patch) | |
tree | 5426526ca602c9394d3501cf15cf61fa5acc2695 | |
parent | 279b8f9a0f3ea3399764047d487dfdd8f7bc9795 (diff) | |
download | linux-1bc6664bdfb949bc69a08113801e7d6acbf6bc3f.tar.gz linux-1bc6664bdfb949bc69a08113801e7d6acbf6bc3f.tar.bz2 linux-1bc6664bdfb949bc69a08113801e7d6acbf6bc3f.zip |
s390/cio: use device_lock during cmb activation
Hold the device_lock during [de]activation of the channel measurement
block to synchronize concurrent usage of these functions.
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/cmb.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/cmf.c | 49 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 2 |
3 files changed, 39 insertions, 13 deletions
diff --git a/arch/s390/include/asm/cmb.h b/arch/s390/include/asm/cmb.h index 806eac12e3bd..ed2630c23f90 100644 --- a/arch/s390/include/asm/cmb.h +++ b/arch/s390/include/asm/cmb.h @@ -6,6 +6,7 @@ struct ccw_device; extern int enable_cmf(struct ccw_device *cdev); extern int disable_cmf(struct ccw_device *cdev); +extern int __disable_cmf(struct ccw_device *cdev); extern u64 cmf_read(struct ccw_device *cdev, int index); extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data); 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) |