diff options
author | Eddie James <eajames@linux.ibm.com> | 2020-11-20 03:49:29 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-12-09 21:52:25 +0300 |
commit | dfd7f2c1c532efaeff6084970bb60ec2f2e44191 (patch) | |
tree | c51de484bd4c7ab9dd776de6203e41828edb6e1c | |
parent | fe34761d9f5febafd189de608eb9f50d78aac107 (diff) | |
download | linux-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.c | 45 |
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); |