Commit 1bc6664b authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky

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: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 279b8f9a
......@@ -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);
......
......@@ -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;
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
* __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;
}
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment