Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68e7f45e authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller
Browse files

sfc: Use generic MDIO functions and definitions



Make use of the newly-added generic MDIO clause 45 support and remove
redundant definitions.

Add an 'efx_' prefix to the remaining driver-specific MDIO functions
and remove arguments which are redundant with efx->mdio.prtad.

Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1b1c2e95
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
config SFC
config SFC
	tristate "Solarflare Solarstorm SFC4000 support"
	tristate "Solarflare Solarstorm SFC4000 support"
	depends on PCI && INET
	depends on PCI && INET
	select MII
	select MDIO
	select CRC32
	select CRC32
	select I2C
	select I2C
	select I2C_ALGOBIT
	select I2C_ALGOBIT
+8 −2
Original line number Original line Diff line number Diff line
@@ -1300,10 +1300,16 @@ static void efx_monitor(struct work_struct *data)
static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
{
{
	struct efx_nic *efx = netdev_priv(net_dev);
	struct efx_nic *efx = netdev_priv(net_dev);
	struct mii_ioctl_data *data = if_mii(ifr);


	EFX_ASSERT_RESET_SERIALISED(efx);
	EFX_ASSERT_RESET_SERIALISED(efx);


	return generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
	/* Convert phy_id from older PRTAD/DEVAD format */
	if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) &&
	    (data->phy_id & 0xfc00) == 0x0400)
		data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400;

	return mdio_mii_ioctl(&efx->mdio, data, cmd);
}
}


/**************************************************************************
/**************************************************************************
@@ -1945,7 +1951,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
	mutex_init(&efx->mac_lock);
	mutex_init(&efx->mac_lock);
	efx->mac_op = &efx_dummy_mac_operations;
	efx->mac_op = &efx_dummy_mac_operations;
	efx->phy_op = &efx_dummy_phy_operations;
	efx->phy_op = &efx_dummy_phy_operations;
	efx->mii.dev = net_dev;
	efx->mdio.dev = net_dev;
	INIT_WORK(&efx->phy_work, efx_phy_work);
	INIT_WORK(&efx->phy_work, efx_phy_work);
	INIT_WORK(&efx->mac_work, efx_mac_work);
	INIT_WORK(&efx->mac_work, efx_mac_work);
	atomic_set(&efx->netif_stop_count, 1);
	atomic_set(&efx->netif_stop_count, 1);
+6 −12
Original line number Original line Diff line number Diff line
@@ -10,6 +10,7 @@


#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/ethtool.h>
#include <linux/mdio.h>
#include <linux/rtnetlink.h>
#include <linux/rtnetlink.h>
#include "net_driver.h"
#include "net_driver.h"
#include "workarounds.h"
#include "workarounds.h"
@@ -345,8 +346,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
	unsigned int n = 0, i;
	unsigned int n = 0, i;
	enum efx_loopback_mode mode;
	enum efx_loopback_mode mode;


	efx_fill_test(n++, strings, data, &tests->mii,
	efx_fill_test(n++, strings, data, &tests->mdio,
		      "core", 0, "mii", NULL);
		      "core", 0, "mdio", NULL);
	efx_fill_test(n++, strings, data, &tests->nvram,
	efx_fill_test(n++, strings, data, &tests->nvram,
		      "core", 0, "nvram", NULL);
		      "core", 0, "nvram", NULL);
	efx_fill_test(n++, strings, data, &tests->interrupt,
	efx_fill_test(n++, strings, data, &tests->interrupt,
@@ -529,14 +530,7 @@ static int efx_ethtool_nway_reset(struct net_device *net_dev)
{
{
	struct efx_nic *efx = netdev_priv(net_dev);
	struct efx_nic *efx = netdev_priv(net_dev);


	if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) {
	return mdio45_nway_restart(&efx->mdio);
		mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN,
				       MDIO_MMDREG_CTRL1,
				       __ffs(BMCR_ANRESTART), true);
		return 0;
	}

	return -EOPNOTSUPP;
}
}


static u32 efx_ethtool_get_link(struct net_device *net_dev)
static u32 efx_ethtool_get_link(struct net_device *net_dev)
@@ -689,7 +683,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
		return -EINVAL;
		return -EINVAL;
	}
	}


	if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) &&
	if (!(efx->phy_op->mmds & MDIO_DEVS_AN) &&
	    (wanted_fc & EFX_FC_AUTO)) {
	    (wanted_fc & EFX_FC_AUTO)) {
		EFX_LOG(efx, "PHY does not support flow control "
		EFX_LOG(efx, "PHY does not support flow control "
			"autonegotiation\n");
			"autonegotiation\n");
@@ -717,7 +711,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
	mutex_lock(&efx->mac_lock);
	mutex_lock(&efx->mac_lock);


	efx->wanted_fc = wanted_fc;
	efx->wanted_fc = wanted_fc;
	mdio_clause45_set_pause(efx);
	efx_mdio_set_pause(efx);
	__efx_reconfigure_port(efx);
	__efx_reconfigure_port(efx);


	mutex_unlock(&efx->mac_lock);
	mutex_unlock(&efx->mac_lock);
+37 −100
Original line number Original line Diff line number Diff line
@@ -2063,26 +2063,6 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
 **************************************************************************
 **************************************************************************
 */
 */


