[PATCH linux dev-5.3 7/7] fsi: aspeed: Special case repeated full word reads

Joel Stanley joel at jms.id.au
Fri Oct 25 12:03:51 AEDT 2019


The driver can skip doing some of the AHB2OPB setup if the operation is
of the same type. Experiment with this for full word reads, which could
be extended to writes if it shows an improvement.

Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 drivers/fsi/fsi-master-aspeed.c | 50 ++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c
index 7e515b43b7a6..30e818728402 100644
--- a/drivers/fsi/fsi-master-aspeed.c
+++ b/drivers/fsi/fsi-master-aspeed.c
@@ -92,6 +92,8 @@ struct fsi_master_aspeed {
 	void __iomem		*base;
 	struct clk		*clk;
 
+	bool			last_was_fw_read;
+
 	struct dentry		*debugfs_dir;
 	struct fsi_master_aspeed_debugfs_entry debugfs[FSI_NUM_DEBUGFS_ENTRIES];
 };
@@ -205,6 +207,8 @@ static u32 opb_write(struct fsi_master_aspeed *aspeed, uint32_t addr,
 	writel(0x1, base + OPB_IRQ_CLEAR);
 	writel(0x1, base + OPB_TRIGGER);
 
+	aspeed->last_was_fw_read = false;
+
 	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
 				(reg & OPB0_XFER_ACK_EN) != 0,
 				0, 10000);
@@ -224,6 +228,43 @@ static u32 opb_write(struct fsi_master_aspeed *aspeed, uint32_t addr,
 	return 0;
 }
 
+static int opb_read_repeat_fullword(struct fsi_master_aspeed *aspeed,
+		                    uint32_t addr, u32 *out)
+{
+	void __iomem *base = aspeed->base;
+	u32 result, reg;
+	int status, ret;
+
+	writel(addr, base + OPB0_FSI_ADDR);
+	writel(0x1, base + OPB_IRQ_CLEAR);
+	writel(0x1, base + OPB_TRIGGER);
+
+	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
+			   (reg & OPB0_XFER_ACK_EN) != 0,
+			   0, 10000);
+
+	status = readl(base + OPB0_STATUS);
+
+	result = readl(base + OPB0_FSI_DATA_R);
+
+	trace_fsi_master_aspeed_opb_read(addr, 4, result,
+			readl(base + OPB0_STATUS),
+			reg);
+
+	/* Return error when poll timed out */
+	if (ret)
+		return ret;
+
+	/* Command failed, master will reset */
+	if (status & STATUS_ERR_ACK)
+		return -EIO;
+
+	if (out)
+		memcpy(out, &result, 4);
+
+	return 0;
+}
+
 static int opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,
 		    size_t size, u32 *out)
 {
@@ -241,6 +282,9 @@ static int opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,
 	writel(0x1, base + OPB_IRQ_CLEAR);
 	writel(0x1, base + OPB_TRIGGER);
 
+	if (size == 4)
+		aspeed->last_was_fw_read = true;
+
 	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
 			   (reg & OPB0_XFER_ACK_EN) != 0,
 			   0, 10000);
@@ -311,7 +355,11 @@ static int aspeed_master_read(struct fsi_master *master, int link,
 		return -EINVAL;
 
 	addr += link * FSI_HUB_LINK_SIZE;
-	ret = opb_read(aspeed, fsi_base + addr, size, val);
+
+	if (aspeed->last_was_fw_read)
+		ret = opb_read_repeat_fullword(aspeed, fsi_base + addr, val);
+	else
+		ret = opb_read(aspeed, fsi_base + addr, size, val);
 
 	ret = check_errors(aspeed, ret);
 	if (ret)
-- 
2.23.0



More information about the openbmc mailing list