Commit e85b1347 authored by Marek Behún's avatar Marek Behún Committed by David S. Miller
Browse files

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: default avatarMarek Behún <kabel@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 13c8adcf
Loading
Loading
Loading
Loading
+51 −13
Original line number Diff line number Diff line
@@ -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)
	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;
		}
+6 −0
Original line number Diff line number Diff line
@@ -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