* [PATCH 0/3] Add atomic transfer support to i2c-cadence
@ 2024-08-01 9:44 Manikanta Guntupalli
2024-08-01 9:44 ` [PATCH 1/3] i2c: cadence: Relocate cdns_i2c_runtime_suspend and cdns_i2c_runtime_resume to facilitate atomic mode Manikanta Guntupalli
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Manikanta Guntupalli @ 2024-08-01 9:44 UTC (permalink / raw)
To: git, andi.shyti, linux-arm-kernel, linux-i2c, linux-kernel
Cc: michal.simek, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk, Manikanta Guntupalli
This patch series adds atomic transfer support to the i2c-cadence
controller version 1.4.
Manikanta Guntupalli (3):
i2c: cadence: Relocate cdns_i2c_runtime_suspend and
cdns_i2c_runtime_resume to facilitate atomic mode
i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode
i2c: cadence: Add atomic transfer support for controller version 1.4
drivers/i2c/busses/i2c-cadence.c | 418 ++++++++++++++++++++++---------
1 file changed, 299 insertions(+), 119 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/3] i2c: cadence: Relocate cdns_i2c_runtime_suspend and cdns_i2c_runtime_resume to facilitate atomic mode
2024-08-01 9:44 [PATCH 0/3] Add atomic transfer support to i2c-cadence Manikanta Guntupalli
@ 2024-08-01 9:44 ` Manikanta Guntupalli
2024-09-10 13:24 ` Andi Shyti
2024-08-01 9:44 ` [PATCH 2/3] i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode Manikanta Guntupalli
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Manikanta Guntupalli @ 2024-08-01 9:44 UTC (permalink / raw)
To: git, andi.shyti, linux-arm-kernel, linux-i2c, linux-kernel
Cc: michal.simek, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk, Manikanta Guntupalli
Relocate cdns_i2c_runtime_suspend, cdns_i2c_runtime_resume and
cdns_i2c_init functions to avoid prototype statement in atomic
mode changes.
Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
---
drivers/i2c/busses/i2c-cadence.c | 120 +++++++++++++++----------------
1 file changed, 60 insertions(+), 60 deletions(-)
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 87b9ba95b2e1..d3f6ca2cb4d7 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -228,6 +228,66 @@ struct cdns_platform_data {
#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \
clk_rate_change_nb)
+/**
+ * cdns_i2c_init - Controller initialisation
+ * @id: Device private data structure
+ *
+ * Initialise the i2c controller.
+ *
+ */
+static void cdns_i2c_init(struct cdns_i2c *id)
+{
+ cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET);
+ /*
+ * Cadence I2C controller has a bug wherein it generates
+ * invalid read transaction after HW timeout in master receiver mode.
+ * HW timeout is not used by this driver and the interrupt is disabled.
+ * But the feature itself cannot be disabled. Hence maximum value
+ * is written to this register to reduce the chances of error.
+ */
+ cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+}
+
+/**
+ * cdns_i2c_runtime_suspend - Runtime suspend method for the driver
+ * @dev: Address of the platform_device structure
+ *
+ * Put the driver into low power mode.
+ *
+ * Return: 0 always
+ */
+static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
+{
+ struct cdns_i2c *xi2c = dev_get_drvdata(dev);
+
+ clk_disable(xi2c->clk);
+
+ return 0;
+}
+
+/**
+ * cdns_i2c_runtime_resume - Runtime resume
+ * @dev: Address of the platform_device structure
+ *
+ * Runtime resume callback.
+ *
+ * Return: 0 on success and error value on error
+ */
+static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
+{
+ struct cdns_i2c *xi2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(xi2c->clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+ cdns_i2c_init(xi2c);
+
+ return 0;
+}
+
/**
* cdns_i2c_clear_bus_hold - Clear bus hold bit
* @id: Pointer to driver data struct
@@ -1158,23 +1218,6 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
}
}
-/**
- * cdns_i2c_runtime_suspend - Runtime suspend method for the driver
- * @dev: Address of the platform_device structure
- *
- * Put the driver into low power mode.
- *
- * Return: 0 always
- */
-static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
-{
- struct cdns_i2c *xi2c = dev_get_drvdata(dev);
-
- clk_disable(xi2c->clk);
-
- return 0;
-}
-
static int __maybe_unused cdns_i2c_suspend(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
@@ -1187,49 +1230,6 @@ static int __maybe_unused cdns_i2c_suspend(struct device *dev)
return 0;
}
-/**
- * cdns_i2c_init - Controller initialisation
- * @id: Device private data structure
- *
- * Initialise the i2c controller.
- *
- */
-static void cdns_i2c_init(struct cdns_i2c *id)
-{
- cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET);
- /*
- * Cadence I2C controller has a bug wherein it generates
- * invalid read transaction after HW timeout in master receiver mode.
- * HW timeout is not used by this driver and the interrupt is disabled.
- * But the feature itself cannot be disabled. Hence maximum value
- * is written to this register to reduce the chances of error.
- */
- cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
-}
-
-/**
- * cdns_i2c_runtime_resume - Runtime resume
- * @dev: Address of the platform_device structure
- *
- * Runtime resume callback.
- *
- * Return: 0 on success and error value on error
- */
-static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
-{
- struct cdns_i2c *xi2c = dev_get_drvdata(dev);
- int ret;
-
- ret = clk_enable(xi2c->clk);
- if (ret) {
- dev_err(dev, "Cannot enable clock.\n");
- return ret;
- }
- cdns_i2c_init(xi2c);
-
- return 0;
-}
-
static int __maybe_unused cdns_i2c_resume(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
--
2.25.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/3] i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode
2024-08-01 9:44 [PATCH 0/3] Add atomic transfer support to i2c-cadence Manikanta Guntupalli
2024-08-01 9:44 ` [PATCH 1/3] i2c: cadence: Relocate cdns_i2c_runtime_suspend and cdns_i2c_runtime_resume to facilitate atomic mode Manikanta Guntupalli
@ 2024-08-01 9:44 ` Manikanta Guntupalli
2024-09-10 13:25 ` Andi Shyti
2024-08-01 9:44 ` [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4 Manikanta Guntupalli
2024-09-02 8:27 ` [PATCH 0/3] Add atomic transfer support to i2c-cadence Michal Simek
3 siblings, 1 reply; 10+ messages in thread
From: Manikanta Guntupalli @ 2024-08-01 9:44 UTC (permalink / raw)
To: git, andi.shyti, linux-arm-kernel, linux-i2c, linux-kernel
Cc: michal.simek, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk, Manikanta Guntupalli
The cdns_i2c_master_xfer function has been refactored to separate
the common code. This change facilitates better support for atomic
mode operations by isolating the shared logic.
Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
---
drivers/i2c/busses/i2c-cadence.c | 100 ++++++++++++++++---------------
1 file changed, 53 insertions(+), 47 deletions(-)
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index d3f6ca2cb4d7..e689448d229f 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -866,46 +866,14 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
return 0;
}
-/**
- * cdns_i2c_master_xfer - The main i2c transfer function
- * @adap: pointer to the i2c adapter driver instance
- * @msgs: pointer to the i2c message structure
- * @num: the number of messages to transfer
- *
- * Initiates the send/recv activity based on the transfer message received.
- *
- * Return: number of msgs processed on success, negative error otherwise
- */
-static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
- int num)
+static int cdns_i2c_master_common_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs,
+ int num)
{
int ret, count;
u32 reg;
struct cdns_i2c *id = adap->algo_data;
bool hold_quirk;
-#if IS_ENABLED(CONFIG_I2C_SLAVE)
- bool change_role = false;
-#endif
-
- ret = pm_runtime_resume_and_get(id->dev);
- if (ret < 0)
- return ret;
-
-#if IS_ENABLED(CONFIG_I2C_SLAVE)
- /* Check i2c operating mode and switch if possible */
- if (id->dev_mode == CDNS_I2C_MODE_SLAVE) {
- if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) {
- ret = -EAGAIN;
- goto out;
- }
-
- /* Set mode to master */
- cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id);
-
- /* Mark flag to change role once xfer is completed */
- change_role = true;
- }
-#endif
/* Check if the bus is free */
@@ -917,7 +885,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
ret = -EAGAIN;
if (id->adap.bus_recovery_info)
i2c_recover_bus(adap);
- goto out;
+ return ret;
}
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
@@ -937,8 +905,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
if (msgs[count].flags & I2C_M_RD) {
dev_warn(adap->dev.parent,
"Can't do repeated start after a receive message\n");
- ret = -EOPNOTSUPP;
- goto out;
+ return -EOPNOTSUPP;
}
}
id->bus_hold_flag = 1;
@@ -956,26 +923,65 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
ret = cdns_i2c_process_msg(id, msgs, adap);
if (ret)
- goto out;
+ return ret;
/* Report the other error interrupts to application */
if (id->err_status) {
cdns_i2c_master_reset(adap);
- if (id->err_status & CDNS_I2C_IXR_NACK) {
- ret = -ENXIO;
- goto out;
- }
- ret = -EIO;
- goto out;
+ if (id->err_status & CDNS_I2C_IXR_NACK)
+ return -ENXIO;
+
+ return -EIO;
}
}
+ return 0;
+}
- ret = num;
+/**
+ * cdns_i2c_master_xfer - The main i2c transfer function
+ * @adap: pointer to the i2c adapter driver instance
+ * @msgs: pointer to the i2c message structure
+ * @num: the number of messages to transfer
+ *
+ * Initiates the send/recv activity based on the transfer message received.
+ *
+ * Return: number of msgs processed on success, negative error otherwise
+ */
+static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int ret;
+ struct cdns_i2c *id = adap->algo_data;
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ bool change_role = false;
+#endif
-out:
+ ret = pm_runtime_resume_and_get(id->dev);
+ if (ret < 0)
+ return ret;
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /* Check i2c operating mode and switch if possible */
+ if (id->dev_mode == CDNS_I2C_MODE_SLAVE) {
+ if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ /* Set mode to master */
+ cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id);
+
+ /* Mark flag to change role once xfer is completed */
+ change_role = true;
+ }
+#endif
+ ret = cdns_i2c_master_common_xfer(adap, msgs, num);
+ if (!ret)
+ ret = num;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
+out:
/* Switch i2c mode to slave */
if (change_role)
cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id);
--
2.25.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4
2024-08-01 9:44 [PATCH 0/3] Add atomic transfer support to i2c-cadence Manikanta Guntupalli
2024-08-01 9:44 ` [PATCH 1/3] i2c: cadence: Relocate cdns_i2c_runtime_suspend and cdns_i2c_runtime_resume to facilitate atomic mode Manikanta Guntupalli
2024-08-01 9:44 ` [PATCH 2/3] i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode Manikanta Guntupalli
@ 2024-08-01 9:44 ` Manikanta Guntupalli
2024-09-10 13:15 ` Andi Shyti
2024-09-02 8:27 ` [PATCH 0/3] Add atomic transfer support to i2c-cadence Michal Simek
3 siblings, 1 reply; 10+ messages in thread
From: Manikanta Guntupalli @ 2024-08-01 9:44 UTC (permalink / raw)
To: git, andi.shyti, linux-arm-kernel, linux-i2c, linux-kernel
Cc: michal.simek, radhey.shyam.pandey, srinivas.goud,
shubhrajyoti.datta, manion05gk, Manikanta Guntupalli
Rework the read and write code paths in the driver to support operation
in atomic contexts in master mode. This change does not apply to slave
mode because there is no way to handle interruptions in that context.
Adjust the message timeout to include some extra time. For non-atomic
contexts, 500 ms is added to the timeout. For atomic contexts,
2000 ms is added because transfers happen in polled mode, requiring
more time to account for the polling overhead.
Similar changes have been implemented in other drivers, including:
commit 3a5ee18d2a32 ("i2c: imx: implement master_xfer_atomic callback")
commit 445094c8a9fb ("i2c: exynos5: add support for atomic transfers")
commit ede2299f7101 ("i2c: tegra: Support atomic transfers")
commit fe402bd09049 ("i2c: meson: implement the master_xfer_atomic
callback")
Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
---
drivers/i2c/busses/i2c-cadence.c | 202 ++++++++++++++++++++++++++++---
1 file changed, 188 insertions(+), 14 deletions(-)
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index e689448d229f..8b8433faf959 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -129,6 +129,7 @@
#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
#define CDNS_I2C_POLL_US 100000
+#define CDNS_I2C_POLL_US_ATOMIC 10
#define CDNS_I2C_TIMEOUT_US 500000
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
@@ -189,6 +190,8 @@ enum cdns_i2c_slave_state {
* @slave_state: I2C Slave state(idle/read/write).
* @fifo_depth: The depth of the transfer FIFO
* @transfer_size: The maximum number of bytes in one transfer
+ * @atomic: Mode of transfer
+ * @err_status_atomic: Error status in atomic mode
*/
struct cdns_i2c {
struct device *dev;
@@ -219,6 +222,8 @@ struct cdns_i2c {
#endif
u32 fifo_depth;
unsigned int transfer_size;
+ bool atomic;
+ int err_status_atomic;
};
struct cdns_platform_data {
@@ -256,7 +261,7 @@ static void cdns_i2c_init(struct cdns_i2c *id)
*
* Return: 0 always
*/
-static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
+static int cdns_i2c_runtime_suspend(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
@@ -273,7 +278,7 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
*
* Return: 0 on success and error value on error
*/
-static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
+static int cdns_i2c_runtime_resume(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
int ret;
@@ -621,6 +626,90 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
return cdns_i2c_master_isr(ptr);
}
+static bool cdns_i2c_error_check(struct cdns_i2c *id)
+{
+ unsigned int isr_status;
+
+ id->err_status = 0;
+
+ isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status & CDNS_I2C_IXR_ERR_INTR_MASK, CDNS_I2C_ISR_OFFSET);
+
+ id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
+ if (id->err_status)
+ return true;
+
+ return false;
+}
+
+static void cdns_i2c_mrecv_atomic(struct cdns_i2c *id)
+{
+ bool updatetx;
+
+ while (id->recv_count > 0) {
+ /*
+ * Check if transfer size register needs to be updated again for a
+ * large data receive operation.
+ */
+ updatetx = id->recv_count > id->curr_recv_count;
+
+ while (id->curr_recv_count > 0) {
+ if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) {
+ *id->p_recv_buf++ = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+ id->recv_count--;
+ id->curr_recv_count--;
+
+ /*
+ * Clear hold bit that was set for FIFO control
+ * if RX data left is less than or equal to
+ * FIFO DEPTH unless repeated start is selected
+ */
+ if (id->recv_count <= id->fifo_depth && !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+ }
+ if (cdns_i2c_error_check(id))
+ return;
+ if (cdns_is_holdquirk(id, updatetx))
+ break;
+ }
+
+ /*
+ * The controller sends NACK to the slave when transfer size
+ * register reaches zero without considering the HOLD bit.
+ * This workaround is implemented for large data transfers to
+ * maintain transfer size non-zero while performing a large
+ * receive operation.
+ */
+ if (cdns_is_holdquirk(id, updatetx)) {
+ /* wait while fifo is full */
+ while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
+ (id->curr_recv_count - id->fifo_depth))
+ ;
+
+ /*
+ * Check number of bytes to be received against maximum
+ * transfer size and update register accordingly.
+ */
+ if (((int)(id->recv_count) - id->fifo_depth) >
+ id->transfer_size) {
+ cdns_i2c_writereg(id->transfer_size,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = id->transfer_size +
+ id->fifo_depth;
+ } else {
+ cdns_i2c_writereg(id->recv_count -
+ id->fifo_depth,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = id->recv_count;
+ }
+ }
+ }
+
+ /* Clear hold (if not repeated start) */
+ if (!id->recv_count && !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
+}
+
/**
* cdns_i2c_mrecv - Prepare and start a master receive operation
* @id: pointer to the i2c device structure
@@ -715,7 +804,34 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
}
- cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+ if (!id->atomic)
+ cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+ else
+ cdns_i2c_mrecv_atomic(id);
+}
+
+static void cdns_i2c_msend_rem_atomic(struct cdns_i2c *id)
+{
+ unsigned int avail_bytes;
+ unsigned int bytes_to_send;
+
+ while (id->send_count) {
+ avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+ if (id->send_count > avail_bytes)
+ bytes_to_send = avail_bytes;
+ else
+ bytes_to_send = id->send_count;
+
+ while (bytes_to_send--) {
+ cdns_i2c_writereg((*id->p_send_buf++), CDNS_I2C_DATA_OFFSET);
+ id->send_count--;
+ }
+ if (cdns_i2c_error_check(id))
+ return;
+ }
+
+ if (!id->send_count && !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
}
/**
@@ -778,7 +894,12 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
CDNS_I2C_ADDR_OFFSET);
- cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+ if (!id->atomic) {
+ cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+ } else {
+ if (id->send_count > 0)
+ cdns_i2c_msend_rem_atomic(id);
+ }
}
/**
@@ -818,7 +939,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
id->p_msg = msg;
id->err_status = 0;
- reinit_completion(&id->xfer_done);
+ if (!id->atomic)
+ reinit_completion(&id->xfer_done);
/* Check for the TEN Bit mode on each msg */
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
@@ -841,13 +963,24 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
/* Minimal time to execute this message */
msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk);
/* Plus some wiggle room */
- msg_timeout += msecs_to_jiffies(500);
+ if (!id->atomic)
+ msg_timeout += msecs_to_jiffies(500);
+ else
+ msg_timeout += msecs_to_jiffies(2000);
if (msg_timeout < adap->timeout)
msg_timeout = adap->timeout;
- /* Wait for the signal of completion */
- time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
+ if (!id->atomic) {
+ /* Wait for the signal of completion */
+ time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
+ } else {
+ /* 0 is success, -ETIMEDOUT is error */
+ time_left = !readl_poll_timeout_atomic(id->membase + CDNS_I2C_ISR_OFFSET,
+ reg, (reg & CDNS_I2C_IXR_COMP),
+ CDNS_I2C_POLL_US_ATOMIC, msg_timeout);
+ }
+
if (time_left == 0) {
cdns_i2c_master_reset(adap);
return -ETIMEDOUT;
@@ -876,11 +1009,16 @@ static int cdns_i2c_master_common_xfer(struct i2c_adapter *adap,
bool hold_quirk;
/* Check if the bus is free */
-
- ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET,
- reg,
- !(reg & CDNS_I2C_SR_BA),
- CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
+ if (!id->atomic)
+ ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET,
+ reg,
+ !(reg & CDNS_I2C_SR_BA),
+ CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
+ else
+ ret = readl_poll_timeout_atomic(id->membase + CDNS_I2C_SR_OFFSET,
+ reg,
+ !(reg & CDNS_I2C_SR_BA),
+ CDNS_I2C_POLL_US_ATOMIC, CDNS_I2C_TIMEOUT_US);
if (ret) {
ret = -EAGAIN;
if (id->adap.bus_recovery_info)
@@ -926,7 +1064,7 @@ static int cdns_i2c_master_common_xfer(struct i2c_adapter *adap,
return ret;
/* Report the other error interrupts to application */
- if (id->err_status) {
+ if (id->err_status || id->err_status_atomic) {
cdns_i2c_master_reset(adap);
if (id->err_status & CDNS_I2C_IXR_NACK)
@@ -992,6 +1130,41 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
return ret;
}
+/**
+ * cdns_i2c_master_xfer_atomic - The i2c transfer function in atomic mode
+ * @adap: pointer to the i2c adapter driver instance
+ * @msgs: pointer to the i2c message structure
+ * @num: the number of messages to transfer
+ *
+ * Return: number of msgs processed on success, negative error otherwise
+ */
+static int cdns_i2c_master_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int ret;
+ struct cdns_i2c *id = adap->algo_data;
+
+ ret = cdns_i2c_runtime_resume(id->dev);
+ if (ret)
+ return ret;
+
+ if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) {
+ dev_warn(id->adap.dev.parent,
+ "Atomic xfer not supported for version 1.0\n");
+ return 0;
+ }
+
+ id->atomic = true;
+ ret = cdns_i2c_master_common_xfer(adap, msgs, num);
+ if (!ret)
+ ret = num;
+
+ id->atomic = false;
+ cdns_i2c_runtime_suspend(id->dev);
+
+ return ret;
+}
+
/**
* cdns_i2c_func - Returns the supported features of the I2C driver
* @adap: pointer to the i2c adapter structure
@@ -1056,6 +1229,7 @@ static int cdns_unreg_slave(struct i2c_client *slave)
static const struct i2c_algorithm cdns_i2c_algo = {
.master_xfer = cdns_i2c_master_xfer,
+ .master_xfer_atomic = cdns_i2c_master_xfer_atomic,
.functionality = cdns_i2c_func,
#if IS_ENABLED(CONFIG_I2C_SLAVE)
.reg_slave = cdns_reg_slave,
--
2.25.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/3] Add atomic transfer support to i2c-cadence
2024-08-01 9:44 [PATCH 0/3] Add atomic transfer support to i2c-cadence Manikanta Guntupalli
` (2 preceding siblings ...)
2024-08-01 9:44 ` [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4 Manikanta Guntupalli
@ 2024-09-02 8:27 ` Michal Simek
3 siblings, 0 replies; 10+ messages in thread
From: Michal Simek @ 2024-09-02 8:27 UTC (permalink / raw)
To: Manikanta Guntupalli, git, andi.shyti, linux-arm-kernel,
linux-i2c, linux-kernel
Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta, manion05gk
On 8/1/24 11:44, Manikanta Guntupalli wrote:
> This patch series adds atomic transfer support to the i2c-cadence
> controller version 1.4.
>
> Manikanta Guntupalli (3):
> i2c: cadence: Relocate cdns_i2c_runtime_suspend and
> cdns_i2c_runtime_resume to facilitate atomic mode
> i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode
> i2c: cadence: Add atomic transfer support for controller version 1.4
>
> drivers/i2c/busses/i2c-cadence.c | 418 ++++++++++++++++++++++---------
> 1 file changed, 299 insertions(+), 119 deletions(-)
>
Acked-by: Michal Simek <michal.simek@amd.com>
Thanks,
Michal
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4
2024-08-01 9:44 ` [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4 Manikanta Guntupalli
@ 2024-09-10 13:15 ` Andi Shyti
2024-09-11 7:26 ` Guntupalli, Manikanta
0 siblings, 1 reply; 10+ messages in thread
From: Andi Shyti @ 2024-09-10 13:15 UTC (permalink / raw)
To: Manikanta Guntupalli
Cc: git, linux-arm-kernel, linux-i2c, linux-kernel, michal.simek,
radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk
Hi Manikata,
Sorry for the delay in reviewing this patch. Looks good, just a
few notes below.
...
> +static bool cdns_i2c_error_check(struct cdns_i2c *id)
> +{
> + unsigned int isr_status;
> +
> + id->err_status = 0;
> +
> + isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
> + cdns_i2c_writereg(isr_status & CDNS_I2C_IXR_ERR_INTR_MASK, CDNS_I2C_ISR_OFFSET);
> +
> + id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
> + if (id->err_status)
> + return true;
> +
> + return false;
return !!id->err_status;
> +}
> +
> +static void cdns_i2c_mrecv_atomic(struct cdns_i2c *id)
> +{
> + bool updatetx;
Please move the udatex declaration inside the while loop.
> + while (id->recv_count > 0) {
> + /*
> + * Check if transfer size register needs to be updated again for a
> + * large data receive operation.
> + */
> + updatetx = id->recv_count > id->curr_recv_count;
> +
> + while (id->curr_recv_count > 0) {
> + if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) {
> + *id->p_recv_buf++ = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
Can you please expand this operation to be a bit more clearer,
without asking people to check on operation precedence?
> + id->recv_count--;
> + id->curr_recv_count--;
> +
> + /*
> + * Clear hold bit that was set for FIFO control
> + * if RX data left is less than or equal to
> + * FIFO DEPTH unless repeated start is selected
mmhhh... the lack of punctuation makes this comment difficult to
understand.
> + */
> + if (id->recv_count <= id->fifo_depth && !id->bus_hold_flag)
> + cdns_i2c_clear_bus_hold(id);
> + }
> + if (cdns_i2c_error_check(id))
> + return;
> + if (cdns_is_holdquirk(id, updatetx))
> + break;
> + }
> +
> + /*
> + * The controller sends NACK to the slave when transfer size
/slave/target/
> + * register reaches zero without considering the HOLD bit.
> + * This workaround is implemented for large data transfers to
> + * maintain transfer size non-zero while performing a large
> + * receive operation.
> + */
> + if (cdns_is_holdquirk(id, updatetx)) {
> + /* wait while fifo is full */
> + while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
> + (id->curr_recv_count - id->fifo_depth))
> + ;
> +
> + /*
> + * Check number of bytes to be received against maximum
> + * transfer size and update register accordingly.
> + */
> + if (((int)(id->recv_count) - id->fifo_depth) >
The cast is not needed here.
> + id->transfer_size) {
> + cdns_i2c_writereg(id->transfer_size,
> + CDNS_I2C_XFER_SIZE_OFFSET);
> + id->curr_recv_count = id->transfer_size +
> + id->fifo_depth;
> + } else {
> + cdns_i2c_writereg(id->recv_count -
> + id->fifo_depth,
> + CDNS_I2C_XFER_SIZE_OFFSET);
> + id->curr_recv_count = id->recv_count;
> + }
> + }
> + }
> +
> + /* Clear hold (if not repeated start) */
> + if (!id->recv_count && !id->bus_hold_flag)
> + cdns_i2c_clear_bus_hold(id);
> +}
> +
> /**
> * cdns_i2c_mrecv - Prepare and start a master receive operation
> * @id: pointer to the i2c device structure
> @@ -715,7 +804,34 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
> }
>
> - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
> + if (!id->atomic)
> + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
> + else
> + cdns_i2c_mrecv_atomic(id);
> +}
> +
> +static void cdns_i2c_msend_rem_atomic(struct cdns_i2c *id)
> +{
> + unsigned int avail_bytes;
> + unsigned int bytes_to_send;
Please move these inside the while.
> +
> + while (id->send_count) {
> + avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
> + if (id->send_count > avail_bytes)
> + bytes_to_send = avail_bytes;
> + else
> + bytes_to_send = id->send_count;
> +
> + while (bytes_to_send--) {
> + cdns_i2c_writereg((*id->p_send_buf++), CDNS_I2C_DATA_OFFSET);
> + id->send_count--;
> + }
> + if (cdns_i2c_error_check(id))
> + return;
> + }
> +
> + if (!id->send_count && !id->bus_hold_flag)
> + cdns_i2c_clear_bus_hold(id);
> }
>
> /**
> @@ -778,7 +894,12 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
> cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
> CDNS_I2C_ADDR_OFFSET);
>
> - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
> + if (!id->atomic) {
> + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
> + } else {
> + if (id->send_count > 0)
If you do:
} else if (id->send_count > 0) {
we save a level of indentation.
> + cdns_i2c_msend_rem_atomic(id);
> + }
> }
>
> /**
> @@ -818,7 +939,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
>
> id->p_msg = msg;
> id->err_status = 0;
> - reinit_completion(&id->xfer_done);
> + if (!id->atomic)
> + reinit_completion(&id->xfer_done);
>
> /* Check for the TEN Bit mode on each msg */
> reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
> @@ -841,13 +963,24 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
> /* Minimal time to execute this message */
> msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk);
> /* Plus some wiggle room */
> - msg_timeout += msecs_to_jiffies(500);
> + if (!id->atomic)
> + msg_timeout += msecs_to_jiffies(500);
> + else
> + msg_timeout += msecs_to_jiffies(2000);
You explained this in the commit log, can you add it in a
comment, as well?
>
> if (msg_timeout < adap->timeout)
> msg_timeout = adap->timeout;
>
> - /* Wait for the signal of completion */
> - time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
> + if (!id->atomic) {
> + /* Wait for the signal of completion */
> + time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
> + } else {
> + /* 0 is success, -ETIMEDOUT is error */
> + time_left = !readl_poll_timeout_atomic(id->membase + CDNS_I2C_ISR_OFFSET,
> + reg, (reg & CDNS_I2C_IXR_COMP),
> + CDNS_I2C_POLL_US_ATOMIC, msg_timeout);
> + }
You can merge this if/else with the one above, to save some code.
> +
Thanks,
Andi
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] i2c: cadence: Relocate cdns_i2c_runtime_suspend and cdns_i2c_runtime_resume to facilitate atomic mode
2024-08-01 9:44 ` [PATCH 1/3] i2c: cadence: Relocate cdns_i2c_runtime_suspend and cdns_i2c_runtime_resume to facilitate atomic mode Manikanta Guntupalli
@ 2024-09-10 13:24 ` Andi Shyti
0 siblings, 0 replies; 10+ messages in thread
From: Andi Shyti @ 2024-09-10 13:24 UTC (permalink / raw)
To: Manikanta Guntupalli
Cc: git, linux-arm-kernel, linux-i2c, linux-kernel, michal.simek,
radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk
Hi Manikanta,
On Thu, Aug 01, 2024 at 03:14:06PM GMT, Manikanta Guntupalli wrote:
> Relocate cdns_i2c_runtime_suspend, cdns_i2c_runtime_resume and
> cdns_i2c_init functions to avoid prototype statement in atomic
> mode changes.
>
> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Thanks,
Andi
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode
2024-08-01 9:44 ` [PATCH 2/3] i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode Manikanta Guntupalli
@ 2024-09-10 13:25 ` Andi Shyti
0 siblings, 0 replies; 10+ messages in thread
From: Andi Shyti @ 2024-09-10 13:25 UTC (permalink / raw)
To: Manikanta Guntupalli
Cc: git, linux-arm-kernel, linux-i2c, linux-kernel, michal.simek,
radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
manion05gk
Hi Manikanta,
On Thu, Aug 01, 2024 at 03:14:07PM GMT, Manikanta Guntupalli wrote:
> The cdns_i2c_master_xfer function has been refactored to separate
> the common code. This change facilitates better support for atomic
> mode operations by isolating the shared logic.
>
> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Thanks,
Andi
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4
2024-09-10 13:15 ` Andi Shyti
@ 2024-09-11 7:26 ` Guntupalli, Manikanta
2024-09-11 8:24 ` Andi Shyti
0 siblings, 1 reply; 10+ messages in thread
From: Guntupalli, Manikanta @ 2024-09-11 7:26 UTC (permalink / raw)
To: Andi Shyti
Cc: git (AMD-Xilinx),
linux-arm-kernel, linux-i2c, linux-kernel, Simek, Michal, Pandey,
Radhey Shyam, Goud, Srinivas, Datta, Shubhrajyoti, manion05gk
Hi Andi,
Thank you for taking the time to review our patch. We appreciate your detailed feedback and will address and fix all the review comments, except for the last one, which we believe may not be applicable.
Please find our inline replies to your comments below for further clarification.
> -----Original Message-----
> From: Andi Shyti <andi.shyti@kernel.org>
> Sent: Tuesday, September 10, 2024 6:46 PM
> To: Guntupalli, Manikanta <manikanta.guntupalli@amd.com>
> Cc: git (AMD-Xilinx) <git@amd.com>; linux-arm-kernel@lists.infradead.org; linux-
> i2c@vger.kernel.org; linux-kernel@vger.kernel.org; Simek, Michal
> <michal.simek@amd.com>; Pandey, Radhey Shyam
> <radhey.shyam.pandey@amd.com>; Goud, Srinivas <srinivas.goud@amd.com>;
> Datta, Shubhrajyoti <shubhrajyoti.datta@amd.com>; manion05gk@gmail.com
> Subject: Re: [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller
> version 1.4
>
> Hi Manikata,
>
> Sorry for the delay in reviewing this patch. Looks good, just a few notes below.
>
> ...
>
> > +static bool cdns_i2c_error_check(struct cdns_i2c *id) {
> > + unsigned int isr_status;
> > +
> > + id->err_status = 0;
> > +
> > + isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
> > + cdns_i2c_writereg(isr_status & CDNS_I2C_IXR_ERR_INTR_MASK,
> > +CDNS_I2C_ISR_OFFSET);
> > +
> > + id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
> > + if (id->err_status)
> > + return true;
> > +
> > + return false;
>
> return !!id->err_status;
We will fix.
>
> > +}
> > +
> > +static void cdns_i2c_mrecv_atomic(struct cdns_i2c *id) {
> > + bool updatetx;
>
> Please move the udatex declaration inside the while loop.
We will fix.
>
> > + while (id->recv_count > 0) {
> > + /*
> > + * Check if transfer size register needs to be updated again for a
> > + * large data receive operation.
> > + */
> > + updatetx = id->recv_count > id->curr_recv_count;
> > +
> > + while (id->curr_recv_count > 0) {
> > + if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
> CDNS_I2C_SR_RXDV) {
> > + *id->p_recv_buf++ =
> cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
>
> Can you please expand this operation to be a bit more clearer, without asking
> people to check on operation precedence?
We will fix.
>
> > + id->recv_count--;
> > + id->curr_recv_count--;
> > +
> > + /*
> > + * Clear hold bit that was set for FIFO control
> > + * if RX data left is less than or equal to
> > + * FIFO DEPTH unless repeated start is selected
>
> mmhhh... the lack of punctuation makes this comment difficult to understand.
Sorry, we will update.
>
> > + */
> > + if (id->recv_count <= id->fifo_depth && !id-
> >bus_hold_flag)
> > + cdns_i2c_clear_bus_hold(id);
> > + }
> > + if (cdns_i2c_error_check(id))
> > + return;
> > + if (cdns_is_holdquirk(id, updatetx))
> > + break;
> > + }
> > +
> > + /*
> > + * The controller sends NACK to the slave when transfer size
>
> /slave/target/
We will update.
>
> > + * register reaches zero without considering the HOLD bit.
> > + * This workaround is implemented for large data transfers to
> > + * maintain transfer size non-zero while performing a large
> > + * receive operation.
> > + */
> > + if (cdns_is_holdquirk(id, updatetx)) {
> > + /* wait while fifo is full */
> > + while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
> > + (id->curr_recv_count - id->fifo_depth))
> > + ;
> > +
> > + /*
> > + * Check number of bytes to be received against maximum
> > + * transfer size and update register accordingly.
> > + */
> > + if (((int)(id->recv_count) - id->fifo_depth) >
>
> The cast is not needed here.
We will fix.
>
> > + id->transfer_size) {
> > + cdns_i2c_writereg(id->transfer_size,
> > + CDNS_I2C_XFER_SIZE_OFFSET);
> > + id->curr_recv_count = id->transfer_size +
> > + id->fifo_depth;
> > + } else {
> > + cdns_i2c_writereg(id->recv_count -
> > + id->fifo_depth,
> > + CDNS_I2C_XFER_SIZE_OFFSET);
> > + id->curr_recv_count = id->recv_count;
> > + }
> > + }
> > + }
> > +
> > + /* Clear hold (if not repeated start) */
> > + if (!id->recv_count && !id->bus_hold_flag)
> > + cdns_i2c_clear_bus_hold(id);
> > +}
> > +
> > /**
> > * cdns_i2c_mrecv - Prepare and start a master receive operation
> > * @id: pointer to the i2c device structure
> > @@ -715,7 +804,34 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> > cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
> > }
> >
> > - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK,
> CDNS_I2C_IER_OFFSET);
> > + if (!id->atomic)
> > + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK,
> CDNS_I2C_IER_OFFSET);
> > + else
> > + cdns_i2c_mrecv_atomic(id);
> > +}
> > +
> > +static void cdns_i2c_msend_rem_atomic(struct cdns_i2c *id) {
> > + unsigned int avail_bytes;
> > + unsigned int bytes_to_send;
>
> Please move these inside the while.
We will update.
>
> > +
> > + while (id->send_count) {
> > + avail_bytes = id->fifo_depth -
> cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
> > + if (id->send_count > avail_bytes)
> > + bytes_to_send = avail_bytes;
> > + else
> > + bytes_to_send = id->send_count;
> > +
> > + while (bytes_to_send--) {
> > + cdns_i2c_writereg((*id->p_send_buf++),
> CDNS_I2C_DATA_OFFSET);
> > + id->send_count--;
> > + }
> > + if (cdns_i2c_error_check(id))
> > + return;
> > + }
> > +
> > + if (!id->send_count && !id->bus_hold_flag)
> > + cdns_i2c_clear_bus_hold(id);
> > }
> >
> > /**
> > @@ -778,7 +894,12 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
> > cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
> > CDNS_I2C_ADDR_OFFSET);
> >
> > - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK,
> CDNS_I2C_IER_OFFSET);
> > + if (!id->atomic) {
> > + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK,
> CDNS_I2C_IER_OFFSET);
> > + } else {
> > + if (id->send_count > 0)
>
> If you do:
>
> } else if (id->send_count > 0) {
>
> we save a level of indentation.
We will fix.
>
> > + cdns_i2c_msend_rem_atomic(id);
> > + }
> > }
> >
> > /**
> > @@ -818,7 +939,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c
> > *id, struct i2c_msg *msg,
> >
> > id->p_msg = msg;
> > id->err_status = 0;
> > - reinit_completion(&id->xfer_done);
> > + if (!id->atomic)
> > + reinit_completion(&id->xfer_done);
> >
> > /* Check for the TEN Bit mode on each msg */
> > reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
> > @@ -841,13 +963,24 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id,
> struct i2c_msg *msg,
> > /* Minimal time to execute this message */
> > msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id-
> >i2c_clk);
> > /* Plus some wiggle room */
> > - msg_timeout += msecs_to_jiffies(500);
> > + if (!id->atomic)
> > + msg_timeout += msecs_to_jiffies(500);
> > + else
> > + msg_timeout += msecs_to_jiffies(2000);
>
> You explained this in the commit log, can you add it in a comment, as well?
We will update.
>
> >
> > if (msg_timeout < adap->timeout)
> > msg_timeout = adap->timeout;
> >
> > - /* Wait for the signal of completion */
> > - time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
> > + if (!id->atomic) {
> > + /* Wait for the signal of completion */
> > + time_left = wait_for_completion_timeout(&id->xfer_done,
> msg_timeout);
> > + } else {
> > + /* 0 is success, -ETIMEDOUT is error */
> > + time_left = !readl_poll_timeout_atomic(id->membase +
> CDNS_I2C_ISR_OFFSET,
> > + reg, (reg & CDNS_I2C_IXR_COMP),
> > + CDNS_I2C_POLL_US_ATOMIC,
> msg_timeout);
> > + }
>
> You can merge this if/else with the one above, to save some code.
Thank you for your suggestion to merge the if/else blocks to streamline the code. We have considered this approach; however, merging them would necessitate duplicating the following lines in both the if and else blocks:
if (msg_timeout < adap->timeout)
msg_timeout = adap->timeout;
Thanks,
Manikanta.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4
2024-09-11 7:26 ` Guntupalli, Manikanta
@ 2024-09-11 8:24 ` Andi Shyti
0 siblings, 0 replies; 10+ messages in thread
From: Andi Shyti @ 2024-09-11 8:24 UTC (permalink / raw)
To: Guntupalli, Manikanta
Cc: git (AMD-Xilinx),
linux-arm-kernel, linux-i2c, linux-kernel, Simek, Michal, Pandey,
Radhey Shyam, Goud, Srinivas, Datta, Shubhrajyoti, manion05gk
Hi Manikanta,
> > > if (msg_timeout < adap->timeout)
> > > msg_timeout = adap->timeout;
> > >
> > > - /* Wait for the signal of completion */
> > > - time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
> > > + if (!id->atomic) {
> > > + /* Wait for the signal of completion */
> > > + time_left = wait_for_completion_timeout(&id->xfer_done,
> > msg_timeout);
> > > + } else {
> > > + /* 0 is success, -ETIMEDOUT is error */
> > > + time_left = !readl_poll_timeout_atomic(id->membase +
> > CDNS_I2C_ISR_OFFSET,
> > > + reg, (reg & CDNS_I2C_IXR_COMP),
> > > + CDNS_I2C_POLL_US_ATOMIC,
> > msg_timeout);
> > > + }
> >
> > You can merge this if/else with the one above, to save some code.
> Thank you for your suggestion to merge the if/else blocks to streamline the code. We have considered this approach; however, merging them would necessitate duplicating the following lines in both the if and else blocks:
> if (msg_timeout < adap->timeout)
> msg_timeout = adap->timeout;
OK, makes sense, I didn't see it.
Thanks,
Andi
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-09-11 8:24 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-08-01 9:44 [PATCH 0/3] Add atomic transfer support to i2c-cadence Manikanta Guntupalli
2024-08-01 9:44 ` [PATCH 1/3] i2c: cadence: Relocate cdns_i2c_runtime_suspend and cdns_i2c_runtime_resume to facilitate atomic mode Manikanta Guntupalli
2024-09-10 13:24 ` Andi Shyti
2024-08-01 9:44 ` [PATCH 2/3] i2c: cadence: Split cdns_i2c_master_xfer for Atomic Mode Manikanta Guntupalli
2024-09-10 13:25 ` Andi Shyti
2024-08-01 9:44 ` [PATCH 3/3] i2c: cadence: Add atomic transfer support for controller version 1.4 Manikanta Guntupalli
2024-09-10 13:15 ` Andi Shyti
2024-09-11 7:26 ` Guntupalli, Manikanta
2024-09-11 8:24 ` Andi Shyti
2024-09-02 8:27 ` [PATCH 0/3] Add atomic transfer support to i2c-cadence Michal Simek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®