/* Use the top bit of the MII PHY id to indicate the PHY type
 * (1G/10G), with the remaining bits as the actual PHY id.
 *
 * This allows us to avoid leaking information from the mii_if_info
 * structure into other data structures.
 */
#define FALCON_PHY_ID_ID_WIDTH  EFX_WIDTH(MD_PRT_DEV_ADR)
#define FALCON_PHY_ID_ID_MASK   ((1 << FALCON_PHY_ID_ID_WIDTH) - 1)
#define FALCON_PHY_ID_WIDTH     (FALCON_PHY_ID_ID_WIDTH + 1)
#define FALCON_PHY_ID_MASK      ((1 << FALCON_PHY_ID_WIDTH) - 1)
#define FALCON_PHY_ID_10G       (1 << (FALCON_PHY_ID_WIDTH - 1))


/* Packing the clause 45 port and device fields into a single value */
#define MD_PRT_ADR_COMP_LBN   (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN)
#define MD_PRT_ADR_COMP_WIDTH  MD_PRT_ADR_WIDTH
#define MD_DEV_ADR_COMP_LBN    0
#define MD_DEV_ADR_COMP_WIDTH  MD_DEV_ADR_WIDTH


/* Wait for GMII access to complete */
/* Wait for GMII access to complete */
static int falcon_gmii_wait(struct efx_nic *efx)
static int falcon_gmii_wait(struct efx_nic *efx)
{
{
@@ -2108,49 +2088,29 @@ static int falcon_gmii_wait(struct efx_nic *efx)
	return -ETIMEDOUT;
	return -ETIMEDOUT;
}
}


/* Writes a GMII register of a PHY connected to Falcon using MDIO. */
/* Write an MDIO register of a PHY connected to Falcon. */
static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
static int falcon_mdio_write(struct net_device *net_dev,
			      int addr, int value)
			     int prtad, int devad, u16 addr, u16 value)
{
{
	struct efx_nic *efx = netdev_priv(net_dev);
	struct efx_nic *efx = netdev_priv(net_dev);
	unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
	efx_oword_t reg;
	efx_oword_t reg;
	int rc;


	/* The 'generic' prt/dev packing in mdio_10g.h is conveniently
	EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n",
	 * chosen so that the only current user, Falcon, can take the
		    prtad, devad, addr, value);
	 * packed value and use them directly.
	 * Fail to build if this assumption is broken.
	 */
	BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G);
	BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH);
	BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN);
	BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN);

	if (phy_id2 == PHY_ADDR_INVALID)
		return;

	/* See falcon_mdio_read for an explanation. */
	if (!(phy_id & FALCON_PHY_ID_10G)) {
		int mmd = ffs(efx->phy_op->mmds) - 1;
		EFX_TRACE(efx, "Fixing erroneous clause22 write\n");
		phy_id2 = mdio_clause45_pack(phy_id2, mmd)
			& FALCON_PHY_ID_ID_MASK;
	}

	EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id,
		    addr, value);


	spin_lock_bh(&efx->phy_lock);
	spin_lock_bh(&efx->phy_lock);


	/* Check MII not currently being accessed */
	/* Check MDIO not currently being accessed */
	if (falcon_gmii_wait(efx) != 0)
	rc = falcon_gmii_wait(efx);
	if (rc)
		goto out;
		goto out;


	/* Write the address/ID register */
	/* Write the address/ID register */
	EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
	EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
	falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
	falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);


	EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2);
	EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad);
	falcon_write(efx, &reg, MD_ID_REG_KER);
	falcon_write(efx, &reg, MD_ID_REG_KER);


	/* Write data */
	/* Write data */
