net: sfp: create/destroy I2C mdiobus before PHY probe/after PHY release

Instead of configuring the I2C mdiobus when SFP driver is probed,
create/destroy the mdiobus before the PHY is probed for/after it is
released.

This way we can tell the mdio-i2c code which protocol to use for each
SFP transceiver.

Move the code that determines MDIO I2C protocol from
sfp_sm_probe_for_phy() to sfp_sm_mod_probe(), where most of the SFP ID
parsing is done. Don't allocate I2C bus if no PHY is expected.

Signed-off-by: Marek Behún <kabel@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Marek Behún 2022-09-30 16:21:08 +02:00 committed by David S. Miller
parent 13c8adcf22
commit e85b1347ac
2 changed files with 57 additions and 13 deletions

View File

@ -218,6 +218,7 @@ struct sfp {
struct i2c_adapter *i2c;
struct mii_bus *i2c_mii;
struct sfp_bus *sfp_bus;
enum mdio_i2c_proto mdio_protocol;
struct phy_device *mod_phy;
const struct sff_data *type;
size_t i2c_block_size;
@ -530,9 +531,6 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
{
struct mii_bus *i2c_mii;
int ret;
if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
return -EINVAL;
@ -540,7 +538,15 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
sfp->read = sfp_i2c_read;
sfp->write = sfp_i2c_write;
i2c_mii = mdio_i2c_alloc(sfp->dev, i2c);
return 0;
}
static int sfp_i2c_mdiobus_create(struct sfp *sfp)
{
struct mii_bus *i2c_mii;
int ret;
i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c);
if (IS_ERR(i2c_mii))
return PTR_ERR(i2c_mii);
@ -558,6 +564,12 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
return 0;
}
static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
{
mdiobus_unregister(sfp->i2c_mii);
sfp->i2c_mii = NULL;
}
/* Interface */
static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
{
@ -1674,6 +1686,14 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
}
}
static int sfp_sm_add_mdio_bus(struct sfp *sfp)
{
if (sfp->mdio_protocol != MDIO_I2C_NONE)
return sfp_i2c_mdiobus_create(sfp);
return 0;
}
/* Probe a SFP for a PHY device if the module supports copper - the PHY
* normally sits at I2C bus address 0x56, and may either be a clause 22
* or clause 45 PHY.
@ -1689,19 +1709,19 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
{
int err = 0;
switch (sfp->id.base.extended_cc) {
case SFF8024_ECC_10GBASE_T_SFI:
case SFF8024_ECC_10GBASE_T_SR:
case SFF8024_ECC_5GBASE_T:
case SFF8024_ECC_2_5GBASE_T:
err = sfp_sm_probe_phy(sfp, true);
switch (sfp->mdio_protocol) {
case MDIO_I2C_NONE:
break;
default:
if (sfp->id.base.e1000_base_t)
err = sfp_sm_probe_phy(sfp, false);
case MDIO_I2C_MARVELL_C22:
err = sfp_sm_probe_phy(sfp, false);
break;
case MDIO_I2C_C45:
err = sfp_sm_probe_phy(sfp, true);
break;
}
return err;
}
@ -2028,6 +2048,16 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
sfp->tx_fault_ignore = false;
if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
sfp->id.base.extended_cc == SFF8024_ECC_5GBASE_T ||
sfp->id.base.extended_cc == SFF8024_ECC_2_5GBASE_T)
sfp->mdio_protocol = MDIO_I2C_C45;
else if (sfp->id.base.e1000_base_t)
sfp->mdio_protocol = MDIO_I2C_MARVELL_C22;
else
sfp->mdio_protocol = MDIO_I2C_NONE;
sfp->quirk = sfp_lookup_quirk(&id);
if (sfp->quirk && sfp->quirk->fixup)
sfp->quirk->fixup(sfp);
@ -2204,6 +2234,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
sfp_module_stop(sfp->sfp_bus);
if (sfp->mod_phy)
sfp_sm_phy_detach(sfp);
if (sfp->i2c_mii)
sfp_i2c_mdiobus_destroy(sfp);
sfp_module_tx_disable(sfp);
sfp_soft_stop_poll(sfp);
sfp_sm_next(sfp, SFP_S_DOWN, 0);
@ -2266,6 +2298,12 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
sfp->sm_fault_retries == N_FAULT_INIT);
} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
init_done:
/* Create mdiobus and start trying for PHY */
ret = sfp_sm_add_mdio_bus(sfp);
if (ret < 0) {
sfp_sm_next(sfp, SFP_S_FAIL, 0);
break;
}
sfp->sm_phy_retries = R_PHY_RETRY;
goto phy_probe;
}

View File

@ -11,6 +11,12 @@ struct device;
struct i2c_adapter;
struct mii_bus;
enum mdio_i2c_proto {
MDIO_I2C_NONE,
MDIO_I2C_MARVELL_C22,
MDIO_I2C_C45,
};
struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
#endif