diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2018-06-12 07:19:07 +0200 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2018-06-18 06:33:56 +0200 |
commit | 162c3946734d1f1950b413bbb3182d76d5be484b (patch) | |
tree | 8851f40603b3e88d4f1ed4fef1cb0d26261c9761 /drivers/fsi | |
parent | fsi: core: Fix sparse warnings (diff) | |
download | linux-162c3946734d1f1950b413bbb3182d76d5be484b.tar.xz linux-162c3946734d1f1950b413bbb3182d76d5be484b.zip |
fsi: scom: Add mutex around FSI2PIB accesses
Otherwise, multiple clients can open the driver and attempt
to access the PIB at the same time, thus clobbering each other
in the process.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Eddie James <eajames@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/fsi')
-rw-r--r-- | drivers/fsi/fsi-scom.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index c8eb5e5b94a7..3cba0eb645e1 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c @@ -37,6 +37,7 @@ struct scom_device { struct list_head link; struct fsi_device *fsi_dev; struct miscdevice mdev; + struct mutex lock; char name[32]; int idx; }; @@ -53,21 +54,26 @@ static int put_scom(struct scom_device *scom_dev, uint64_t value, int rc; uint32_t data; + mutex_lock(&scom_dev->lock); + data = cpu_to_be32((value >> 32) & 0xffffffff); rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data, sizeof(uint32_t)); if (rc) - return rc; + goto bail; data = cpu_to_be32(value & 0xffffffff); rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA1_REG, &data, sizeof(uint32_t)); if (rc) - return rc; + goto bail; data = cpu_to_be32(SCOM_WRITE_CMD | addr); - return fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data, + rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data, sizeof(uint32_t)); + bail: + mutex_unlock(&scom_dev->lock); + return rc; } static int get_scom(struct scom_device *scom_dev, uint64_t *value, @@ -76,27 +82,31 @@ static int get_scom(struct scom_device *scom_dev, uint64_t *value, uint32_t result, data; int rc; + + mutex_lock(&scom_dev->lock); *value = 0ULL; data = cpu_to_be32(addr); rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data, sizeof(uint32_t)); if (rc) - return rc; + goto bail; rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA0_REG, &result, sizeof(uint32_t)); if (rc) - return rc; + goto bail; *value |= (uint64_t)cpu_to_be32(result) << 32; rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA1_REG, &result, sizeof(uint32_t)); if (rc) - return rc; + goto bail; *value |= cpu_to_be32(result); - return 0; + bail: + mutex_unlock(&scom_dev->lock); + return rc; } static ssize_t scom_read(struct file *filep, char __user *buf, size_t len, @@ -183,6 +193,7 @@ static int scom_probe(struct device *dev) if (!scom) return -ENOMEM; + mutex_init(&scom->lock); scom->idx = ida_simple_get(&scom_ida, 1, INT_MAX, GFP_KERNEL); snprintf(scom->name, sizeof(scom->name), "scom%d", scom->idx); scom->fsi_dev = fsi_dev; |