[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250427-pasemi-fixes-v3-2-af28568296c0@svenpeter.dev>
Date: Sun, 27 Apr 2025 11:30:44 +0000
From: Sven Peter via B4 Relay <devnull+sven.svenpeter.dev@...nel.org>
To: Janne Grunau <j@...nau.net>, Alyssa Rosenzweig <alyssa@...enzweig.io>,
Madhavan Srinivasan <maddy@...ux.ibm.com>,
Michael Ellerman <mpe@...erman.id.au>, Nicholas Piggin <npiggin@...il.com>,
Christophe Leroy <christophe.leroy@...roup.eu>,
Naveen N Rao <naveen@...nel.org>, Andi Shyti <andi.shyti@...nel.org>,
Neal Gompa <neal@...pa.dev>, Hector Martin <marcan@...can.st>
Cc: linuxppc-dev@...ts.ozlabs.org, asahi@...ts.linux.dev,
linux-arm-kernel@...ts.infradead.org, linux-i2c@...r.kernel.org,
linux-kernel@...r.kernel.org, Sven Peter <sven@...npeter.dev>
Subject: [PATCH v3 2/4] i2c: pasemi: Improve timeout handling
From: Sven Peter <sven@...npeter.dev>
The hardware (supposedly) has a 25ms timeout for clock stretching
and the driver uses 100ms which should be plenty.
The interrupt path however misses handling for errors while waiting for
the completion and the polling path uses an open-coded readx_poll_timeout.
Note that we drop reg_write(smbus, REG_SMSTA, status) while fixing those
issues here which will be done anyway whenever the next transaction starts
via pasemi_smb_clear.
Signed-off-by: Sven Peter <sven@...npeter.dev>
---
drivers/i2c/busses/i2c-pasemi-core.c | 41 +++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-pasemi-core.c
index 3f5571a90c1d268ea2a9d95285f1a5e47f0481ff..ee38e8a1e1f5d062384e85a2fd49d7da9257aacc 100644
--- a/drivers/i2c/busses/i2c-pasemi-core.c
+++ b/drivers/i2c/busses/i2c-pasemi-core.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -52,6 +53,12 @@
#define CTL_UJM BIT(8)
#define CTL_CLK_M GENMASK(7, 0)
+/*
+ * The hardware (supposedly) has a 25ms timeout for clock stretching, thus
+ * use 100ms here which should be plenty.
+ */
+#define PASEMI_TRANSFER_TIMEOUT_MS 100
+
static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
{
dev_dbg(smbus->dev, "smbus write reg %x val %08x\n", reg, val);
@@ -90,20 +97,36 @@ static void pasemi_smb_clear(struct pasemi_smbus *smbus)
static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
{
- int timeout = 100;
unsigned int status;
if (smbus->use_irq) {
reinit_completion(&smbus->irq_completion);
reg_write(smbus, REG_IMASK, SMSTA_XEN | SMSTA_MTN);
- wait_for_completion_timeout(&smbus->irq_completion, msecs_to_jiffies(100));
+ int ret = wait_for_completion_timeout(
+ &smbus->irq_completion,
+ msecs_to_jiffies(PASEMI_TRANSFER_TIMEOUT_MS));
reg_write(smbus, REG_IMASK, 0);
status = reg_read(smbus, REG_SMSTA);
+
+ if (ret < 0) {
+ dev_err(smbus->dev,
+ "Completion wait failed with %d, status 0x%08x\n",
+ ret, status);
+ return ret;
+ } else if (ret == 0) {
+ dev_err(smbus->dev, "Timeout, status 0x%08x\n", status);
+ return -ETIME;
+ }
} else {
- status = reg_read(smbus, REG_SMSTA);
- while (!(status & SMSTA_XEN) && timeout--) {
- msleep(1);
- status = reg_read(smbus, REG_SMSTA);
+ int ret = readx_poll_timeout(
+ ioread32, smbus->ioaddr + REG_SMSTA,
+ status, status & SMSTA_XEN,
+ USEC_PER_MSEC,
+ USEC_PER_MSEC * PASEMI_TRANSFER_TIMEOUT_MS);
+
+ if (ret < 0) {
+ dev_err(smbus->dev, "Timeout, status 0x%08x\n", status);
+ return -ETIME;
}
}
@@ -111,12 +134,6 @@ static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
if (status & SMSTA_MTN)
return -ENXIO;
- if (timeout < 0) {
- dev_warn(smbus->dev, "Timeout, status 0x%08x\n", status);
- reg_write(smbus, REG_SMSTA, status);
- return -ETIME;
- }
-
/* Clear XEN */
reg_write(smbus, REG_SMSTA, SMSTA_XEN);
--
2.34.1
Powered by blists - more mailing lists