summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEddie James <eajames@linux.ibm.com>2020-11-20 03:49:29 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-12-09 21:52:25 +0300
commitdfd7f2c1c532efaeff6084970bb60ec2f2e44191 (patch)
treec51de484bd4c7ab9dd776de6203e41828edb6e1c
parentfe34761d9f5febafd189de608eb9f50d78aac107 (diff)
downloadlinux-dfd7f2c1c532efaeff6084970bb60ec2f2e44191.tar.xz
fsi: Aspeed: Add mutex to protect HW access
There is nothing to prevent multiple commands being executed simultaneously. Add a mutex to prevent this. Fixes: 606397d67f41 ("fsi: Add ast2600 master driver") Reviewed-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Milton Miller <miltonm@us.ibm.com> Signed-off-by: Eddie James <eajames@linux.ibm.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Link: https://lore.kernel.org/r/20201120004929.185239-1-joel@jms.id.au Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/fsi/fsi-master-aspeed.c45
1 files changed, 29 insertions, 16 deletions
diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c
index c006ec008a1a..90dbe58ca1ed 100644
--- a/drivers/fsi/fsi-master-aspeed.c
+++ b/drivers/fsi/fsi-master-aspeed.c
@@ -8,6 +8,7 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -19,6 +20,7 @@
struct fsi_master_aspeed {
struct fsi_master master;
+ struct mutex lock; /* protect HW access */
struct device *dev;
void __iomem *base;
struct clk *clk;
@@ -254,6 +256,8 @@ static int aspeed_master_read(struct fsi_master *master, int link,
addr |= id << 21;
addr += link * FSI_HUB_LINK_SIZE;
+ mutex_lock(&aspeed->lock);
+
switch (size) {
case 1:
ret = opb_readb(aspeed, fsi_base + addr, val);
@@ -265,14 +269,14 @@ static int aspeed_master_read(struct fsi_master *master, int link,
ret = opb_readl(aspeed, fsi_base + addr, val);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
ret = check_errors(aspeed, ret);
- if (ret)
- return ret;
-
- return 0;
+done:
+ mutex_unlock(&aspeed->lock);
+ return ret;
}
static int aspeed_master_write(struct fsi_master *master, int link,
@@ -287,6 +291,8 @@ static int aspeed_master_write(struct fsi_master *master, int link,
addr |= id << 21;
addr += link * FSI_HUB_LINK_SIZE;
+ mutex_lock(&aspeed->lock);
+
switch (size) {
case 1:
ret = opb_writeb(aspeed, fsi_base + addr, *(u8 *)val);
@@ -298,14 +304,14 @@ static int aspeed_master_write(struct fsi_master *master, int link,
ret = opb_writel(aspeed, fsi_base + addr, *(__be32 *)val);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
ret = check_errors(aspeed, ret);
- if (ret)
- return ret;
-
- return 0;
+done:
+ mutex_unlock(&aspeed->lock);
+ return ret;
}
static int aspeed_master_link_enable(struct fsi_master *master, int link,
@@ -320,17 +326,21 @@ static int aspeed_master_link_enable(struct fsi_master *master, int link,
reg = cpu_to_be32(0x80000000 >> bit);
- if (!enable)
- return opb_writel(aspeed, ctrl_base + FSI_MCENP0 + (4 * idx),
- reg);
+ mutex_lock(&aspeed->lock);
+
+ if (!enable) {
+ ret = opb_writel(aspeed, ctrl_base + FSI_MCENP0 + (4 * idx), reg);
+ goto done;
+ }
ret = opb_writel(aspeed, ctrl_base + FSI_MSENP0 + (4 * idx), reg);
if (ret)
- return ret;
+ goto done;
mdelay(FSI_LINK_ENABLE_SETUP_TIME);
-
- return 0;
+done:
+ mutex_unlock(&aspeed->lock);
+ return ret;
}
static int aspeed_master_term(struct fsi_master *master, int link, uint8_t id)
@@ -431,9 +441,11 @@ static ssize_t cfam_reset_store(struct device *dev, struct device_attribute *att
{
struct fsi_master_aspeed *aspeed = dev_get_drvdata(dev);
+ mutex_lock(&aspeed->lock);
gpiod_set_value(aspeed->cfam_reset_gpio, 1);
usleep_range(900, 1000);
gpiod_set_value(aspeed->cfam_reset_gpio, 0);
+ mutex_unlock(&aspeed->lock);
return count;
}
@@ -597,6 +609,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, aspeed);
+ mutex_init(&aspeed->lock);
aspeed_master_init(aspeed);
rc = fsi_master_register(&aspeed->master);