From: Eddie James <eaja...@linux.ibm.com>

[ Upstream commit dfd7f2c1c532efaeff6084970bb60ec2f2e44191 ]

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 <j...@jms.id.au>
Reviewed-by: Milton Miller <milt...@us.ibm.com>
Signed-off-by: Eddie James <eaja...@linux.ibm.com>
Signed-off-by: Joel Stanley <j...@jms.id.au>
Link: https://lore.kernel.org/r/20201120004929.185239-1-j...@jms.id.au
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/fsi/fsi-master-aspeed.c | 45 +++++++++++++++++++++------------
 1 file changed, 29 insertions(+), 16 deletions(-)

diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c
index c006ec008a1aa..90dbe58ca1edc 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);
-- 
2.27.0



Reply via email to