Skip to content

Commit aa3651c

Browse files
committed
Merge branch 'net-phy-sfp-add-single-byte-smbus-sfp-access'
Maxime Chevallier says: ==================== net: phy: sfp: Add single-byte SMBus SFP access This is V4 for the single-byte SMBus support for SFP cages as well as embedded PHYs accessed over mdio-i2c. v3: https://lore.kernel.org/[email protected] v2: https://lore.kernel.org/[email protected] v1: https://lore.kernel.org/[email protected] ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 586b7b3 + d4bd3ac commit aa3651c

File tree

2 files changed

+152
-9
lines changed

2 files changed

+152
-9
lines changed

drivers/net/mdio/mdio-i2c.c

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,62 @@ static int i2c_mii_write_default_c22(struct mii_bus *bus, int phy_id, int reg,
106106
return i2c_mii_write_default_c45(bus, phy_id, -1, reg, val);
107107
}
108108

109+
static int smbus_byte_mii_read_default_c22(struct mii_bus *bus, int phy_id,
110+
int reg)
111+
{
112+
struct i2c_adapter *i2c = bus->priv;
113+
union i2c_smbus_data smbus_data;
114+
int val = 0, ret;
115+
116+
if (!i2c_mii_valid_phy_id(phy_id))
117+
return 0;
118+
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);
122+
if (ret < 0)
123+
return ret;
124+
125+
val = (smbus_data.byte & 0xff) << 8;
126+
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);
130+
if (ret < 0)
131+
return ret;
132+
133+
val |= smbus_data.byte & 0xff;
134+
135+
return val;
136+
}
137+
138+
static int smbus_byte_mii_write_default_c22(struct mii_bus *bus, int phy_id,
139+
int reg, u16 val)
140+
{
141+
struct i2c_adapter *i2c = bus->priv;
142+
union i2c_smbus_data smbus_data;
143+
int ret;
144+
145+
if (!i2c_mii_valid_phy_id(phy_id))
146+
return 0;
147+
148+
smbus_data.byte = (val & 0xff00) >> 8;
149+
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);
153+
if (ret < 0)
154+
return ret;
155+
156+
smbus_data.byte = val & 0xff;
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);
161+
162+
return ret < 0 ? ret : 0;
163+
}
164+
109165
/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
110166
* instead via address 0x51, when SFP page is set to 0x03 and password to
111167
* 0xffffffff.
@@ -378,13 +434,26 @@ static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
378434
return 0;
379435
}
380436

437+
static bool mdio_i2c_check_functionality(struct i2c_adapter *i2c,
438+
enum mdio_i2c_proto protocol)
439+
{
440+
if (i2c_check_functionality(i2c, I2C_FUNC_I2C))
441+
return true;
442+
443+
if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA) &&
444+
protocol == MDIO_I2C_MARVELL_C22)
445+
return true;
446+
447+
return false;
448+
}
449+
381450
struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
382451
enum mdio_i2c_proto protocol)
383452
{
384453
struct mii_bus *mii;
385454
int ret;
386455

387-
if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
456+
if (!mdio_i2c_check_functionality(i2c, protocol))
388457
return ERR_PTR(-EINVAL);
389458

390459
mii = mdiobus_alloc();
@@ -395,6 +464,14 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
395464
mii->parent = parent;
396465
mii->priv = i2c;
397466

467+
/* Only use SMBus if we have no other choice */
468+
if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA) &&
469+
!i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
470+
mii->read = smbus_byte_mii_read_default_c22;
471+
mii->write = smbus_byte_mii_write_default_c22;
472+
return mii;
473+
}
474+
398475
switch (protocol) {
399476
case MDIO_I2C_ROLLBALL:
400477
ret = i2c_mii_init_rollball(i2c);

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)