* [PATCH v12 0/3] i2c: octeon: add block-mode r/w
@ 2025-03-11 2:34 Aryan Srivastava
2025-03-11 2:34 ` [PATCH v12 1/3] i2c: octeon: fix return commenting Aryan Srivastava
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Aryan Srivastava @ 2025-03-11 2:34 UTC (permalink / raw)
To: Andi Shyti, Andy Shevchenko, Markus Elfring
Cc: linux-i2c, linux-kernel, Aryan Srivastava
Add support for block mode read/write operations on
Thunderx chips.
-Refactor common code for i2c transactions (merged in v11).
-Correct function docs.
-Remove 10-bit addressing considerations.
-Add block mode transaction functionality.
Signed-off-by: Aryan Srivastava <aryan.srivastava@alliedtelesis.co.nz>
---
Changes in v2:
- comment style and formatting.
Changes in v3:
- comment style and formatting.
Changes in v4:
- Refactoring common code.
- Additional comments.
Changes in v5:
- Further refactoring.
- Split refactoring into separate patch in series.
- Add more comments + details to comments.
Changes in v6:
- Reword/reformat commit messages
Changes in v7:
- Fix typo in commit message.
- Remove usage of r/w and hlc abbreviations from commits.
Changes in v8:
- Updated refactor commit msg with more information.
- Rebased patch
Changes in v9:
- Rebased patch against i2c-host
Changes in v10:
- Fixed unitialised variable
Changes in v11:
- Rebased patch against i2c-host
Changes in v12:
- Added fixes for function docs
- Removed considerations for 10-bit addressing
- Transition to using appropriate byte-swap operations, instead of custom code
- Refactor commit removed from this set, merged in:
https://lore.kernel.org/linux-i2c/seom4yspcjnmdxxwn6wuyiqdy2ywpna6nw4rn36tsqinlncbca@jdehzfnznlsg/
Aryan Srivastava (3):
i2c: octeon: fix return commenting
i2c: octeon: remove 10-bit addressing support
i2c: octeon: add block-mode i2c operations
drivers/i2c/busses/i2c-octeon-core.c | 195 +++++++++++++++++++----
drivers/i2c/busses/i2c-octeon-core.h | 13 +-
drivers/i2c/busses/i2c-thunderx-pcidrv.c | 3 +
3 files changed, 179 insertions(+), 32 deletions(-)
--
2.47.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v12 1/3] i2c: octeon: fix return commenting
2025-03-11 2:34 [PATCH v12 0/3] i2c: octeon: add block-mode r/w Aryan Srivastava
@ 2025-03-11 2:34 ` Aryan Srivastava
2025-03-19 0:13 ` Andi Shyti
2025-03-11 2:34 ` [PATCH v12 2/3] i2c: octeon: remove 10-bit addressing support Aryan Srivastava
2025-03-11 2:34 ` [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations Aryan Srivastava
2 siblings, 1 reply; 8+ messages in thread
From: Aryan Srivastava @ 2025-03-11 2:34 UTC (permalink / raw)
To: Andi Shyti, Andy Shevchenko, Markus Elfring
Cc: linux-i2c, linux-kernel, Aryan Srivastava, Robert Richter
Kernel-docs require a ':' to signify the return behaviour of a function
with within the comment. Many functions in this file were missing ':'
after the "Returns" line, resulting in kernel-doc warnings.
Add the ':' to satisfy kernel-doc requirements.
Signed-off-by: Aryan Srivastava <aryan.srivastava@alliedtelesis.co.nz>
---
drivers/i2c/busses/i2c-octeon-core.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c
index 3fbc828508ab..0094fe5f7460 100644
--- a/drivers/i2c/busses/i2c-octeon-core.c
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -45,7 +45,7 @@ static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
* octeon_i2c_wait - wait for the IFLG to be set
* @i2c: The struct octeon_i2c
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_wait(struct octeon_i2c *i2c)
{
@@ -139,7 +139,7 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
* octeon_i2c_hlc_wait - wait for an HLC operation to complete
* @i2c: The struct octeon_i2c
*
- * Returns 0 on success, otherwise -ETIMEDOUT.
+ * Returns: 0 on success, otherwise -ETIMEDOUT.
*/
static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
{
@@ -273,7 +273,7 @@ static int octeon_i2c_recovery(struct octeon_i2c *i2c)
* octeon_i2c_start - send START to the bus
* @i2c: The struct octeon_i2c
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_start(struct octeon_i2c *i2c)
{
@@ -314,7 +314,7 @@ static void octeon_i2c_stop(struct octeon_i2c *i2c)
*
* The address is sent over the bus, then the data is read.
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
u8 *data, u16 *rlength, bool recv_len)
@@ -382,7 +382,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
*
* The address is sent over the bus, then the data.
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
const u8 *data, int length)
@@ -625,7 +625,7 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
* @msgs: Pointer to the messages to be processed
* @num: Length of the MSGS array
*
- * Returns the number of messages processed, or a negative errno on failure.
+ * Returns: the number of messages processed, or a negative errno on failure.
*/
int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
--
2.47.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v12 2/3] i2c: octeon: remove 10-bit addressing support
2025-03-11 2:34 [PATCH v12 0/3] i2c: octeon: add block-mode r/w Aryan Srivastava
2025-03-11 2:34 ` [PATCH v12 1/3] i2c: octeon: fix return commenting Aryan Srivastava
@ 2025-03-11 2:34 ` Aryan Srivastava
2025-03-19 0:11 ` Andi Shyti
2025-03-11 2:34 ` [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations Aryan Srivastava
2 siblings, 1 reply; 8+ messages in thread
From: Aryan Srivastava @ 2025-03-11 2:34 UTC (permalink / raw)
To: Andi Shyti, Andy Shevchenko, Markus Elfring
Cc: linux-i2c, linux-kernel, Aryan Srivastava, Robert Richter
The driver gives the illusion of 10-bit address support, but the upper
3 bits of the given address are always thrown away. Remove unnecessary
considerations for 10 bit addressing and always complete 7 bit ops when
using the hlc methods.
Signed-off-by: Aryan Srivastava <aryan.srivastava@alliedtelesis.co.nz>
---
drivers/i2c/busses/i2c-octeon-core.c | 23 ++++-------------------
1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c
index 0094fe5f7460..baf6b27f3752 100644
--- a/drivers/i2c/busses/i2c-octeon-core.c
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -421,17 +421,12 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
octeon_i2c_hlc_enable(i2c);
octeon_i2c_hlc_int_clear(i2c);
- cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7;
/* SIZE */
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
- if (msgs[0].flags & I2C_M_TEN)
- cmd |= SW_TWSI_OP_10;
- else
- cmd |= SW_TWSI_OP_7;
-
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -463,17 +458,12 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
octeon_i2c_hlc_enable(i2c);
octeon_i2c_hlc_int_clear(i2c);
- cmd = SW_TWSI_V | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7;
/* SIZE */
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
- if (msgs[0].flags & I2C_M_TEN)
- cmd |= SW_TWSI_OP_10;
- else
- cmd |= SW_TWSI_OP_7;
-
for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--)
cmd |= (u64)msgs[0].buf[j] << (8 * i);
@@ -513,11 +503,6 @@ static bool octeon_i2c_hlc_ext(struct octeon_i2c *i2c, struct i2c_msg msg, u64 *
bool set_ext = false;
u64 cmd = 0;
- if (msg.flags & I2C_M_TEN)
- cmd |= SW_TWSI_OP_10_IA;
- else
- cmd |= SW_TWSI_OP_7_IA;
-
if (msg.len == 2) {
cmd |= SW_TWSI_EIA;
*ext = (u64)msg.buf[0] << SW_TWSI_IA_SHIFT;
@@ -550,7 +535,7 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs
octeon_i2c_hlc_enable(i2c);
- cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
/* SIZE */
cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
@@ -587,7 +572,7 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
octeon_i2c_hlc_enable(i2c);
- cmd = SW_TWSI_V | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
/* SIZE */
cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
--
2.47.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations
2025-03-11 2:34 [PATCH v12 0/3] i2c: octeon: add block-mode r/w Aryan Srivastava
2025-03-11 2:34 ` [PATCH v12 1/3] i2c: octeon: fix return commenting Aryan Srivastava
2025-03-11 2:34 ` [PATCH v12 2/3] i2c: octeon: remove 10-bit addressing support Aryan Srivastava
@ 2025-03-11 2:34 ` Aryan Srivastava
2025-03-11 19:45 ` Andy Shevchenko
2025-03-12 23:12 ` kernel test robot
2 siblings, 2 replies; 8+ messages in thread
From: Aryan Srivastava @ 2025-03-11 2:34 UTC (permalink / raw)
To: Andi Shyti, Andy Shevchenko, Markus Elfring
Cc: linux-i2c, linux-kernel, Aryan Srivastava, Robert Richter
Add functions to perform block read and write operations. This applies
for cases where the requested operation is for >8 bytes of data.
When not using the block mode transfer, the driver will attempt a series
of 8 byte i2c operations until it reaches the desired total. For
example, for a 40 byte request the driver will complete 5 separate
transactions. This results in large transactions taking a significant
amount of time to process.
Add block mode such that the driver can request larger transactions, up
to 1024 bytes per transfer.
Many aspects of the block mode transfer is common with the regular 8
byte operations. Use generic functions for parts of the message
construction and sending the message. The key difference for the block
mode is the usage of separate FIFO buffer to store data.
Write to this buffer in the case of a write (before command send).
Read from this buffer in the case of a read (after command send).
Data is written into this buffer by placing data into the MSB onwards.
This means the bottom 8 bits of the data will match the top 8 bits, and
so on and so forth.
Set specific bits in message for block mode, enable block mode transfers
from global i2c management registers, construct message, send message,
read or write from FIFO buffer as required.
The block-mode transactions result in a significant speed increase in
large i2c requests.
Signed-off-by: Aryan Srivastava <aryan.srivastava@alliedtelesis.co.nz>
---
drivers/i2c/busses/i2c-octeon-core.c | 160 ++++++++++++++++++++++-
drivers/i2c/busses/i2c-octeon-core.h | 13 +-
drivers/i2c/busses/i2c-thunderx-pcidrv.c | 3 +
3 files changed, 169 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c
index baf6b27f3752..e92935d61b67 100644
--- a/drivers/i2c/busses/i2c-octeon-core.c
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -135,6 +135,32 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
}
+static void octeon_i2c_block_enable(struct octeon_i2c *i2c)
+{
+ u64 mode;
+
+ if (i2c->block_enabled || !OCTEON_REG_BLOCK_CTL(i2c))
+ return;
+
+ i2c->block_enabled = true;
+ mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c));
+ mode |= TWSX_MODE_BLOCK_MODE;
+ octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c));
+}
+
+static void octeon_i2c_block_disable(struct octeon_i2c *i2c)
+{
+ u64 mode;
+
+ if (!i2c->block_enabled || !OCTEON_REG_BLOCK_CTL(i2c))
+ return;
+
+ i2c->block_enabled = false;
+ mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c));
+ mode &= ~TWSX_MODE_BLOCK_MODE;
+ octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c));
+}
+
/**
* octeon_i2c_hlc_wait - wait for an HLC operation to complete
* @i2c: The struct octeon_i2c
@@ -281,6 +307,7 @@ static int octeon_i2c_start(struct octeon_i2c *i2c)
u8 stat;
octeon_i2c_hlc_disable(i2c);
+ octeon_i2c_block_disable(i2c);
octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
ret = octeon_i2c_wait(i2c);
@@ -604,6 +631,119 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
return ret;
}
+/**
+ * octeon_i2c_hlc_block_comp_read - high-level-controller composite block read
+ * @i2c: The struct octeon_i2c
+ * @msgs: msg[0] contains address, place read data into msg[1]
+ *
+ * i2c core command is constructed and written into the SW_TWSI register.
+ * The execution of the command will result in requested data being
+ * placed into a FIFO buffer, ready to be read.
+ * Used in the case where the i2c xfer is for greater than 8 bytes of read data.
+ *
+ * Returns: 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_hlc_block_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+ int ret = 0;
+ u16 len;
+ u64 cmd;
+
+ octeon_i2c_hlc_enable(i2c);
+ octeon_i2c_block_enable(i2c);
+
+ /* Write (size - 1) into block control register */
+ len = msgs[1].len - 1;
+ octeon_i2c_writeq_flush((u64)(len), i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c));
+
+ /* Prepare core command */
+ cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
+ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+ /* Send core command */
+ ret = octeon_i2c_hlc_read_cmd(i2c, msgs[0], cmd);
+ if (ret)
+ return ret;
+
+ cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
+ if ((cmd & SW_TWSI_R) == 0)
+ return octeon_i2c_check_status(i2c, false);
+
+ /* read data in FIFO */
+ octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR,
+ i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c));
+ for (u16 i = 0; i <= len; i += 8) {
+ /* Byte-swap FIFO data and copy into msg buffer */
+ u64 rd = cpu_to_be64(__raw_readq(i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c)));
+
+ memcpy(&msgs[1].buf[i], &rd, MIN_T(u16, 8, msgs[1].len - i));
+ }
+
+ octeon_i2c_block_disable(i2c);
+ return ret;
+}
+
+/**
+ * octeon_i2c_hlc_block_comp_write - high-level-controller composite block write
+ * @i2c: The struct octeon_i2c
+ * @msgs: msg[0] contains address, msg[1] contains data to be written
+ *
+ * i2c core command is constructed and write data is written into the FIFO buffer.
+ * The execution of the command will result in HW write, using the data in FIFO.
+ * Used in the case where the i2c xfer is for greater than 8 bytes of write data.
+ *
+ * Returns: 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_hlc_block_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+ bool set_ext = false;
+ int ret = 0;
+ u16 len;
+ u64 cmd, ext = 0;
+
+ octeon_i2c_hlc_enable(i2c);
+ octeon_i2c_block_enable(i2c);
+
+ /* Write (size - 1) into block control register */
+ len = msgs[1].len - 1;
+ octeon_i2c_writeq_flush((u64)(len), i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c));
+
+ /* Prepare core command */
+ cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
+ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+ /* Set parameters for extended message (if required) */
+ set_ext = octeon_i2c_hlc_ext(i2c, msgs[0], &cmd, &ext);
+
+ /* Write msg into FIFO buffer */
+ octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR,
+ i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c));
+ for (u16 i = 0; i <= len; i += 8) {
+ u64 buf = 0;
+
+ /* Copy 8 bytes or remaining bytes from message buffer */
+ memcpy(&buf, &msgs[1].buf[i], MIN_T(u16, 8, msgs[1].len - i));
+
+ /* Byte-swap message data and write into FIFO */
+ buf = cpu_to_be64(buf);
+ octeon_i2c_writeq_flush(buf, i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c));
+ }
+ if (set_ext)
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
+
+ /* Send command to core (send data in FIFO) */
+ ret = octeon_i2c_hlc_cmd_send(i2c, cmd);
+ if (ret)
+ return ret;
+
+ cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
+ if ((cmd & SW_TWSI_R) == 0)
+ return octeon_i2c_check_status(i2c, false);
+
+ octeon_i2c_block_disable(i2c);
+ return ret;
+}
+
/**
* octeon_i2c_xfer - The driver's xfer function
* @adap: Pointer to the i2c_adapter structure
@@ -630,13 +770,21 @@ int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if ((msgs[0].flags & I2C_M_RD) == 0 &&
(msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
msgs[0].len > 0 && msgs[0].len <= 2 &&
- msgs[1].len > 0 && msgs[1].len <= 8 &&
+ msgs[1].len > 0 &&
msgs[0].addr == msgs[1].addr) {
- if (msgs[1].flags & I2C_M_RD)
- ret = octeon_i2c_hlc_comp_read(i2c, msgs);
- else
- ret = octeon_i2c_hlc_comp_write(i2c, msgs);
- goto out;
+ if (msgs[1].len <= 8) {
+ if (msgs[1].flags & I2C_M_RD)
+ ret = octeon_i2c_hlc_comp_read(i2c, msgs);
+ else
+ ret = octeon_i2c_hlc_comp_write(i2c, msgs);
+ goto out;
+ } else if (msgs[1].len <= 1024 && OCTEON_REG_BLOCK_CTL(i2c)) {
+ if (msgs[1].flags & I2C_M_RD)
+ ret = octeon_i2c_hlc_block_comp_read(i2c, msgs);
+ else
+ ret = octeon_i2c_hlc_block_comp_write(i2c, msgs);
+ goto out;
+ }
}
}
}
diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h
index b265e21189a1..fecaf7388182 100644
--- a/drivers/i2c/busses/i2c-octeon-core.h
+++ b/drivers/i2c/busses/i2c-octeon-core.h
@@ -96,18 +96,28 @@ struct octeon_i2c_reg_offset {
unsigned int twsi_int;
unsigned int sw_twsi_ext;
unsigned int mode;
+ unsigned int block_ctl;
+ unsigned int block_sts;
+ unsigned int block_fifo;
};
#define OCTEON_REG_SW_TWSI(x) ((x)->roff.sw_twsi)
#define OCTEON_REG_TWSI_INT(x) ((x)->roff.twsi_int)
#define OCTEON_REG_SW_TWSI_EXT(x) ((x)->roff.sw_twsi_ext)
#define OCTEON_REG_MODE(x) ((x)->roff.mode)
+#define OCTEON_REG_BLOCK_CTL(x) (x->roff.block_ctl)
+#define OCTEON_REG_BLOCK_STS(x) (x->roff.block_sts)
+#define OCTEON_REG_BLOCK_FIFO(x) (x->roff.block_fifo)
-/* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */
+/* TWSX_MODE register */
#define TWSX_MODE_REFCLK_SRC BIT(4)
+#define TWSX_MODE_BLOCK_MODE BIT(2)
#define TWSX_MODE_HS_MODE BIT(0)
#define TWSX_MODE_HS_MASK (TWSX_MODE_REFCLK_SRC | TWSX_MODE_HS_MODE)
+/* TWSX_BLOCK_STS register */
+#define TWSX_BLOCK_STS_RESET_PTR BIT(0)
+
/* Set BUS_MON_RST to reset bus monitor */
#define BUS_MON_RST_MASK BIT(3)
@@ -123,6 +133,7 @@ struct octeon_i2c {
void __iomem *twsi_base;
struct device *dev;
bool hlc_enabled;
+ bool block_enabled;
bool broken_irq_mode;
bool broken_irq_check;
void (*int_enable)(struct octeon_i2c *);
diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
index 143d012fa43e..0dc08cd97e8a 100644
--- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c
+++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
@@ -168,6 +168,9 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
i2c->roff.twsi_int = 0x1010;
i2c->roff.sw_twsi_ext = 0x1018;
i2c->roff.mode = 0x1038;
+ i2c->roff.block_ctl = 0x1048;
+ i2c->roff.block_sts = 0x1050;
+ i2c->roff.block_fifo = 0x1058;
i2c->dev = dev;
pci_set_drvdata(pdev, i2c);
--
2.47.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations
2025-03-11 2:34 ` [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations Aryan Srivastava
@ 2025-03-11 19:45 ` Andy Shevchenko
2025-03-12 23:12 ` kernel test robot
1 sibling, 0 replies; 8+ messages in thread
From: Andy Shevchenko @ 2025-03-11 19:45 UTC (permalink / raw)
To: Aryan Srivastava
Cc: Andi Shyti, Markus Elfring, linux-i2c, linux-kernel,
Robert Richter
On Tue, Mar 11, 2025 at 4:34 AM Aryan Srivastava
<aryan.srivastava@alliedtelesis.co.nz> wrote:
>
> Add functions to perform block read and write operations. This applies
> for cases where the requested operation is for >8 bytes of data.
>
> When not using the block mode transfer, the driver will attempt a series
> of 8 byte i2c operations until it reaches the desired total. For
> example, for a 40 byte request the driver will complete 5 separate
> transactions. This results in large transactions taking a significant
> amount of time to process.
>
> Add block mode such that the driver can request larger transactions, up
> to 1024 bytes per transfer.
>
> Many aspects of the block mode transfer is common with the regular 8
> byte operations. Use generic functions for parts of the message
> construction and sending the message. The key difference for the block
> mode is the usage of separate FIFO buffer to store data.
>
> Write to this buffer in the case of a write (before command send).
> Read from this buffer in the case of a read (after command send).
>
> Data is written into this buffer by placing data into the MSB onwards.
> This means the bottom 8 bits of the data will match the top 8 bits, and
> so on and so forth.
>
> Set specific bits in message for block mode, enable block mode transfers
> from global i2c management registers, construct message, send message,
> read or write from FIFO buffer as required.
>
> The block-mode transactions result in a significant speed increase in
> large i2c requests.
...
> +static int octeon_i2c_hlc_block_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
> +{
> + int ret = 0;
Why the useless assignment?
> + u16 len;
> + u64 cmd;
> +
> + octeon_i2c_hlc_enable(i2c);
> + octeon_i2c_block_enable(i2c);
> +
> + /* Write (size - 1) into block control register */
> + len = msgs[1].len - 1;
> + octeon_i2c_writeq_flush((u64)(len), i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c));
Why explicit casting? (And no need to have parentheses for simple
cases like this)
> + /* Prepare core command */
> + cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
> + cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
> +
> + /* Send core command */
> + ret = octeon_i2c_hlc_read_cmd(i2c, msgs[0], cmd);
> + if (ret)
> + return ret;
> +
> + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
> + if ((cmd & SW_TWSI_R) == 0)
> + return octeon_i2c_check_status(i2c, false);
> +
> + /* read data in FIFO */
> + octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR,
> + i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c));
> + for (u16 i = 0; i <= len; i += 8) {
> + /* Byte-swap FIFO data and copy into msg buffer */
> + u64 rd = cpu_to_be64(__raw_readq(i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c)));
> +
> + memcpy(&msgs[1].buf[i], &rd, MIN_T(u16, 8, msgs[1].len - i));
Why MIN_T()?! umin() or min() should work.
> + }
> +
> + octeon_i2c_block_disable(i2c);
> + return ret;
> +}
...
> +static int octeon_i2c_hlc_block_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
> +{
Same comments as per above.
> + bool set_ext = false;
> + int ret = 0;
Why do you need these assignments? What for?
> + u16 len;
> + u64 cmd, ext = 0;
> +
> + octeon_i2c_hlc_enable(i2c);
> + octeon_i2c_block_enable(i2c);
> +
> + /* Write (size - 1) into block control register */
> + len = msgs[1].len - 1;
> + octeon_i2c_writeq_flush((u64)(len), i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c));
> +
> + /* Prepare core command */
> + cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
> + cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
> +
> + /* Set parameters for extended message (if required) */
> + set_ext = octeon_i2c_hlc_ext(i2c, msgs[0], &cmd, &ext);
> +
> + /* Write msg into FIFO buffer */
> + octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR,
> + i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c));
> + for (u16 i = 0; i <= len; i += 8) {
> + u64 buf = 0;
> +
> + /* Copy 8 bytes or remaining bytes from message buffer */
> + memcpy(&buf, &msgs[1].buf[i], MIN_T(u16, 8, msgs[1].len - i));
> +
> + /* Byte-swap message data and write into FIFO */
> + buf = cpu_to_be64(buf);
> + octeon_i2c_writeq_flush(buf, i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c));
> + }
> + if (set_ext)
> + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
> +
> + /* Send command to core (send data in FIFO) */
> + ret = octeon_i2c_hlc_cmd_send(i2c, cmd);
> + if (ret)
> + return ret;
> +
> + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
> + if ((cmd & SW_TWSI_R) == 0)
> + return octeon_i2c_check_status(i2c, false);
> +
> + octeon_i2c_block_disable(i2c);
> + return ret;
> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations
2025-03-11 2:34 ` [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations Aryan Srivastava
2025-03-11 19:45 ` Andy Shevchenko
@ 2025-03-12 23:12 ` kernel test robot
1 sibling, 0 replies; 8+ messages in thread
From: kernel test robot @ 2025-03-12 23:12 UTC (permalink / raw)
To: Aryan Srivastava, Andi Shyti, Andy Shevchenko, Markus Elfring
Cc: oe-kbuild-all, linux-i2c, linux-kernel, Aryan Srivastava,
Robert Richter
Hi Aryan,
kernel test robot noticed the following build warnings:
[auto build test WARNING on andi-shyti/i2c/i2c-host]
[also build test WARNING on next-20250312]
[cannot apply to linus/master v6.14-rc6]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Aryan-Srivastava/i2c-octeon-fix-return-commenting/20250311-103714
base: https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git i2c/i2c-host
patch link: https://lore.kernel.org/r/20250311023435.3962466-4-aryan.srivastava%40alliedtelesis.co.nz
patch subject: [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations
config: alpha-randconfig-r132-20250312 (https://download.01.org/0day-ci/archive/20250313/202503130610.rUb3f7P4-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 14.2.0
reproduce: (https://download.01.org/0day-ci/archive/20250313/202503130610.rUb3f7P4-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202503130610.rUb3f7P4-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/i2c/busses/i2c-octeon-core.c:677:26: sparse: sparse: incorrect type in initializer (different base types) @@ expected unsigned long long [usertype] rd @@ got restricted __be64 [usertype] @@
drivers/i2c/busses/i2c-octeon-core.c:677:26: sparse: expected unsigned long long [usertype] rd
drivers/i2c/busses/i2c-octeon-core.c:677:26: sparse: got restricted __be64 [usertype]
>> drivers/i2c/busses/i2c-octeon-core.c:728:21: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned long long [addressable] [usertype] buf @@ got restricted __be64 [usertype] @@
drivers/i2c/busses/i2c-octeon-core.c:728:21: sparse: expected unsigned long long [addressable] [usertype] buf
drivers/i2c/busses/i2c-octeon-core.c:728:21: sparse: got restricted __be64 [usertype]
vim +677 drivers/i2c/busses/i2c-octeon-core.c
633
634 /**
635 * octeon_i2c_hlc_block_comp_read - high-level-controller composite block read
636 * @i2c: The struct octeon_i2c
637 * @msgs: msg[0] contains address, place read data into msg[1]
638 *
639 * i2c core command is constructed and written into the SW_TWSI register.
640 * The execution of the command will result in requested data being
641 * placed into a FIFO buffer, ready to be read.
642 * Used in the case where the i2c xfer is for greater than 8 bytes of read data.
643 *
644 * Returns: 0 on success, otherwise a negative errno.
645 */
646 static int octeon_i2c_hlc_block_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
647 {
648 int ret = 0;
649 u16 len;
650 u64 cmd;
651
652 octeon_i2c_hlc_enable(i2c);
653 octeon_i2c_block_enable(i2c);
654
655 /* Write (size - 1) into block control register */
656 len = msgs[1].len - 1;
657 octeon_i2c_writeq_flush((u64)(len), i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c));
658
659 /* Prepare core command */
660 cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
661 cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
662
663 /* Send core command */
664 ret = octeon_i2c_hlc_read_cmd(i2c, msgs[0], cmd);
665 if (ret)
666 return ret;
667
668 cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
669 if ((cmd & SW_TWSI_R) == 0)
670 return octeon_i2c_check_status(i2c, false);
671
672 /* read data in FIFO */
673 octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR,
674 i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c));
675 for (u16 i = 0; i <= len; i += 8) {
676 /* Byte-swap FIFO data and copy into msg buffer */
> 677 u64 rd = cpu_to_be64(__raw_readq(i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c)));
678
679 memcpy(&msgs[1].buf[i], &rd, MIN_T(u16, 8, msgs[1].len - i));
680 }
681
682 octeon_i2c_block_disable(i2c);
683 return ret;
684 }
685
686 /**
687 * octeon_i2c_hlc_block_comp_write - high-level-controller composite block write
688 * @i2c: The struct octeon_i2c
689 * @msgs: msg[0] contains address, msg[1] contains data to be written
690 *
691 * i2c core command is constructed and write data is written into the FIFO buffer.
692 * The execution of the command will result in HW write, using the data in FIFO.
693 * Used in the case where the i2c xfer is for greater than 8 bytes of write data.
694 *
695 * Returns: 0 on success, otherwise a negative errno.
696 */
697 static int octeon_i2c_hlc_block_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
698 {
699 bool set_ext = false;
700 int ret = 0;
701 u16 len;
702 u64 cmd, ext = 0;
703
704 octeon_i2c_hlc_enable(i2c);
705 octeon_i2c_block_enable(i2c);
706
707 /* Write (size - 1) into block control register */
708 len = msgs[1].len - 1;
709 octeon_i2c_writeq_flush((u64)(len), i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c));
710
711 /* Prepare core command */
712 cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
713 cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
714
715 /* Set parameters for extended message (if required) */
716 set_ext = octeon_i2c_hlc_ext(i2c, msgs[0], &cmd, &ext);
717
718 /* Write msg into FIFO buffer */
719 octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR,
720 i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c));
721 for (u16 i = 0; i <= len; i += 8) {
722 u64 buf = 0;
723
724 /* Copy 8 bytes or remaining bytes from message buffer */
725 memcpy(&buf, &msgs[1].buf[i], MIN_T(u16, 8, msgs[1].len - i));
726
727 /* Byte-swap message data and write into FIFO */
> 728 buf = cpu_to_be64(buf);
729 octeon_i2c_writeq_flush(buf, i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c));
730 }
731 if (set_ext)
732 octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
733
734 /* Send command to core (send data in FIFO) */
735 ret = octeon_i2c_hlc_cmd_send(i2c, cmd);
736 if (ret)
737 return ret;
738
739 cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
740 if ((cmd & SW_TWSI_R) == 0)
741 return octeon_i2c_check_status(i2c, false);
742
743 octeon_i2c_block_disable(i2c);
744 return ret;
745 }
746
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v12 2/3] i2c: octeon: remove 10-bit addressing support
2025-03-11 2:34 ` [PATCH v12 2/3] i2c: octeon: remove 10-bit addressing support Aryan Srivastava
@ 2025-03-19 0:11 ` Andi Shyti
0 siblings, 0 replies; 8+ messages in thread
From: Andi Shyti @ 2025-03-19 0:11 UTC (permalink / raw)
To: Aryan Srivastava
Cc: Andy Shevchenko, Markus Elfring, linux-i2c, linux-kernel,
Robert Richter
Hi Aryan,
On Tue, Mar 11, 2025 at 03:34:33PM +1300, Aryan Srivastava wrote:
> The driver gives the illusion of 10-bit address support, but the upper
> 3 bits of the given address are always thrown away. Remove unnecessary
> considerations for 10 bit addressing and always complete 7 bit ops when
> using the hlc methods.
Can someone from Marvell comment here?
The datasheet I have isn't very clear on this part. Also, I'd
like to know if there's any product line that could be negatively
impacted by this patch.
Andi
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v12 1/3] i2c: octeon: fix return commenting
2025-03-11 2:34 ` [PATCH v12 1/3] i2c: octeon: fix return commenting Aryan Srivastava
@ 2025-03-19 0:13 ` Andi Shyti
0 siblings, 0 replies; 8+ messages in thread
From: Andi Shyti @ 2025-03-19 0:13 UTC (permalink / raw)
To: Aryan Srivastava
Cc: Andy Shevchenko, Markus Elfring, linux-i2c, linux-kernel,
Robert Richter
Hi Aryan,
On Tue, Mar 11, 2025 at 03:34:32PM +1300, Aryan Srivastava wrote:
> Kernel-docs require a ':' to signify the return behaviour of a function
> with within the comment. Many functions in this file were missing ':'
> after the "Returns" line, resulting in kernel-doc warnings.
>
> Add the ':' to satisfy kernel-doc requirements.
>
> Signed-off-by: Aryan Srivastava <aryan.srivastava@alliedtelesis.co.nz>
I merged just this patch in i2c/i2c-host.
Thanks,
Andi
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-03-19 0:13 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-11 2:34 [PATCH v12 0/3] i2c: octeon: add block-mode r/w Aryan Srivastava
2025-03-11 2:34 ` [PATCH v12 1/3] i2c: octeon: fix return commenting Aryan Srivastava
2025-03-19 0:13 ` Andi Shyti
2025-03-11 2:34 ` [PATCH v12 2/3] i2c: octeon: remove 10-bit addressing support Aryan Srivastava
2025-03-19 0:11 ` Andi Shyti
2025-03-11 2:34 ` [PATCH v12 3/3] i2c: octeon: add block-mode i2c operations Aryan Srivastava
2025-03-11 19:45 ` Andy Shevchenko
2025-03-12 23:12 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox