Skip to content

Commit 4dc8b26

Browse files
minimaxwellPaolo Abeni
authored andcommitted
net: mdio: mdio-i2c: Hold the i2c bus lock during smbus transactions
When accessing an MDIO register using single-byte smbus accesses, we have to perform 2 consecutive operations targeting the same address, first accessing the MSB then the LSB of the 16 bit register: read_1_byte(addr); <- returns MSB of register at address 'addr' read_1_byte(addr); <- returns LSB Some PHY devices present in SFP such as the Broadcom 5461 don't like seeing foreign i2c transactions in-between these 2 smbus accesses, and will return the MSB a second time when trying to read the LSB : read_1_byte(addr); <- returns MSB i2c_transaction_for_other_device_on_the_bus(); read_1_byte(addr); <- returns MSB again Given the already fragile nature of accessing PHYs/SFPs with single-byte smbus accesses, it's safe to say that this Broadcom PHY may not be the only one acting like this. Let's therefore hold the i2c bus lock while performing our smbus transactions to avoid interleaved accesses. Fixes: d4bd3ac ("net: mdio: mdio-i2c: Add support for single-byte SMBus operations") Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> Reviewed-by: Kory Maincent <kory.maincent@bootlin.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Link: https://patch.msgid.link/20251003070311.861135-1-maxime.chevallier@bootlin.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent f07f91a commit 4dc8b26

File tree

1 file changed

+25
-14
lines changed

1 file changed

+25
-14
lines changed

drivers/net/mdio/mdio-i2c.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,23 @@ static int smbus_byte_mii_read_default_c22(struct mii_bus *bus, int phy_id,
116116
if (!i2c_mii_valid_phy_id(phy_id))
117117
return 0;
118118

119-
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
120-
I2C_SMBUS_READ, reg,
121-
I2C_SMBUS_BYTE_DATA, &smbus_data);
119+
i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
120+
121+
ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
122+
I2C_SMBUS_READ, reg,
123+
I2C_SMBUS_BYTE_DATA, &smbus_data);
122124
if (ret < 0)
123-
return ret;
125+
goto unlock;
124126

125127
val = (smbus_data.byte & 0xff) << 8;
126128

127-
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
128-
I2C_SMBUS_READ, reg,
129-
I2C_SMBUS_BYTE_DATA, &smbus_data);
129+
ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
130+
I2C_SMBUS_READ, reg,
131+
I2C_SMBUS_BYTE_DATA, &smbus_data);
132+
133+
unlock:
134+
i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
135+
130136
if (ret < 0)
131137
return ret;
132138

@@ -147,17 +153,22 @@ static int smbus_byte_mii_write_default_c22(struct mii_bus *bus, int phy_id,
147153

148154
smbus_data.byte = (val & 0xff00) >> 8;
149155

150-
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
151-
I2C_SMBUS_WRITE, reg,
152-
I2C_SMBUS_BYTE_DATA, &smbus_data);
156+
i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
157+
158+
ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
159+
I2C_SMBUS_WRITE, reg,
160+
I2C_SMBUS_BYTE_DATA, &smbus_data);
153161
if (ret < 0)
154-
return ret;
162+
goto unlock;
155163

156164
smbus_data.byte = val & 0xff;
157165

158-
ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
159-
I2C_SMBUS_WRITE, reg,
160-
I2C_SMBUS_BYTE_DATA, &smbus_data);
166+
ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
167+
I2C_SMBUS_WRITE, reg,
168+
I2C_SMBUS_BYTE_DATA, &smbus_data);
169+
170+
unlock:
171+
i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
161172

162173
return ret < 0 ? ret : 0;
163174
}

0 commit comments

Comments
 (0)