2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-20 19:23:57 +08:00

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>
This commit is contained in:
Sebastian Ott 2015-09-15 13:11:42 +02:00 committed by Martin Schwidefsky
parent 279b8f9a0f
commit 1bc6664bdf
3 changed files with 40 additions and 14 deletions

View File

@ -6,6 +6,7 @@
struct ccw_device; struct ccw_device;
extern int enable_cmf(struct ccw_device *cdev); 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 int __disable_cmf(struct ccw_device *cdev);
extern u64 cmf_read(struct ccw_device *cdev, int index); extern u64 cmf_read(struct ccw_device *cdev, int index);
extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data); extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data);

View File

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

View File

@ -1797,7 +1797,7 @@ static void ccw_device_shutdown(struct device *dev)
cdev = to_ccwdev(dev); cdev = to_ccwdev(dev);
if (cdev->drv && cdev->drv->shutdown) if (cdev->drv && cdev->drv->shutdown)
cdev->drv->shutdown(cdev); cdev->drv->shutdown(cdev);
disable_cmf(cdev); __disable_cmf(cdev);
} }
static int ccw_device_pm_prepare(struct device *dev) static int ccw_device_pm_prepare(struct device *dev)