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,20 +1226,46 @@ int enable_cmf(struct ccw_device *cdev) { int ret; + device_lock(&cdev->dev); ret = cmbops->alloc(cdev); - cmbops->reset(cdev); if (ret) - return ret; - ret = cmbops->set(cdev, 2); + goto out; + cmbops->reset(cdev); + ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group); if (ret) { cmbops->free(cdev); - return ret; + goto out; } - ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group); - if (!ret) - return 0; - cmbops->set(cdev, 0); //FIXME: this can fail + ret = cmbops->set(cdev, 2); + if (ret) { + sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); + cmbops->free(cdev); + } +out: + device_unlock(&cdev->dev); + 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, device_lock() held. + */ +int __disable_cmf(struct ccw_device *cdev) +{ + int ret; + + ret = cmbops->set(cdev, 0); + if (ret) + return ret; + + sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); cmbops->free(cdev); + return ret; } @@ -1256,11 +1282,10 @@ 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); + 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)