Skip to content

Commit 7662abf

Browse files
minimaxwellkuba-moo
authored andcommitted
net: phy: sfp: Add support for SMBus module access
The SFP module's eeprom and internals are accessible through an i2c bus. It is possible that the SFP might be connected to an SMBus-only controller, such as the one found in some PHY devices in the VSC85xx family. Introduce a set of sfp read/write ops that are going to be used if the i2c bus is only capable of doing smbus byte accesses. As Single-byte SMBus transaction go against SFF-8472 and breaks the atomicity for diagnostics data access, hwmon is disabled in the case of SMBus access. Moreover, as this may cause other instabilities, print a warning at probe time to indicate that the setup may be unreliable because of the hardware design. As hwmon may be disabled for both broken EEPROM and smbus, the warnings are udpated accordingly. Signed-off-by: Maxime Chevallier <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 586b7b3 commit 7662abf

File tree

1 file changed

+74
-8
lines changed

1 file changed

+74
-8
lines changed

drivers/net/phy/sfp.c

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ struct sfp {
234234
enum mdio_i2c_proto mdio_protocol;
235235
struct phy_device *mod_phy;
236236
const struct sff_data *type;
237+
size_t i2c_max_block_size;
237238
size_t i2c_block_size;
238239
u32 max_power_mW;
239240

@@ -691,14 +692,71 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
691692
return ret == ARRAY_SIZE(msgs) ? len : 0;
692693
}
693694

694-
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
695+
static int sfp_smbus_byte_read(struct sfp *sfp, bool a2, u8 dev_addr,
696+
void *buf, size_t len)
695697
{
696-
if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
697-
return -EINVAL;
698+
union i2c_smbus_data smbus_data;
699+
u8 bus_addr = a2 ? 0x51 : 0x50;
700+
u8 *data = buf;
701+
int ret;
702+
703+
while (len) {
704+
ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0,
705+
I2C_SMBUS_READ, dev_addr,
706+
I2C_SMBUS_BYTE_DATA, &smbus_data);
707+
if (ret < 0)
708+
return ret;
709+
710+
*data = smbus_data.byte;
711+
712+
len--;
713+
data++;
714+
dev_addr++;
715+
}
716+
717+
return data - (u8 *)buf;
718+
}
719+
720+
static int sfp_smbus_byte_write(struct sfp *sfp, bool a2, u8 dev_addr,
721+
void *buf, size_t len)
722+
{
723+
union i2c_smbus_data smbus_data;
724+
u8 bus_addr = a2 ? 0x51 : 0x50;
725+
u8 *data = buf;
726+
int ret;
698727

728+
while (len) {
729+
smbus_data.byte = *data;
730+
ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0,
731+
I2C_SMBUS_WRITE, dev_addr,
732+
I2C_SMBUS_BYTE_DATA, &smbus_data);
733+
if (ret)
734+
return ret;
735+
736+
len--;
737+
data++;
738+
dev_addr++;
739+
}
740+
741+
return 0;
742+
}
743+
744+
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
745+
{
699746
sfp->i2c = i2c;
700-
sfp->read = sfp_i2c_read;
701-
sfp->write = sfp_i2c_write;
747+
748+
if (i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
749+
sfp->read = sfp_i2c_read;
750+
sfp->write = sfp_i2c_write;
751+
sfp->i2c_max_block_size = SFP_EEPROM_BLOCK_SIZE;
752+
} else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) {
753+
sfp->read = sfp_smbus_byte_read;
754+
sfp->write = sfp_smbus_byte_write;
755+
sfp->i2c_max_block_size = 1;
756+
} else {
757+
sfp->i2c = NULL;
758+
return -EINVAL;
759+
}
702760

703761
return 0;
704762
}
@@ -1594,7 +1652,7 @@ static void sfp_hwmon_probe(struct work_struct *work)
15941652
*/
15951653
if (sfp->i2c_block_size < 2) {
15961654
dev_info(sfp->dev,
1597-
"skipping hwmon device registration due to broken EEPROM\n");
1655+
"skipping hwmon device registration\n");
15981656
dev_info(sfp->dev,
15991657
"diagnostic EEPROM area cannot be read atomically to guarantee data coherency\n");
16001658
return;
@@ -2201,7 +2259,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
22012259
u8 check;
22022260
int ret;
22032261

2204-
sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE;
2262+
sfp->i2c_block_size = sfp->i2c_max_block_size;
22052263

22062264
ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
22072265
if (ret < 0) {
@@ -2941,7 +2999,6 @@ static struct sfp *sfp_alloc(struct device *dev)
29412999
return ERR_PTR(-ENOMEM);
29423000

29433001
sfp->dev = dev;
2944-
sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE;
29453002

29463003
mutex_init(&sfp->sm_mutex);
29473004
mutex_init(&sfp->st_mutex);
@@ -3115,6 +3172,15 @@ static int sfp_probe(struct platform_device *pdev)
31153172
if (!sfp->sfp_bus)
31163173
return -ENOMEM;
31173174

3175+
if (sfp->i2c_max_block_size < 2)
3176+
dev_warn(sfp->dev,
3177+
"Please note:\n"
3178+
"This SFP cage is accessed via an SMBus only capable of single byte\n"
3179+
"transactions. Some features are disabled, other may be unreliable or\n"
3180+
"sporadically fail. Use with caution. There is nothing that the kernel\n"
3181+
"or community can do to fix it, the kernel will try best efforts. Please\n"
3182+
"verify any problems on hardware that supports multi-byte I2C transactions.\n");
3183+
31183184
sfp_debugfs_init(sfp);
31193185

31203186
return 0;

0 commit comments

Comments
 (0)