Skip to content

Commit 86067cc

Browse files
Asmaa Mnebhiwsakernel
authored andcommitted
i2c: mlxbf: support lock mechanism
Linux is not the only entity using the BlueField I2C busses so support a lock mechanism provided by hardware to avoid issues when multiple entities are trying to access the same bus. The lock is acquired whenever written explicitely or the lock register is read. So make sure it is always released at the end of a successful or failed transaction. Fixes: b5b5b32 (i2c: mlxbf: I2C SMBus driver for Mellanox BlueField SoC) Reviewed-by: Khalil Blaiech <[email protected]> Signed-off-by: Asmaa Mnebhi <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 85f17d6 commit 86067cc

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

drivers/i2c/busses/i2c-mlxbf.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ static u64 mlxbf_i2c_corepll_frequency;
306306
* exact.
307307
*/
308308
#define MLXBF_I2C_SMBUS_TIMEOUT (300 * 1000) /* 300ms */
309+
#define MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT (300 * 1000) /* 300ms */
309310

310311
/* Encapsulates timing parameters. */
311312
struct mlxbf_i2c_timings {
@@ -514,6 +515,25 @@ static bool mlxbf_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv)
514515
return false;
515516
}
516517

518+
/*
519+
* wait for the lock to be released before acquiring it.
520+
*/
521+
static bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv)
522+
{
523+
if (mlxbf_smbus_poll(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW,
524+
MLXBF_I2C_MASTER_LOCK_BIT, true,
525+
MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT))
526+
return true;
527+
528+
return false;
529+
}
530+
531+
static void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv)
532+
{
533+
/* Clear the gw to clear the lock */
534+
writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW);
535+
}
536+
517537
static bool mlxbf_i2c_smbus_transaction_success(u32 master_status,
518538
u32 cause_status)
519539
{
@@ -705,10 +725,19 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
705725
slave = request->slave & GENMASK(6, 0);
706726
addr = slave << 1;
707727

708-
/* First of all, check whether the HW is idle. */
709-
if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(priv)))
728+
/*
729+
* Try to acquire the smbus gw lock before any reads of the GW register since
730+
* a read sets the lock.
731+
*/
732+
if (WARN_ON(!mlxbf_i2c_smbus_master_lock(priv)))
710733
return -EBUSY;
711734

735+
/* Check whether the HW is idle */
736+
if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(priv))) {
737+
ret = -EBUSY;
738+
goto out_unlock;
739+
}
740+
712741
/* Set first byte. */
713742
data_desc[data_idx++] = addr;
714743

@@ -732,8 +761,10 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
732761
write_en = 1;
733762
write_len += operation->length;
734763
if (data_idx + operation->length >
735-
MLXBF_I2C_MASTER_DATA_DESC_SIZE)
736-
return -ENOBUFS;
764+
MLXBF_I2C_MASTER_DATA_DESC_SIZE) {
765+
ret = -ENOBUFS;
766+
goto out_unlock;
767+
}
737768
memcpy(data_desc + data_idx,
738769
operation->buffer, operation->length);
739770
data_idx += operation->length;
@@ -765,7 +796,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
765796
ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en,
766797
pec_en, 0);
767798
if (ret)
768-
return ret;
799+
goto out_unlock;
769800
}
770801

771802
if (read_en) {
@@ -792,6 +823,9 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
792823
priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM);
793824
}
794825

826+
out_unlock:
827+
mlxbf_i2c_smbus_master_unlock(priv);
828+
795829
return ret;
796830
}
797831

0 commit comments

Comments
 (0)