@@ -2163,7 +2123,8 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
	falcon_write(efx, &reg, MD_CS_REG_KER);
	falcon_write(efx, &reg, MD_CS_REG_KER);


	/* Wait for data to be written */
	/* Wait for data to be written */
	if (falcon_gmii_wait(efx) != 0) {
	rc = falcon_gmii_wait(efx);
	if (rc) {
		/* Abort the write operation */
		/* Abort the write operation */
		EFX_POPULATE_OWORD_2(reg,
		EFX_POPULATE_OWORD_2(reg,
				     MD_WRC, 0,
				     MD_WRC, 0,
@@ -2174,45 +2135,28 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id,


 out:
 out:
	spin_unlock_bh(&efx->phy_lock);
	spin_unlock_bh(&efx->phy_lock);
	return rc;
}
}


/* Reads a GMII register from a PHY connected to Falcon.  If no value
/* Read an MDIO register of a PHY connected to Falcon. */
 * could be read, -1 will be returned. */
static int falcon_mdio_read(struct net_device *net_dev,
static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
			    int prtad, int devad, u16 addr)
{
{
	struct efx_nic *efx = netdev_priv(net_dev);
	struct efx_nic *efx = netdev_priv(net_dev);
	unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
	efx_oword_t reg;
	efx_oword_t reg;
	int value = -1;
	int rc;

	if (phy_addr == PHY_ADDR_INVALID)
		return -1;

	/* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G)
	 * but the generic Linux code does not make any distinction or have
	 * any state for this.
	 * We spot the case where someone tried to talk 22 to a 45 PHY and
	 * redirect the request to the lowest numbered MMD as a clause45
	 * request. This is enough to allow simple queries like id and link
	 * state to succeed. TODO: We may need to do more in future.
	 */
	if (!(phy_id & FALCON_PHY_ID_10G)) {
		int mmd = ffs(efx->phy_op->mmds) - 1;
		EFX_TRACE(efx, "Fixing erroneous clause22 read\n");
		phy_addr = mdio_clause45_pack(phy_addr, mmd)
			& FALCON_PHY_ID_ID_MASK;
	}


	spin_lock_bh(&efx->phy_lock);
	spin_lock_bh(&efx->phy_lock);


	/* Check MII not currently being accessed */
	/* Check MDIO not currently being accessed */
	if (falcon_gmii_wait(efx) != 0)
	rc = falcon_gmii_wait(efx);
	if (rc)
		goto out;
		goto out;


	EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
	EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
	falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
	falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);


	EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr);
	EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad);
	falcon_write(efx, &reg, MD_ID_REG_KER);
	falcon_write(efx, &reg, MD_ID_REG_KER);


	/* Request data to be read */
	/* Request data to be read */
@@ -2220,12 +2164,12 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
	falcon_write(efx, &reg, MD_CS_REG_KER);
	falcon_write(efx, &reg, MD_CS_REG_KER);


	/* Wait for data to become available */
	/* Wait for data to become available */
	value = falcon_gmii_wait(efx);
	rc = falcon_gmii_wait(efx);
	if (value == 0) {
	if (rc == 0) {
		falcon_read(efx, &reg, MD_RXD_REG_KER);
		falcon_read(efx, &reg, MD_RXD_REG_KER);
		value = EFX_OWORD_FIELD(reg, MD_RXD);
		rc = EFX_OWORD_FIELD(reg, MD_RXD);
		EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n",
		EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n",
			    phy_id, addr, value);
			    prtad, devad, addr, rc);
	} else {
	} else {
		/* Abort the read operation */
		/* Abort the read operation */
		EFX_POPULATE_OWORD_2(reg,
		EFX_POPULATE_OWORD_2(reg,
@@ -2233,22 +2177,13 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
				     MD_GC, 1);
				     MD_GC, 1);
		falcon_write(efx, &reg, MD_CS_REG_KER);
		falcon_write(efx, &reg, MD_CS_REG_KER);


		EFX_LOG(efx, "read from GMII 0x%x register %02x, got "
		EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n",
			"error %d\n", phy_id, addr, value);
			prtad, devad, addr, rc);
	}
	}


 out:
 out:
	spin_unlock_bh(&efx->phy_lock);
	spin_unlock_bh(&efx->phy_lock);

	return rc;
	return value;
}

static void falcon_init_mdio(struct mii_if_info *gmii)
{
	gmii->mdio_read = falcon_mdio_read;
	gmii->mdio_write = falcon_mdio_write;
	gmii->phy_id_mask = FALCON_PHY_ID_MASK;
	gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_PHY_ADR)) - 1);
}
}


static int falcon_probe_phy(struct efx_nic *efx)
static int falcon_probe_phy(struct efx_nic *efx)
@@ -2342,9 +2277,11 @@ int falcon_probe_port(struct efx_nic *efx)
	if (rc)
	if (rc)
		return rc;
		return rc;


	/* Set up GMII structure for PHY */
	/* Set up MDIO structure for PHY */
	efx->mii.supports_gmii = true;
	efx->mdio.mmds = efx->phy_op->mmds;
	falcon_init_mdio(&efx->mii);
	efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
	efx->mdio.mdio_read = falcon_mdio_read;
	efx->mdio.mdio_write = falcon_mdio_write;


	/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
	/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
	if (falcon_rev(efx) >= FALCON_REV_B0)
	if (falcon_rev(efx) >= FALCON_REV_B0)
@@ -2761,7 +2698,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
	if (rc == -EINVAL) {
	if (rc == -EINVAL) {
		EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
		EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
		efx->phy_type = PHY_TYPE_NONE;
		efx->phy_type = PHY_TYPE_NONE;
		efx->mii.phy_id = PHY_ADDR_INVALID;
		efx->mdio.prtad = MDIO_PRTAD_NONE;
		board_rev = 0;
		board_rev = 0;
		rc = 0;
		rc = 0;
	} else if (rc) {
	} else if (rc) {
@@ -2771,7 +2708,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
		struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;
		struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;


		efx->phy_type = v2->port0_phy_type;
		efx->phy_type = v2->port0_phy_type;
		efx->mii.phy_id = v2->port0_phy_addr;
		efx->mdio.prtad = v2->port0_phy_addr;
		board_rev = le16_to_cpu(v2->board_revision);
		board_rev = le16_to_cpu(v2->board_revision);


		if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
		if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
@@ -2793,7 +2730,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
	/* Read the MAC addresses */
	/* Read the MAC addresses */
	memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
	memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);


	EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id);
	EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad);


	efx_set_board_info(efx, board_rev);
	efx_set_board_info(efx, board_rev);


+0 −3
Original line number Original line Diff line number Diff line
@@ -456,9 +456,6 @@
#define MD_PRT_ADR_WIDTH 5
#define MD_PRT_ADR_WIDTH 5
#define MD_DEV_ADR_LBN 6
#define MD_DEV_ADR_LBN 6
#define MD_DEV_ADR_WIDTH 5
#define MD_DEV_ADR_WIDTH 5
/* Used for writing both at once */
#define MD_PRT_DEV_ADR_LBN 6
#define MD_PRT_DEV_ADR_WIDTH 10


/* PHY management status & mask register (DWORD read only) */
/* PHY management status & mask register (DWORD read only) */
#define MD_STAT_REG_KER 0xc50
#define MD_STAT_REG_KER 0xc50
Loading