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:
parent
13c8adcf22
commit
e85b1347ac
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue