Skip to content

Commit

Permalink
sfc: Use generic MDIO functions and definitions
Browse files Browse the repository at this point in the history
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: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ben Hutchings authored and David S. Miller committed Apr 30, 2009
1 parent 1b1c2e9 commit 68e7f45
Show file tree
Hide file tree
Showing 14 changed files with 311 additions and 845 deletions.
2 changes: 1 addition & 1 deletion drivers/net/sfc/Kconfig
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
config SFC
tristate "Solarflare Solarstorm SFC4000 support"
depends on PCI && INET
select MII
select MDIO
select CRC32
select I2C
select I2C_ALGOBIT
Expand Down
10 changes: 8 additions & 2 deletions drivers/net/sfc/efx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct mii_ioctl_data *data = if_mii(ifr);

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);
}

/**************************************************************************
Expand Down Expand Up @@ -1945,7 +1951,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
mutex_init(&efx->mac_lock);
efx->mac_op = &efx_dummy_mac_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->mac_work, efx_mac_work);
atomic_set(&efx->netif_stop_count, 1);
Expand Down
18 changes: 6 additions & 12 deletions drivers/net/sfc/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

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

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

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

return -EOPNOTSUPP;
return mdio45_nway_restart(&efx->mdio);
}

static u32 efx_ethtool_get_link(struct net_device *net_dev)
Expand Down Expand Up @@ -689,7 +683,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
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)) {
EFX_LOG(efx, "PHY does not support flow control "
"autonegotiation\n");
Expand Down Expand Up @@ -717,7 +711,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
mutex_lock(&efx->mac_lock);

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

mutex_unlock(&efx->mac_lock);
Expand Down
137 changes: 37 additions & 100 deletions drivers/net/sfc/falcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
static int falcon_gmii_wait(struct efx_nic *efx)
{
Expand All @@ -2108,49 +2088,29 @@ static int falcon_gmii_wait(struct efx_nic *efx)
return -ETIMEDOUT;
}

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

/* The 'generic' prt/dev packing in mdio_10g.h is conveniently
* chosen so that the only current user, Falcon, can take the
* 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);
EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n",
prtad, devad, addr, value);

spin_lock_bh(&efx->phy_lock);

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

/* Write the address/ID register */
EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
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);

/* Write data */
Expand All @@ -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);

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

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

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

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;
}
int rc;

spin_lock_bh(&efx->phy_lock);

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

EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
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);

/* Request data to be read */
EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0);
falcon_write(efx, &reg, MD_CS_REG_KER);

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

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

out:
spin_unlock_bh(&efx->phy_lock);

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);
return rc;
}

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

/* Set up GMII structure for PHY */
efx->mii.supports_gmii = true;
falcon_init_mdio(&efx->mii);
/* Set up MDIO structure for PHY */
efx->mdio.mmds = efx->phy_op->mmds;
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 */
if (falcon_rev(efx) >= FALCON_REV_B0)
Expand Down Expand Up @@ -2761,7 +2698,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
if (rc == -EINVAL) {
EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
efx->phy_type = PHY_TYPE_NONE;
efx->mii.phy_id = PHY_ADDR_INVALID;
efx->mdio.prtad = MDIO_PRTAD_NONE;
board_rev = 0;
rc = 0;
} else if (rc) {
Expand All @@ -2771,7 +2708,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;

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);

if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
Expand All @@ -2793,7 +2730,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
/* Read the MAC addresses */
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);

Expand Down
3 changes: 0 additions & 3 deletions drivers/net/sfc/falcon_hwdefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,6 @@
#define MD_PRT_ADR_WIDTH 5
#define MD_DEV_ADR_LBN 6
#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) */
#define MD_STAT_REG_KER 0xc50
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/sfc/falcon_xmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx)
/* If the link is up, then check the phy side of the xaui link */
if (efx->link_up && link_ok)
if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
link_ok = efx_mdio_phyxgxs_lane_sync(efx);

return link_ok;
}
Expand Down
Loading

0 comments on commit 68e7f45

Please sign in to comment.