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

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
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
......
...@@ -1300,10 +1300,16 @@ out_requeue: ...@@ -1300,10 +1300,16 @@ out_requeue:
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, ...@@ -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);
......
...@@ -10,6 +10,7 @@ ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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);
......
...@@ -2063,26 +2063,6 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -456,9 +456,6 @@ ...@@ -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
......
...@@ -133,7 +133,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) ...@@ -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 the link is up, then check the phy side of the xaui link */
if (efx->link_up && link_ok) if (efx->link_up && link_ok)
if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) 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; return link_ok;
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include "boards.h" #include "boards.h"
#include "workarounds.h" #include "workarounds.h"
unsigned mdio_id_oui(u32 id) unsigned efx_mdio_id_oui(u32 id)
{ {
unsigned oui = 0; unsigned oui = 0;
int i; int i;
...@@ -32,52 +32,45 @@ unsigned mdio_id_oui(u32 id) ...@@ -32,52 +32,45 @@ unsigned mdio_id_oui(u32 id)
return oui; return oui;
} }
int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, int efx_mdio_reset_mmd(struct efx_nic *port, int mmd,
int spins, int spintime) int spins, int spintime)
{ {
u32 ctrl; u32 ctrl;
int phy_id = port->mii.phy_id;
/* Catch callers passing values in the wrong units (or just silly) */ /* Catch callers passing values in the wrong units (or just silly) */
EFX_BUG_ON_PARANOID(spins * spintime >= 5000); EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1, efx_mdio_write(port, mmd, MDIO_CTRL1, MDIO_CTRL1_RESET);
(1 << MDIO_MMDREG_CTRL1_RESET_LBN));
/* Wait for the reset bit to clear. */ /* Wait for the reset bit to clear. */
do { do {
msleep(spintime); msleep(spintime);
ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1); ctrl = efx_mdio_read(port, mmd, MDIO_CTRL1);
spins--; spins--;
} while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))); } while (spins && (ctrl & MDIO_CTRL1_RESET));
return spins ? spins : -ETIMEDOUT; return spins ? spins : -ETIMEDOUT;
} }
static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal)
int fault_fatal)
{ {
int status; int status;
int phy_id = efx->mii.phy_id;
if (LOOPBACK_INTERNAL(efx)) if (LOOPBACK_INTERNAL(efx))
return 0; return 0;
if (mmd != MDIO_MMD_AN) { if (mmd != MDIO_MMD_AN) {
/* Read MMD STATUS2 to check it is responding. */ /* Read MMD STATUS2 to check it is responding. */
status = mdio_clause45_read(efx, phy_id, mmd, status = efx_mdio_read(efx, mmd, MDIO_STAT2);
MDIO_MMDREG_STAT2); if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) {
if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
MDIO_MMDREG_STAT2_PRESENT_VAL) {
EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
return -EIO; return -EIO;
} }
} }
/* Read MMD STATUS 1 to check for fault. */ /* Read MMD STATUS 1 to check for fault. */
status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1); status = efx_mdio_read(efx, mmd, MDIO_STAT1);
if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) { if (status & MDIO_STAT1_FAULT) {
if (fault_fatal) { if (fault_fatal) {
EFX_ERR(efx, "PHY MMD %d reporting fatal" EFX_ERR(efx, "PHY MMD %d reporting fatal"
" fault: status %x\n", mmd, status); " fault: status %x\n", mmd, status);
...@@ -94,8 +87,7 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, ...@@ -94,8 +87,7 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
#define MDIO45_RESET_TIME 1000 /* ms */ #define MDIO45_RESET_TIME 1000 /* ms */
#define MDIO45_RESET_ITERS 100 #define MDIO45_RESET_ITERS 100
int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask)
unsigned int mmd_mask)
{ {
const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS; const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
int tries = MDIO45_RESET_ITERS; int tries = MDIO45_RESET_ITERS;
...@@ -109,16 +101,13 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, ...@@ -109,16 +101,13 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
in_reset = 0; in_reset = 0;
while (mask) { while (mask) {
if (mask & 1) { if (mask & 1) {
stat = mdio_clause45_read(efx, stat = efx_mdio_read(efx, mmd, MDIO_CTRL1);
efx->mii.phy_id,
mmd,
MDIO_MMDREG_CTRL1);
if (stat < 0) { if (stat < 0) {
EFX_ERR(efx, "failed to read status of" EFX_ERR(efx, "failed to read status of"
" MMD %d\n", mmd); " MMD %d\n", mmd);
return -EIO; return -EIO;
} }
if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)) if (stat & MDIO_CTRL1_RESET)
in_reset |= (1 << mmd); in_reset |= (1 << mmd);
} }
mask = mask >> 1; mask = mask >> 1;
...@@ -137,28 +126,26 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, ...@@ -137,28 +126,26 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
return rc; return rc;
} }
int mdio_clause45_check_mmds(struct efx_nic *efx, int efx_mdio_check_mmds(struct efx_nic *efx,
unsigned int mmd_mask, unsigned int fatal_mask) unsigned int mmd_mask, unsigned int fatal_mask)
{ {
int mmd = 0, probe_mmd, devs0, devs1; int mmd = 0, probe_mmd, devs1, devs2;
u32 devices; u32 devices;
/* Historically we have probed the PHYXS to find out what devices are /* Historically we have probed the PHYXS to find out what devices are
* present,but that doesn't work so well if the PHYXS isn't expected * present,but that doesn't work so well if the PHYXS isn't expected
* to exist, if so just find the first item in the list supplied. */ * to exist, if so just find the first item in the list supplied. */
probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS : probe_mmd = (mmd_mask & MDIO_DEVS_PHYXS) ? MDIO_MMD_PHYXS :
__ffs(mmd_mask); __ffs(mmd_mask);
/* Check all the expected MMDs are present */ /* Check all the expected MMDs are present */
devs0 = mdio_clause45_read(efx, efx->mii.phy_id, devs1 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS1);
probe_mmd, MDIO_MMDREG_DEVS0); devs2 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS2);
devs1 = mdio_clause45_read(efx, efx->mii.phy_id, if (devs1 < 0 || devs2 < 0) {
probe_mmd, MDIO_MMDREG_DEVS1);
if (devs0 < 0 || devs1 < 0) {
EFX_ERR(efx, "failed to read devices present\n"); EFX_ERR(efx, "failed to read devices present\n");
return -EIO; return -EIO;
} }
devices = devs0 | (devs1 << 16); devices = devs1 | (devs2 << 16);
if ((devices & mmd_mask) != mmd_mask) { if ((devices & mmd_mask) != mmd_mask) {
EFX_ERR(efx, "required MMDs not present: got %x, " EFX_ERR(efx, "required MMDs not present: got %x, "
"wanted %x\n", devices, mmd_mask); "wanted %x\n", devices, mmd_mask);
...@@ -170,7 +157,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, ...@@ -170,7 +157,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx,
while (mmd_mask) { while (mmd_mask) {
if (mmd_mask & 1) { if (mmd_mask & 1) {
int fault_fatal = fatal_mask & 1; int fault_fatal = fatal_mask & 1;
if (mdio_clause45_check_mmd(efx, mmd, fault_fatal)) if (efx_mdio_check_mmd(efx, mmd, fault_fatal))
return -EIO; return -EIO;
} }
mmd_mask = mmd_mask >> 1; mmd_mask = mmd_mask >> 1;
...@@ -181,13 +168,8 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, ...@@ -181,13 +168,8 @@ int mdio_clause45_check_mmds(struct efx_nic *efx,
return 0; return 0;
} }
bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
{ {
int phy_id = efx->mii.phy_id;
u32 reg;
bool ok = true;
int mmd = 0;
/* If the port is in loopback, then we should only consider a subset /* If the port is in loopback, then we should only consider a subset
* of mmd's */ * of mmd's */
if (LOOPBACK_INTERNAL(efx)) if (LOOPBACK_INTERNAL(efx))
...@@ -197,241 +179,75 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) ...@@ -197,241 +179,75 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
else if (efx_phy_mode_disabled(efx->phy_mode)) else if (efx_phy_mode_disabled(efx->phy_mode))
return false; return false;
else if (efx->loopback_mode == LOOPBACK_PHYXS) else if (efx->loopback_mode == LOOPBACK_PHYXS)
mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | mmd_mask &= ~(MDIO_DEVS_PHYXS |
MDIO_MMDREG_DEVS_PCS | MDIO_DEVS_PCS |
MDIO_MMDREG_DEVS_PMAPMD | MDIO_DEVS_PMAPMD |
MDIO_MMDREG_DEVS_AN); MDIO_DEVS_AN);
else if (efx->loopback_mode == LOOPBACK_PCS) else if (efx->loopback_mode == LOOPBACK_PCS)
mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | mmd_mask &= ~(MDIO_DEVS_PCS |
MDIO_MMDREG_DEVS_PMAPMD | MDIO_DEVS_PMAPMD |
MDIO_MMDREG_DEVS_AN); MDIO_DEVS_AN);
else if (efx->loopback_mode == LOOPBACK_PMAPMD) else if (efx->loopback_mode == LOOPBACK_PMAPMD)
mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | mmd_mask &= ~(MDIO_DEVS_PMAPMD |
MDIO_MMDREG_DEVS_AN); MDIO_DEVS_AN);
if (!mmd_mask) {
/* Use presence of XGMII faults in leui of link state */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
MDIO_PHYXS_STATUS2);
return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN));
}
while (mmd_mask) { return mdio45_links_ok(&efx->mdio, mmd_mask);
if (mmd_mask & 1) {
/* Double reads because link state is latched, and a
* read moves the current state into the register */
reg = mdio_clause45_read(efx, phy_id,
mmd, MDIO_MMDREG_STAT1);
reg = mdio_clause45_read(efx, phy_id,
mmd, MDIO_MMDREG_STAT1);
ok = ok && (reg & (1 << MDIO_MMDREG_STAT1_LINK_LBN));
}
mmd_mask = (mmd_mask >> 1);
mmd++;
}
return ok;
} }
void mdio_clause45_transmit_disable(struct efx_nic *efx) void efx_mdio_transmit_disable(struct efx_nic *efx)
{ {
mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN, MDIO_PMA_TXDIS, MDIO_PMD_TXDIS_GLOBAL,
efx->phy_mode & PHY_MODE_TX_DISABLED); efx->phy_mode & PHY_MODE_TX_DISABLED);
} }
void mdio_clause45_phy_reconfigure(struct efx_nic *efx) void efx_mdio_phy_reconfigure(struct efx_nic *efx)
{ {
int phy_id = efx->mii.phy_id; efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
MDIO_CTRL1, MDIO_PMA_CTRL1_LOOPBACK,
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, efx->loopback_mode == LOOPBACK_PMAPMD);
MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN, efx_mdio_set_flag(efx, MDIO_MMD_PCS,
efx->loopback_mode == LOOPBACK_PMAPMD); MDIO_CTRL1, MDIO_PCS_CTRL1_LOOPBACK,
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS, efx->loopback_mode == LOOPBACK_PCS);
MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, efx_mdio_set_flag(efx, MDIO_MMD_PHYXS,
efx->loopback_mode == LOOPBACK_PCS); MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK,
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, efx->loopback_mode == LOOPBACK_NETWORK);
MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN,
efx->loopback_mode == LOOPBACK_NETWORK);
} }
static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx, static void efx_mdio_set_mmd_lpower(struct efx_nic *efx,
int lpower, int mmd) int lpower, int mmd)
{ {
int phy = efx->mii.phy_id; int stat = efx_mdio_read(efx, mmd, MDIO_STAT1);
int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1);
EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n", EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n",
mmd, lpower); mmd, lpower);
if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) { if (stat & MDIO_STAT1_LPOWERABLE) {
mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1, efx_mdio_set_flag(efx, mmd, MDIO_CTRL1,
MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower); MDIO_CTRL1_LPOWER, lpower);
} }
} }
void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
int low_power, unsigned int mmd_mask) int low_power, unsigned int mmd_mask)
{ {
int mmd = 0; int mmd = 0;
mmd_mask &= ~MDIO_MMDREG_DEVS_AN; mmd_mask &= ~MDIO_DEVS_AN;
while (mmd_mask) { while (mmd_mask) {
if (mmd_mask & 1) if (mmd_mask & 1)
mdio_clause45_set_mmd_lpower(efx, low_power, mmd); efx_mdio_set_mmd_lpower(efx, low_power, mmd);
mmd_mask = (mmd_mask >> 1); mmd_mask = (mmd_mask >> 1);
mmd++; mmd++;
} }
} }
static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr)
{
int phy_id = efx->mii.phy_id;
u32 result = 0;
int reg;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr);
if (reg & ADVERTISE_10HALF)
result |= ADVERTISED_10baseT_Half;
if (reg & ADVERTISE_10FULL)
result |= ADVERTISED_10baseT_Full;
if (reg & ADVERTISE_100HALF)
result |= ADVERTISED_100baseT_Half;
if (reg & ADVERTISE_100FULL)
result |= ADVERTISED_100baseT_Full;
return result;
}
/**
* mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
* @efx: Efx NIC
* @ecmd: Buffer for settings
*
* On return the 'port', 'speed', 'supported' and 'advertising' fields of
* ecmd have been filled out.
*/
void mdio_clause45_get_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd)
{
mdio_clause45_get_settings_ext(efx, ecmd, 0, 0);
}
/** /**
* mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. * efx_mdio_set_settings - Set (some of) the PHY settings over MDIO.
* @efx: Efx NIC
* @ecmd: Buffer for settings
* @xnp: Advertised Extended Next Page state
* @xnp_lpa: Link Partner's advertised XNP state
*
* On return the 'port', 'speed', 'supported' and 'advertising' fields of
* ecmd have been filled out.
*/
void mdio_clause45_get_settings_ext(struct efx_nic *efx,
struct ethtool_cmd *ecmd,
u32 npage_adv, u32 npage_lpa)
{
int phy_id = efx->mii.phy_id;
int reg;
ecmd->transceiver = XCVR_INTERNAL;
ecmd->phy_address = phy_id;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_MMDREG_CTRL2);
switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) {
case MDIO_PMAPMD_CTRL2_10G_BT:
case MDIO_PMAPMD_CTRL2_1G_BT:
case MDIO_PMAPMD_CTRL2_100_BT:
case MDIO_PMAPMD_CTRL2_10_BT:
ecmd->port = PORT_TP;
ecmd->supported = SUPPORTED_TP;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_MMDREG_SPEED);
if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN))
ecmd->supported |= SUPPORTED_10000baseT_Full;
if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN))
ecmd->supported |= (SUPPORTED_1000baseT_Full |
SUPPORTED_1000baseT_Half);
if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN))
ecmd->supported |= (SUPPORTED_100baseT_Full |
SUPPORTED_100baseT_Half);
if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN))
ecmd->supported |= (SUPPORTED_10baseT_Full |
SUPPORTED_10baseT_Half);
ecmd->advertising = ADVERTISED_TP;
break;
/* We represent CX4 as fibre in the absence of anything better */
case MDIO_PMAPMD_CTRL2_10G_CX4:
/* All the other defined modes are flavours of optical */
default:
ecmd->port = PORT_FIBRE;
ecmd->supported = SUPPORTED_FIBRE;
ecmd->advertising = ADVERTISED_FIBRE;
break;
}
if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) {
ecmd->supported |= SUPPORTED_Autoneg;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
MDIO_MMDREG_CTRL1);
if (reg & BMCR_ANENABLE) {
ecmd->autoneg = AUTONEG_ENABLE;
ecmd->advertising |=
ADVERTISED_Autoneg |
mdio_clause45_get_an(efx, MDIO_AN_ADVERTISE) |
npage_adv;
} else
ecmd->autoneg = AUTONEG_DISABLE;
} else
ecmd->autoneg = AUTONEG_DISABLE;
if (ecmd->autoneg) {
/* If AN is complete, report best common mode,
* otherwise report best advertised mode. */
u32 modes = 0;
if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
MDIO_MMDREG_STAT1) &
(1 << MDIO_AN_STATUS_AN_DONE_LBN))
modes = (ecmd->advertising &
(mdio_clause45_get_an(efx, MDIO_AN_LPA) |
npage_lpa));
if (modes == 0)
modes = ecmd->advertising;
if (modes & ADVERTISED_10000baseT_Full) {
ecmd->speed = SPEED_10000;
ecmd->duplex = DUPLEX_FULL;
} else if (modes & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half)) {
ecmd->speed = SPEED_1000;
ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full);
} else if (modes & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
ecmd->speed = SPEED_100;
ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full);
} else {
ecmd->speed = SPEED_10;
ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full);
}
} else {
/* Report forced settings */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_MMDREG_CTRL1);
ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) *
((reg & BMCR_SPEED100) ? 100 : 10));
ecmd->duplex = (reg & BMCR_FULLDPLX ||
ecmd->speed == SPEED_10000);
}
}
/**
* mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
* @efx: Efx NIC * @efx: Efx NIC
* @ecmd: New settings * @ecmd: New settings
*/ */
int mdio_clause45_set_settings(struct efx_nic *efx, int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
struct ethtool_cmd *ecmd)
{ {
int phy_id = efx->mii.phy_id;
struct ethtool_cmd prev; struct ethtool_cmd prev;
u32 required; u32 required;
int reg; int reg;
...@@ -489,94 +305,67 @@ int mdio_clause45_set_settings(struct efx_nic *efx, ...@@ -489,94 +305,67 @@ int mdio_clause45_set_settings(struct efx_nic *efx,
ADVERTISED_1000baseT_Full)) ADVERTISED_1000baseT_Full))
reg |= ADVERTISE_NPAGE; reg |= ADVERTISE_NPAGE;
reg |= efx_fc_advertise(efx->wanted_fc); reg |= efx_fc_advertise(efx->wanted_fc);
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
MDIO_AN_ADVERTISE, reg);
/* Set up the (extended) next page if necessary */ /* Set up the (extended) next page if necessary */
if (efx->phy_op->set_npage_adv) if (efx->phy_op->set_npage_adv)
efx->phy_op->set_npage_adv(efx, ecmd->advertising); efx->phy_op->set_npage_adv(efx, ecmd->advertising);
/* Enable and restart AN */ /* Enable and restart AN */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
MDIO_MMDREG_CTRL1); reg |= MDIO_AN_CTRL1_ENABLE;
reg |= BMCR_ANENABLE;
if (!(EFX_WORKAROUND_15195(efx) && if (!(EFX_WORKAROUND_15195(efx) &&
LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) LOOPBACK_MASK(efx) & efx->phy_op->loopbacks))
reg |= BMCR_ANRESTART; reg |= MDIO_AN_CTRL1_RESTART;
if (xnp) if (xnp)
reg |= 1 << MDIO_AN_CTRL_XNP_LBN; reg |= MDIO_AN_CTRL1_XNP;
else else
reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); reg &= ~MDIO_AN_CTRL1_XNP;
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
MDIO_MMDREG_CTRL1, reg);
} else { } else {
/* Disable AN */ /* Disable AN */
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1,
MDIO_MMDREG_CTRL1, MDIO_AN_CTRL1_ENABLE, false);
__ffs(BMCR_ANENABLE), false);
/* Set the basic control bits */ /* Set the basic control bits */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1);
MDIO_MMDREG_CTRL1); reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX);
reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX |
0x003c);
if (ecmd->speed == SPEED_100) if (ecmd->speed == SPEED_100)
reg |= BMCR_SPEED100; reg |= MDIO_PMA_CTRL1_SPEED100;
if (ecmd->duplex) if (ecmd->duplex)
reg |= BMCR_FULLDPLX; reg |= MDIO_CTRL1_FULLDPLX;
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg);
MDIO_MMDREG_CTRL1, reg);
} }
return 0; return 0;
} }
void mdio_clause45_set_pause(struct efx_nic *efx) void efx_mdio_set_pause(struct efx_nic *efx)
{ {
int phy_id = efx->mii.phy_id;
int reg; int reg;
if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { if (efx->phy_op->mmds & MDIO_DEVS_AN) {
/* Set pause capability advertising */ /* Set pause capability advertising */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
MDIO_AN_ADVERTISE);
reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
reg |= efx_fc_advertise(efx->wanted_fc); reg |= efx_fc_advertise(efx->wanted_fc);
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
MDIO_AN_ADVERTISE, reg);
/* Restart auto-negotiation */ /* Restart auto-negotiation */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
MDIO_MMDREG_CTRL1); if (reg & MDIO_AN_CTRL1_ENABLE) {
if (reg & BMCR_ANENABLE) { reg |= MDIO_AN_CTRL1_RESTART;
reg |= BMCR_ANRESTART; efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
MDIO_MMDREG_CTRL1, reg);
} }
} }
} }
enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
{ {
int phy_id = efx->mii.phy_id;
int lpa; int lpa;
if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) if (!(efx->phy_op->mmds & MDIO_DEVS_AN))
return efx->wanted_fc; return efx->wanted_fc;
lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); lpa = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA);
return efx_fc_resolve(efx->wanted_fc, lpa); return efx_fc_resolve(efx->wanted_fc, lpa);
} }
void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev,
u16 addr, int bit, bool sense)
{
int old_val = mdio_clause45_read(efx, prt, dev, addr);
int new_val;
if (sense)
new_val = old_val | (1 << bit);
else
new_val = old_val & ~(1 << bit);
if (old_val != new_val)
mdio_clause45_write(efx, prt, dev, addr, new_val);
}
...@@ -10,247 +10,53 @@ ...@@ -10,247 +10,53 @@
#ifndef EFX_MDIO_10G_H #ifndef EFX_MDIO_10G_H
#define EFX_MDIO_10G_H #define EFX_MDIO_10G_H
#include <linux/mdio.h>
/* /*
* Definitions needed for doing 10G MDIO as specified in clause 45 * Helper functions for doing 10G MDIO as specified in IEEE 802.3 clause 45.
* MDIO, which do not appear in Linux yet. Also some helper functions.
*/ */
#include "efx.h" #include "efx.h"
#include "boards.h" #include "boards.h"
/* Numbering of the MDIO Manageable Devices (MMDs) */ static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; }
/* Physical Medium Attachment/ Physical Medium Dependent sublayer */ static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; }
#define MDIO_MMD_PMAPMD (1) extern unsigned efx_mdio_id_oui(u32 id);
/* WAN Interface Sublayer */
#define MDIO_MMD_WIS (2)
/* Physical Coding Sublayer */
#define MDIO_MMD_PCS (3)
/* PHY Extender Sublayer */
#define MDIO_MMD_PHYXS (4)
/* Extender Sublayer */
#define MDIO_MMD_DTEXS (5)
/* Transmission convergence */
#define MDIO_MMD_TC (6)
/* Auto negotiation */
#define MDIO_MMD_AN (7)
/* Clause 22 extension */
#define MDIO_MMD_C22EXT 29
/* Generic register locations */
#define MDIO_MMDREG_CTRL1 (0)
#define MDIO_MMDREG_STAT1 (1)
#define MDIO_MMDREG_IDHI (2)
#define MDIO_MMDREG_IDLOW (3)
#define MDIO_MMDREG_SPEED (4)
#define MDIO_MMDREG_DEVS0 (5)
#define MDIO_MMDREG_DEVS1 (6)
#define MDIO_MMDREG_CTRL2 (7)
#define MDIO_MMDREG_STAT2 (8)
#define MDIO_MMDREG_TXDIS (9)
/* Bits in MMDREG_CTRL1 */
/* Reset */
#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
/* Loopback */
/* Loopback bit for WIS, PCS, PHYSX and DTEXS */
#define MDIO_MMDREG_CTRL1_LBACK_LBN (14)
#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1)
/* Low power */
#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11)
#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1)
/* Bits in MMDREG_STAT1 */
#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
/* Link state */
#define MDIO_MMDREG_STAT1_LINK_LBN (2)
#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
/* Low power ability */
#define MDIO_MMDREG_STAT1_LPABLE_LBN (1)
#define MDIO_MMDREG_STAT1_LPABLE_WIDTH (1)
/* Bits in combined ID regs */
static inline unsigned mdio_id_rev(u32 id) { return id & 0xf; }
static inline unsigned mdio_id_model(u32 id) { return (id >> 4) & 0x3f; }
extern unsigned mdio_id_oui(u32 id);
/* Bits in MMDREG_DEVS0/1. Someone thoughtfully layed things out
* so the 'bit present' bit number of an MMD is the number of
* that MMD */
#define DEV_PRESENT_BIT(_b) (1 << _b)
#define MDIO_MMDREG_DEVS_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
#define MDIO_MMDREG_DEVS_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
#define MDIO_MMDREG_DEVS_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
#define MDIO_MMDREG_DEVS_AN DEV_PRESENT_BIT(MDIO_MMD_AN)
#define MDIO_MMDREG_DEVS_C22EXT DEV_PRESENT_BIT(MDIO_MMD_C22EXT)
/* Bits in MMDREG_SPEED */
#define MDIO_MMDREG_SPEED_10G_LBN 0
#define MDIO_MMDREG_SPEED_10G_WIDTH 1
#define MDIO_MMDREG_SPEED_1000M_LBN 4
#define MDIO_MMDREG_SPEED_1000M_WIDTH 1
#define MDIO_MMDREG_SPEED_100M_LBN 5
#define MDIO_MMDREG_SPEED_100M_WIDTH 1
#define MDIO_MMDREG_SPEED_10M_LBN 6
#define MDIO_MMDREG_SPEED_10M_WIDTH 1
/* Bits in MMDREG_STAT2 */
#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
/* Bits in MMDREG_TXDIS */
#define MDIO_MMDREG_TXDIS_GLOBAL_LBN (0)
#define MDIO_MMDREG_TXDIS_GLOBAL_WIDTH (1)
/* MMD-specific bits, ordered by MMD, then register */
#define MDIO_PMAPMD_CTRL1_LBACK_LBN (0)
#define MDIO_PMAPMD_CTRL1_LBACK_WIDTH (1)
/* PMA type (4 bits) */
#define MDIO_PMAPMD_CTRL2_10G_CX4 (0x0)
#define MDIO_PMAPMD_CTRL2_10G_EW (0x1)
#define MDIO_PMAPMD_CTRL2_10G_LW (0x2)
#define MDIO_PMAPMD_CTRL2_10G_SW (0x3)
#define MDIO_PMAPMD_CTRL2_10G_LX4 (0x4)
#define MDIO_PMAPMD_CTRL2_10G_ER (0x5)
#define MDIO_PMAPMD_CTRL2_10G_LR (0x6)
#define MDIO_PMAPMD_CTRL2_10G_SR (0x7)
/* Reserved */
#define MDIO_PMAPMD_CTRL2_10G_BT (0x9)
/* Reserved */
/* Reserved */
#define MDIO_PMAPMD_CTRL2_1G_BT (0xc)
/* Reserved */
#define MDIO_PMAPMD_CTRL2_100_BT (0xe)
#define MDIO_PMAPMD_CTRL2_10_BT (0xf)
#define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf)
/* PMA 10GBT registers */
#define MDIO_PMAPMD_10GBT_TXPWR (131)
#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN (0)
#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_WIDTH (1)
/* PHY XGXS Status 2 */
#define MDIO_PHYXS_STATUS2 (8)
#define MDIO_PHYXS_STATUS2_RX_FAULT_LBN 10
/* PHY XGXS lane state */
#define MDIO_PHYXS_LANE_STATE (0x18)
#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
/* AN registers */
#define MDIO_AN_CTRL_XNP_LBN 13
#define MDIO_AN_STATUS (1)
#define MDIO_AN_STATUS_XNP_LBN (7)
#define MDIO_AN_STATUS_PAGE_LBN (6)
#define MDIO_AN_STATUS_AN_DONE_LBN (5)
#define MDIO_AN_STATUS_LP_AN_CAP_LBN (0)
#define MDIO_AN_ADVERTISE 16
#define MDIO_AN_ADVERTISE_XNP_LBN 12
#define MDIO_AN_LPA 19
#define MDIO_AN_XNP 22
#define MDIO_AN_LPA_XNP 25
#define MDIO_AN_10GBT_CTRL 32
#define MDIO_AN_10GBT_CTRL_ADV_10G_LBN 12
#define MDIO_AN_10GBT_STATUS (33)
#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */
#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */
#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */
#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */
#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */
#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9) /* LP Training Reset Request */
static inline int efx_mdio_read(struct efx_nic *efx, int devad, int addr)
/* Packing of the prt and dev arguments of clause 45 style MDIO into a
* single int so they can be passed into the mdio_read/write functions
* that currently exist. Note that as Falcon is the only current user,
* the packed form is chosen to match what Falcon needs to write into
* a register. This is checked at compile-time so do not change it. If
* your target chip needs things layed out differently you will need
* to unpack the arguments in your chip-specific mdio functions.
*/
/* These are defined by the standard. */
#define MDIO45_PRT_ID_WIDTH (5)
#define MDIO45_DEV_ID_WIDTH (5)
/* The prt ID is just packed in immediately to the left of the dev ID */
#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH)
#define MDIO45_PRT_ID_MASK ((1 << MDIO45_PRT_DEV_WIDTH) - 1)
/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */
#define MDIO45_XPRT_ID_WIDTH (MDIO45_PRT_DEV_WIDTH + 1)
#define MDIO45_XPRT_ID_MASK ((1 << MDIO45_XPRT_ID_WIDTH) - 1)
#define MDIO45_XPRT_ID_IS10G (1 << (MDIO45_XPRT_ID_WIDTH - 1))
#define MDIO45_PRT_ID_COMP_LBN MDIO45_DEV_ID_WIDTH
#define MDIO45_PRT_ID_COMP_WIDTH MDIO45_PRT_ID_WIDTH
#define MDIO45_DEV_ID_COMP_LBN 0
#define MDIO45_DEV_ID_COMP_WIDTH MDIO45_DEV_ID_WIDTH
/* Compose port and device into a phy_id */
static inline int mdio_clause45_pack(u8 prt, u8 dev)
{
efx_dword_t phy_id;
EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt,
MDIO45_DEV_ID_COMP, dev);
return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id);
}
static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
{ {
efx_dword_t phy_id; return efx->mdio.mdio_read(efx->net_dev, efx->mdio.prtad, devad, addr);
EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val);
*prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP);
*dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP);
} }
static inline int mdio_clause45_read(struct efx_nic *efx, static inline void
u8 prt, u8 dev, u16 addr) efx_mdio_write(struct efx_nic *efx, int devad, int addr, int value)
{ {
return efx->mii.mdio_read(efx->net_dev, efx->mdio.mdio_write(efx->net_dev, efx->mdio.prtad, devad, addr, value);
mdio_clause45_pack(prt, dev), addr);
} }
static inline void mdio_clause45_write(struct efx_nic *efx, static inline u32 efx_mdio_read_id(struct efx_nic *efx, int mmd)
u8 prt, u8 dev, u16 addr, int value)
{
efx->mii.mdio_write(efx->net_dev,
mdio_clause45_pack(prt, dev), addr, value);
}
static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd)
{ {
int phy_id = efx->mii.phy_id; u16 id_low = efx_mdio_read(efx, mmd, MDIO_DEVID2);
u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW); u16 id_hi = efx_mdio_read(efx, mmd, MDIO_DEVID1);
u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
return (id_hi << 16) | (id_low); return (id_hi << 16) | (id_low);
} }
static inline bool mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx) static inline bool efx_mdio_phyxgxs_lane_sync(struct efx_nic *efx)
{ {
int i, lane_status; int i, lane_status;
bool sync; bool sync;
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
lane_status = mdio_clause45_read(efx, efx->mii.phy_id, lane_status = efx_mdio_read(efx, MDIO_MMD_PHYXS,
MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT);
MDIO_PHYXS_LANE_STATE);
sync = !!(lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)); sync = !!(lane_status & MDIO_PHYXS_LNSTAT_ALIGN);
if (!sync) if (!sync)
EFX_LOG(efx, "XGXS lane status: %x\n", lane_status); EFX_LOG(efx, "XGXS lane status: %x\n", lane_status);
return sync; return sync;
} }
extern const char *mdio_clause45_mmd_name(int mmd); extern const char *efx_mdio_mmd_name(int mmd);
/* /*
* Reset a specific MMD and wait for reset to clear. * Reset a specific MMD and wait for reset to clear.
...@@ -258,54 +64,47 @@ extern const char *mdio_clause45_mmd_name(int mmd); ...@@ -258,54 +64,47 @@ extern const char *mdio_clause45_mmd_name(int mmd);
* *
* This function will sleep * This function will sleep
*/ */
extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd, extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd,
int spins, int spintime); int spins, int spintime);
/* As mdio_clause45_check_mmd but for multiple MMDs */ /* As efx_mdio_check_mmd but for multiple MMDs */
int mdio_clause45_check_mmds(struct efx_nic *efx, int efx_mdio_check_mmds(struct efx_nic *efx,
unsigned int mmd_mask, unsigned int fatal_mask); unsigned int mmd_mask, unsigned int fatal_mask);
/* Check the link status of specified mmds in bit mask */ /* Check the link status of specified mmds in bit mask */
extern bool mdio_clause45_links_ok(struct efx_nic *efx, extern bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask);
unsigned int mmd_mask);
/* Generic transmit disable support though PMAPMD */ /* Generic transmit disable support though PMAPMD */
extern void mdio_clause45_transmit_disable(struct efx_nic *efx); extern void efx_mdio_transmit_disable(struct efx_nic *efx);
/* Generic part of reconfigure: set/clear loopback bits */ /* Generic part of reconfigure: set/clear loopback bits */
extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); extern void efx_mdio_phy_reconfigure(struct efx_nic *efx);
/* Set the power state of the specified MMDs */ /* Set the power state of the specified MMDs */
extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
int low_power, unsigned int mmd_mask); int low_power, unsigned int mmd_mask);
/* Read (some of) the PHY settings over MDIO */
extern void mdio_clause45_get_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd);
/* Read (some of) the PHY settings over MDIO */
extern void
mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd,
u32 xnp, u32 xnp_lpa);
/* Set (some of) the PHY settings over MDIO */ /* Set (some of) the PHY settings over MDIO */
extern int mdio_clause45_set_settings(struct efx_nic *efx, extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd);
struct ethtool_cmd *ecmd);
/* Set pause parameters to be advertised through AN (if available) */ /* Set pause parameters to be advertised through AN (if available) */
extern void mdio_clause45_set_pause(struct efx_nic *efx); extern void efx_mdio_set_pause(struct efx_nic *efx);
/* Get pause parameters from AN if available (otherwise return /* Get pause parameters from AN if available (otherwise return
* requested pause parameters) * requested pause parameters)
*/ */
enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx); enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx);
/* Wait for specified MMDs to exit reset within a timeout */ /* Wait for specified MMDs to exit reset within a timeout */
extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx,
unsigned int mmd_mask); unsigned int mmd_mask);
/* Set or clear flag, debouncing */ /* Set or clear flag, debouncing */
extern void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, static inline void
u16 addr, int bit, bool sense); efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr,
int mask, bool state)
{
mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state);
}
#endif /* EFX_MDIO_10G_H */ #endif /* EFX_MDIO_10G_H */
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/mii.h> #include <linux/mdio.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/device.h> #include <linux/device.h>
...@@ -458,8 +458,6 @@ enum phy_type { ...@@ -458,8 +458,6 @@ enum phy_type {
PHY_TYPE_MAX /* Insert any new items before this */ PHY_TYPE_MAX /* Insert any new items before this */
}; };
#define PHY_ADDR_INVALID 0xff
#define EFX_IS10G(efx) ((efx)->link_speed == 10000) #define EFX_IS10G(efx) ((efx)->link_speed == 10000)
enum nic_state { enum nic_state {
...@@ -758,7 +756,7 @@ union efx_multicast_hash { ...@@ -758,7 +756,7 @@ union efx_multicast_hash {
* @phy_lock: PHY access lock * @phy_lock: PHY access lock
* @phy_op: PHY interface * @phy_op: PHY interface
* @phy_data: PHY private data (including PHY-specific stats) * @phy_data: PHY private data (including PHY-specific stats)
* @mii: PHY interface * @mdio: PHY MDIO interface
* @phy_mode: PHY operating mode. Serialised by @mac_lock. * @phy_mode: PHY operating mode. Serialised by @mac_lock.
* @mac_up: MAC link state * @mac_up: MAC link state
* @link_up: Link status * @link_up: Link status
...@@ -845,7 +843,7 @@ struct efx_nic { ...@@ -845,7 +843,7 @@ struct efx_nic {
struct work_struct phy_work; struct work_struct phy_work;
struct efx_phy_operations *phy_op; struct efx_phy_operations *phy_op;
void *phy_data; void *phy_data;
struct mii_if_info mii; struct mdio_if_info mdio;
enum efx_phy_mode phy_mode; enum efx_phy_mode phy_mode;
bool mac_up; bool mac_up;
......
...@@ -80,39 +80,38 @@ struct efx_loopback_state { ...@@ -80,39 +80,38 @@ struct efx_loopback_state {
* *
**************************************************************************/ **************************************************************************/
static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests)
{ {
int rc = 0; int rc = 0;
int devad = __ffs(efx->mdio.mmds);
u16 physid1, physid2; u16 physid1, physid2;
struct mii_if_info *mii = &efx->mii;
struct net_device *net_dev = efx->net_dev;
if (efx->phy_type == PHY_TYPE_NONE) if (efx->phy_type == PHY_TYPE_NONE)
return 0; return 0;
mutex_lock(&efx->mac_lock); mutex_lock(&efx->mac_lock);
tests->mii = -1; tests->mdio = -1;
physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
if ((physid1 == 0x0000) || (physid1 == 0xffff) || if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
(physid2 == 0x0000) || (physid2 == 0xffff)) { (physid2 == 0x0000) || (physid2 == 0xffff)) {
EFX_ERR(efx, "no MII PHY present with ID %d\n", EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
mii->phy_id); efx->mdio.prtad);
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
if (EFX_IS10G(efx)) { if (EFX_IS10G(efx)) {
rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0);
if (rc) if (rc)
goto out; goto out;
} }
out: out:
mutex_unlock(&efx->mac_lock); mutex_unlock(&efx->mac_lock);
tests->mii = rc ? -1 : 1; tests->mdio = rc ? -1 : 1;
return rc; return rc;
} }
...@@ -673,7 +672,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, ...@@ -673,7 +672,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
/* Online (i.e. non-disruptive) testing /* Online (i.e. non-disruptive) testing
* This checks interrupt generation, event delivery and PHY presence. */ * This checks interrupt generation, event delivery and PHY presence. */
rc = efx_test_mii(efx, tests); rc = efx_test_mdio(efx, tests);
if (rc && !rc_test) if (rc && !rc_test)
rc_test = rc; rc_test = rc;
......
...@@ -32,7 +32,7 @@ struct efx_loopback_self_tests { ...@@ -32,7 +32,7 @@ struct efx_loopback_self_tests {
*/ */
struct efx_self_tests { struct efx_self_tests {
/* online tests */ /* online tests */
int mii; int mdio;
int nvram; int nvram;
int interrupt; int interrupt;
int eventq_dma[EFX_MAX_CHANNELS]; int eventq_dma[EFX_MAX_CHANNELS];
......
...@@ -23,10 +23,10 @@ ...@@ -23,10 +23,10 @@
* clause 22 extension MMD, but since it doesn't have all the generic * clause 22 extension MMD, but since it doesn't have all the generic
* MMD registers it is pointless to include it here. * MMD registers it is pointless to include it here.
*/ */
#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \ #define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \
MDIO_MMDREG_DEVS_PCS | \ MDIO_DEVS_PCS | \
MDIO_MMDREG_DEVS_PHYXS | \ MDIO_DEVS_PHYXS | \
MDIO_MMDREG_DEVS_AN) MDIO_DEVS_AN)
#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \
(1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PCS) | \
...@@ -153,10 +153,6 @@ ...@@ -153,10 +153,6 @@
#define LOOPBACK_NEAR_LBN (8) #define LOOPBACK_NEAR_LBN (8)
#define LOOPBACK_NEAR_WIDTH (1) #define LOOPBACK_NEAR_WIDTH (1)
#define PCS_10GBASET_STAT1 32
#define PCS_10GBASET_BLKLK_LBN 0
#define PCS_10GBASET_BLKLK_WIDTH 1
/* Boot status register */ /* Boot status register */
#define PCS_BOOT_STATUS_REG 53248 #define PCS_BOOT_STATUS_REG 53248
#define PCS_BOOT_FATAL_ERROR_LBN 0 #define PCS_BOOT_FATAL_ERROR_LBN 0
...@@ -206,10 +202,8 @@ static ssize_t show_phy_short_reach(struct device *dev, ...@@ -206,10 +202,8 @@ static ssize_t show_phy_short_reach(struct device *dev,
struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
int reg; int reg;
reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR);
MDIO_PMAPMD_10GBT_TXPWR); return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT));
return sprintf(buf, "%d\n",
!!(reg & (1 << MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN)));
} }
static ssize_t set_phy_short_reach(struct device *dev, static ssize_t set_phy_short_reach(struct device *dev,
...@@ -219,10 +213,9 @@ static ssize_t set_phy_short_reach(struct device *dev, ...@@ -219,10 +213,9 @@ static ssize_t set_phy_short_reach(struct device *dev,
struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
rtnl_lock(); rtnl_lock();
mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
MDIO_PMAPMD_10GBT_TXPWR, MDIO_PMA_10GBT_TXPWR_SHORT,
MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN, count != 0 && *buf != '0');
count != 0 && *buf != '0');
efx_reconfigure_port(efx); efx_reconfigure_port(efx);
rtnl_unlock(); rtnl_unlock();
...@@ -238,9 +231,8 @@ int sft9001_wait_boot(struct efx_nic *efx) ...@@ -238,9 +231,8 @@ int sft9001_wait_boot(struct efx_nic *efx)
int boot_stat; int boot_stat;
for (;;) { for (;;) {
boot_stat = mdio_clause45_read(efx, efx->mii.phy_id, boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS,
MDIO_MMD_PCS, PCS_BOOT_STATUS_REG);
PCS_BOOT_STATUS_REG);
if (boot_stat >= 0) { if (boot_stat >= 0) {
EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat); EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat);
switch (boot_stat & switch (boot_stat &
...@@ -286,38 +278,32 @@ int sft9001_wait_boot(struct efx_nic *efx) ...@@ -286,38 +278,32 @@ int sft9001_wait_boot(struct efx_nic *efx)
static int tenxpress_init(struct efx_nic *efx) static int tenxpress_init(struct efx_nic *efx)
{ {
int phy_id = efx->mii.phy_id;
int reg; int reg;
if (efx->phy_type == PHY_TYPE_SFX7101) { if (efx->phy_type == PHY_TYPE_SFX7101) {
/* Enable 312.5 MHz clock */ /* Enable 312.5 MHz clock */
mdio_clause45_write(efx, phy_id, efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
MDIO_MMD_PCS, PCS_TEST_SELECT_REG, 1 << CLK312_EN_LBN);
1 << CLK312_EN_LBN);
} else { } else {
/* Enable 312.5 MHz clock and GMII */ /* Enable 312.5 MHz clock and GMII */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
PMA_PMD_XCONTROL_REG);
reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) |
(1 << PMA_PMD_EXT_CLK_OUT_LBN) | (1 << PMA_PMD_EXT_CLK_OUT_LBN) |
(1 << PMA_PMD_EXT_CLK312_LBN) | (1 << PMA_PMD_EXT_CLK312_LBN) |
(1 << PMA_PMD_EXT_ROBUST_LBN)); (1 << PMA_PMD_EXT_ROBUST_LBN));
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
PMA_PMD_XCONTROL_REG, reg); efx_mdio_set_flag(efx, MDIO_MMD_C22EXT,
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN,
GPHY_XCONTROL_REG, GPHY_ISOLATE_LBN, false);
false);
} }
/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
if (efx->phy_type == PHY_TYPE_SFX7101) { if (efx->phy_type == PHY_TYPE_SFX7101) {
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
PMA_PMD_LED_CTRL_REG, 1 << PMA_PMA_LED_ACTIVITY_LBN, true);
PMA_PMA_LED_ACTIVITY_LBN, efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
true); PMA_PMD_LED_DEFAULT);
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT);
} }
return 0; return 0;
...@@ -337,22 +323,19 @@ static int tenxpress_phy_init(struct efx_nic *efx) ...@@ -337,22 +323,19 @@ static int tenxpress_phy_init(struct efx_nic *efx)
if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
if (efx->phy_type == PHY_TYPE_SFT9001A) { if (efx->phy_type == PHY_TYPE_SFT9001A) {
int reg; int reg;
reg = mdio_clause45_read(efx, efx->mii.phy_id, reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
PMA_PMD_XCONTROL_REG);
reg |= (1 << PMA_PMD_EXT_SSR_LBN); reg |= (1 << PMA_PMD_EXT_SSR_LBN);
mdio_clause45_write(efx, efx->mii.phy_id, efx_mdio_write(efx, MDIO_MMD_PMAPMD,
MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
PMA_PMD_XCONTROL_REG, reg);
mdelay(200); mdelay(200);
} }
rc = mdio_clause45_wait_reset_mmds(efx, rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
TENXPRESS_REQUIRED_DEVS);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
} }
...@@ -360,7 +343,7 @@ static int tenxpress_phy_init(struct efx_nic *efx) ...@@ -360,7 +343,7 @@ static int tenxpress_phy_init(struct efx_nic *efx)
rc = tenxpress_init(efx); rc = tenxpress_init(efx);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
mdio_clause45_set_pause(efx); efx_mdio_set_pause(efx);
if (efx->phy_type == PHY_TYPE_SFT9001B) { if (efx->phy_type == PHY_TYPE_SFT9001B) {
rc = device_create_file(&efx->pci_dev->dev, rc = device_create_file(&efx->pci_dev->dev,
...@@ -395,17 +378,14 @@ static int tenxpress_special_reset(struct efx_nic *efx) ...@@ -395,17 +378,14 @@ static int tenxpress_special_reset(struct efx_nic *efx)
efx_stats_disable(efx); efx_stats_disable(efx);
/* Initiate reset */ /* Initiate reset */
reg = mdio_clause45_read(efx, efx->mii.phy_id, reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
reg |= (1 << PMA_PMD_EXT_SSR_LBN); reg |= (1 << PMA_PMD_EXT_SSR_LBN);
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
PMA_PMD_XCONTROL_REG, reg);
mdelay(200); mdelay(200);
/* Wait for the blocks to come out of reset */ /* Wait for the blocks to come out of reset */
rc = mdio_clause45_wait_reset_mmds(efx, rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
TENXPRESS_REQUIRED_DEVS);
if (rc < 0) if (rc < 0)
goto out; goto out;
...@@ -424,7 +404,6 @@ out: ...@@ -424,7 +404,6 @@ out:
static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
{ {
struct tenxpress_phy_data *pd = efx->phy_data; struct tenxpress_phy_data *pd = efx->phy_data;
int phy_id = efx->mii.phy_id;
bool bad_lp; bool bad_lp;
int reg; int reg;
...@@ -432,11 +411,10 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) ...@@ -432,11 +411,10 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
bad_lp = false; bad_lp = false;
} else { } else {
/* Check that AN has started but not completed. */ /* Check that AN has started but not completed. */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1);
MDIO_AN_STATUS); if (!(reg & MDIO_AN_STAT1_LPABLE))
if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN)))
return; /* LP status is unknown */ return; /* LP status is unknown */
bad_lp = !(reg & (1 << MDIO_AN_STATUS_AN_DONE_LBN)); bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE);
if (bad_lp) if (bad_lp)
pd->bad_lp_tries++; pd->bad_lp_tries++;
} }
...@@ -448,8 +426,8 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) ...@@ -448,8 +426,8 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
/* Use the RX (red) LED as an error indicator once we've seen AN /* Use the RX (red) LED as an error indicator once we've seen AN
* failure several times in a row, and also log a message. */ * failure several times in a row, and also log a message. */
if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
PMA_PMD_LED_OVERR_REG); PMA_PMD_LED_OVERR_REG);
reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);
if (!bad_lp) { if (!bad_lp) {
reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;
...@@ -460,23 +438,22 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) ...@@ -460,23 +438,22 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
" supports 10GBASE-T ONLY, so no link can" " supports 10GBASE-T ONLY, so no link can"
" be established\n"); " be established\n");
} }
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD,
PMA_PMD_LED_OVERR_REG, reg); PMA_PMD_LED_OVERR_REG, reg);
pd->bad_lp_tries = bad_lp; pd->bad_lp_tries = bad_lp;
} }
} }
static bool sfx7101_link_ok(struct efx_nic *efx) static bool sfx7101_link_ok(struct efx_nic *efx)
{ {
return mdio_clause45_links_ok(efx, return efx_mdio_links_ok(efx,
MDIO_MMDREG_DEVS_PMAPMD | MDIO_DEVS_PMAPMD |
MDIO_MMDREG_DEVS_PCS | MDIO_DEVS_PCS |
MDIO_MMDREG_DEVS_PHYXS); MDIO_DEVS_PHYXS);
} }
static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{ {
int phy_id = efx->mii.phy_id;
u32 reg; u32 reg;
if (efx_phy_mode_disabled(efx->phy_mode)) if (efx_phy_mode_disabled(efx->phy_mode))
...@@ -484,50 +461,43 @@ static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) ...@@ -484,50 +461,43 @@ static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd)
else if (efx->loopback_mode == LOOPBACK_GPHY) else if (efx->loopback_mode == LOOPBACK_GPHY)
return true; return true;
else if (efx->loopback_mode) else if (efx->loopback_mode)
return mdio_clause45_links_ok(efx, return efx_mdio_links_ok(efx,
MDIO_MMDREG_DEVS_PMAPMD | MDIO_DEVS_PMAPMD |
MDIO_MMDREG_DEVS_PHYXS); MDIO_DEVS_PHYXS);
/* We must use the same definition of link state as LASI, /* We must use the same definition of link state as LASI,
* otherwise we can miss a link state transition * otherwise we can miss a link state transition
*/ */
if (ecmd->speed == 10000) { if (ecmd->speed == 10000) {
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
PCS_10GBASET_STAT1); return reg & MDIO_PCS_10GBRT_STAT1_BLKLK;
return reg & (1 << PCS_10GBASET_BLKLK_LBN);
} else { } else {
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG);
C22EXT_STATUS_REG);
return reg & (1 << C22EXT_STATUS_LINK_LBN); return reg & (1 << C22EXT_STATUS_LINK_LBN);
} }
} }
static void tenxpress_ext_loopback(struct efx_nic *efx) static void tenxpress_ext_loopback(struct efx_nic *efx)
{ {
int phy_id = efx->mii.phy_id; efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,
1 << LOOPBACK_NEAR_LBN,
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, efx->loopback_mode == LOOPBACK_PHYXS);
PHYXS_TEST1, LOOPBACK_NEAR_LBN,
efx->loopback_mode == LOOPBACK_PHYXS);
if (efx->phy_type != PHY_TYPE_SFX7101) if (efx->phy_type != PHY_TYPE_SFX7101)
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG,
GPHY_XCONTROL_REG, 1 << GPHY_LOOPBACK_NEAR_LBN,
GPHY_LOOPBACK_NEAR_LBN, efx->loopback_mode == LOOPBACK_GPHY);
efx->loopback_mode == LOOPBACK_GPHY);
} }
static void tenxpress_low_power(struct efx_nic *efx) static void tenxpress_low_power(struct efx_nic *efx)
{ {
int phy_id = efx->mii.phy_id;
if (efx->phy_type == PHY_TYPE_SFX7101) if (efx->phy_type == PHY_TYPE_SFX7101)
mdio_clause45_set_mmds_lpower( efx_mdio_set_mmds_lpower(
efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER), efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
TENXPRESS_REQUIRED_DEVS); TENXPRESS_REQUIRED_DEVS);
else else
mdio_clause45_set_flag( efx_mdio_set_flag(
efx, phy_id, MDIO_MMD_PMAPMD, efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG,
PMA_PMD_XCONTROL_REG, PMA_PMD_EXT_LPOWER_LBN, 1 << PMA_PMD_EXT_LPOWER_LBN,
!!(efx->phy_mode & PHY_MODE_LOW_POWER)); !!(efx->phy_mode & PHY_MODE_LOW_POWER));
} }
...@@ -568,8 +538,8 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) ...@@ -568,8 +538,8 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx)
WARN_ON(rc); WARN_ON(rc);
} }
mdio_clause45_transmit_disable(efx); efx_mdio_transmit_disable(efx);
mdio_clause45_phy_reconfigure(efx); efx_mdio_phy_reconfigure(efx);
tenxpress_ext_loopback(efx); tenxpress_ext_loopback(efx);
phy_data->loopback_mode = efx->loopback_mode; phy_data->loopback_mode = efx->loopback_mode;
...@@ -585,7 +555,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) ...@@ -585,7 +555,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx)
efx->link_fd = ecmd.duplex == DUPLEX_FULL; efx->link_fd = ecmd.duplex == DUPLEX_FULL;
efx->link_up = sft9001_link_ok(efx, &ecmd); efx->link_up = sft9001_link_ok(efx, &ecmd);
} }
efx->link_fc = mdio_clause45_get_pause(efx); efx->link_fc = efx_mdio_get_pause(efx);
} }
/* Poll PHY for interrupt */ /* Poll PHY for interrupt */
...@@ -599,7 +569,7 @@ static void tenxpress_phy_poll(struct efx_nic *efx) ...@@ -599,7 +569,7 @@ static void tenxpress_phy_poll(struct efx_nic *efx)
if (link_ok != efx->link_up) { if (link_ok != efx->link_up) {
change = true; change = true;
} else { } else {
unsigned int link_fc = mdio_clause45_get_pause(efx); unsigned int link_fc = efx_mdio_get_pause(efx);
if (link_fc != efx->link_fc) if (link_fc != efx->link_fc)
change = true; change = true;
} }
...@@ -609,9 +579,8 @@ static void tenxpress_phy_poll(struct efx_nic *efx) ...@@ -609,9 +579,8 @@ static void tenxpress_phy_poll(struct efx_nic *efx)
if (link_ok != efx->link_up) if (link_ok != efx->link_up)
change = true; change = true;
} else { } else {
u32 status = mdio_clause45_read(efx, efx->mii.phy_id, int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
MDIO_MMD_PMAPMD, PMA_PMD_LASI_STATUS);
PMA_PMD_LASI_STATUS);
if (status & (1 << PMA_PMD_LS_ALARM_LBN)) if (status & (1 << PMA_PMD_LS_ALARM_LBN))
change = true; change = true;
} }
...@@ -634,8 +603,7 @@ static void tenxpress_phy_fini(struct efx_nic *efx) ...@@ -634,8 +603,7 @@ static void tenxpress_phy_fini(struct efx_nic *efx)
if (efx->phy_type == PHY_TYPE_SFX7101) { if (efx->phy_type == PHY_TYPE_SFX7101) {
/* Power down the LNPGA */ /* Power down the LNPGA */
reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
PMA_PMD_XCONTROL_REG, reg);
/* Waiting here ensures that the board fini, which can turn /* Waiting here ensures that the board fini, which can turn
* off the power to the PHY, won't get run until the LNPGA * off the power to the PHY, won't get run until the LNPGA
...@@ -661,8 +629,7 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink) ...@@ -661,8 +629,7 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink)
else else
reg = PMA_PMD_LED_DEFAULT; reg = PMA_PMD_LED_DEFAULT;
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg);
PMA_PMD_LED_OVERR_REG, reg);
} }
static const char *const sfx7101_test_names[] = { static const char *const sfx7101_test_names[] = {
...@@ -698,7 +665,6 @@ static const char *const sft9001_test_names[] = { ...@@ -698,7 +665,6 @@ static const char *const sft9001_test_names[] = {
static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
{ {
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd;
int phy_id = efx->mii.phy_id;
int rc = 0, rc2, i, ctrl_reg, res_reg; int rc = 0, rc2, i, ctrl_reg, res_reg;
if (flags & ETH_TEST_FL_OFFLINE) if (flags & ETH_TEST_FL_OFFLINE)
...@@ -717,11 +683,10 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) ...@@ -717,11 +683,10 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
* must reset the PHY to resume normal service. */ * must reset the PHY to resume normal service. */
ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN); ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN);
} }
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG,
PMA_PMD_CDIAG_CTRL_REG, ctrl_reg); ctrl_reg);
i = 0; i = 0;
while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) &
PMA_PMD_CDIAG_CTRL_REG) &
(1 << CDIAG_CTRL_IN_PROG_LBN)) { (1 << CDIAG_CTRL_IN_PROG_LBN)) {
if (++i == 50) { if (++i == 50) {
rc = -ETIMEDOUT; rc = -ETIMEDOUT;
...@@ -729,15 +694,13 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) ...@@ -729,15 +694,13 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
} }
msleep(100); msleep(100);
} }
res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG);
PMA_PMD_CDIAG_RES_REG);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
int pair_res = int pair_res =
(res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH))
& ((1 << CDIAG_RES_WIDTH) - 1); & ((1 << CDIAG_RES_WIDTH) - 1);
int len_reg = mdio_clause45_read(efx, efx->mii.phy_id, int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_LEN_REG + i);
PMA_PMD_CDIAG_LEN_REG + i);
if (pair_res == CDIAG_RES_OK) if (pair_res == CDIAG_RES_OK)
results[1 + i] = 1; results[1 + i] = 1;
else if (pair_res == CDIAG_RES_INVALID) else if (pair_res == CDIAG_RES_INVALID)
...@@ -769,32 +732,27 @@ out: ...@@ -769,32 +732,27 @@ out:
static void static void
tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{ {
int phy_id = efx->mii.phy_id;
u32 adv = 0, lpa = 0; u32 adv = 0, lpa = 0;
int reg; int reg;
if (efx->phy_type != PHY_TYPE_SFX7101) { if (efx->phy_type != PHY_TYPE_SFX7101) {
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL);
C22EXT_MSTSLV_CTRL);
if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN)) if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN))
adv |= ADVERTISED_1000baseT_Full; adv |= ADVERTISED_1000baseT_Full;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS);
C22EXT_MSTSLV_STATUS);
if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN)) if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN))
lpa |= ADVERTISED_1000baseT_Half; lpa |= ADVERTISED_1000baseT_Half;
if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN)) if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN))
lpa |= ADVERTISED_1000baseT_Full; lpa |= ADVERTISED_1000baseT_Full;
} }
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
MDIO_AN_10GBT_CTRL); if (reg & MDIO_AN_10GBT_CTRL_ADV10G)
if (reg & (1 << MDIO_AN_10GBT_CTRL_ADV_10G_LBN))
adv |= ADVERTISED_10000baseT_Full; adv |= ADVERTISED_10000baseT_Full;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
MDIO_AN_10GBT_STATUS); if (reg & MDIO_AN_10GBT_STAT_LP10G)
if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN))
lpa |= ADVERTISED_10000baseT_Full; lpa |= ADVERTISED_10000baseT_Full;
mdio_clause45_get_settings_ext(efx, ecmd, adv, lpa); mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
if (efx->phy_type != PHY_TYPE_SFX7101) if (efx->phy_type != PHY_TYPE_SFX7101)
ecmd->supported |= (SUPPORTED_100baseT_Full | ecmd->supported |= (SUPPORTED_100baseT_Full |
...@@ -813,29 +771,24 @@ static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) ...@@ -813,29 +771,24 @@ static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
if (!ecmd->autoneg) if (!ecmd->autoneg)
return -EINVAL; return -EINVAL;
return mdio_clause45_set_settings(efx, ecmd); return efx_mdio_set_settings(efx, ecmd);
} }
static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising)
{ {
mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN, efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
MDIO_AN_10GBT_CTRL, MDIO_AN_10GBT_CTRL_ADV10G,
MDIO_AN_10GBT_CTRL_ADV_10G_LBN, advertising & ADVERTISED_10000baseT_Full);
advertising & ADVERTISED_10000baseT_Full);
} }
static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
{ {
int phy_id = efx->mii.phy_id; efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL,
1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN,
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, advertising & ADVERTISED_1000baseT_Full);
C22EXT_MSTSLV_CTRL, efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, MDIO_AN_10GBT_CTRL_ADV10G,
advertising & ADVERTISED_1000baseT_Full); advertising & ADVERTISED_10000baseT_Full);
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN,
MDIO_AN_10GBT_CTRL,
MDIO_AN_10GBT_CTRL_ADV_10G_LBN,
advertising & ADVERTISED_10000baseT_Full);
} }
struct efx_phy_operations falcon_sfx7101_phy_ops = { struct efx_phy_operations falcon_sfx7101_phy_ops = {
......
...@@ -34,29 +34,24 @@ ...@@ -34,29 +34,24 @@
/* Enable LASI interrupts for PHY */ /* Enable LASI interrupts for PHY */
static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx) static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx)
{ {
int reg;
int phy_id = efx->mii.phy_id;
/* Read to clear LASI status register */ /* Read to clear LASI status register */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
MDIO_XP_LASI_STAT);
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL,
MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM); XP_LASI_LS_ALARM);
} }
/* Read the LASI interrupt status to clear the interrupt. */ /* Read the LASI interrupt status to clear the interrupt. */
static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx) static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
{ {
/* Read to clear link status alarm */ /* Read to clear link status alarm */
return mdio_clause45_read(efx, efx->mii.phy_id, return efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
} }
/* Turn off LASI interrupts */ /* Turn off LASI interrupts */
static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx) static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
{ {
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL, 0);
MDIO_XP_LASI_CTRL, 0);
} }
#endif /* EFX_XENPACK_H */ #endif /* EFX_XENPACK_H */
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
#include "phy.h" #include "phy.h"
#include "falcon.h" #include "falcon.h"
#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PCS | \ #define XFP_REQUIRED_DEVS (MDIO_DEVS_PCS | \
MDIO_MMDREG_DEVS_PMAPMD | \ MDIO_DEVS_PMAPMD | \
MDIO_MMDREG_DEVS_PHYXS) MDIO_DEVS_PHYXS)
#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \ #define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \
(1 << LOOPBACK_PMAPMD) | \ (1 << LOOPBACK_PMAPMD) | \
...@@ -49,8 +49,7 @@ ...@@ -49,8 +49,7 @@
void xfp_set_led(struct efx_nic *p, int led, int mode) void xfp_set_led(struct efx_nic *p, int led, int mode)
{ {
int addr = MDIO_QUAKE_LED0_REG + led; int addr = MDIO_QUAKE_LED0_REG + led;
mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr, efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode);
mode);
} }
struct xfp_phy_data { struct xfp_phy_data {
...@@ -63,14 +62,12 @@ struct xfp_phy_data { ...@@ -63,14 +62,12 @@ struct xfp_phy_data {
static int qt2025c_wait_reset(struct efx_nic *efx) static int qt2025c_wait_reset(struct efx_nic *efx)
{ {
unsigned long timeout = jiffies + 10 * HZ; unsigned long timeout = jiffies + 10 * HZ;
int phy_id = efx->mii.phy_id;
int reg, old_counter = 0; int reg, old_counter = 0;
/* Wait for firmware heartbeat to start */ /* Wait for firmware heartbeat to start */
for (;;) { for (;;) {
int counter; int counter;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG);
PCS_FW_HEARTBEAT_REG);
if (reg < 0) if (reg < 0)
return reg; return reg;
counter = ((reg >> PCS_FW_HEARTB_LBN) & counter = ((reg >> PCS_FW_HEARTB_LBN) &
...@@ -86,8 +83,7 @@ static int qt2025c_wait_reset(struct efx_nic *efx) ...@@ -86,8 +83,7 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
/* Wait for firmware status to look good */ /* Wait for firmware status to look good */
for (;;) { for (;;) {
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG);
PCS_UC8051_STATUS_REG);
if (reg < 0) if (reg < 0)
return reg; return reg;
if ((reg & if ((reg &
...@@ -109,9 +105,9 @@ static int xfp_reset_phy(struct efx_nic *efx) ...@@ -109,9 +105,9 @@ static int xfp_reset_phy(struct efx_nic *efx)
{ {
int rc; int rc;
rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS, rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS,
XFP_MAX_RESET_TIME / XFP_RESET_WAIT, XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
XFP_RESET_WAIT); XFP_RESET_WAIT);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
...@@ -126,8 +122,7 @@ static int xfp_reset_phy(struct efx_nic *efx) ...@@ -126,8 +122,7 @@ static int xfp_reset_phy(struct efx_nic *efx)
/* Check that all the MMDs we expect are present and responding. We /* Check that all the MMDs we expect are present and responding. We
* expect faults on some if the link is down, but not on the PHY XS */ * expect faults on some if the link is down, but not on the PHY XS */
rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS, rc = efx_mdio_check_mmds(efx, XFP_REQUIRED_DEVS, MDIO_DEVS_PHYXS);
MDIO_MMDREG_DEVS_PHYXS);
if (rc < 0) if (rc < 0)
goto fail; goto fail;
...@@ -143,7 +138,7 @@ static int xfp_reset_phy(struct efx_nic *efx) ...@@ -143,7 +138,7 @@ static int xfp_reset_phy(struct efx_nic *efx)
static int xfp_phy_init(struct efx_nic *efx) static int xfp_phy_init(struct efx_nic *efx)
{ {
struct xfp_phy_data *phy_data; struct xfp_phy_data *phy_data;
u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS); u32 devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS);
int rc; int rc;
phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL); phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
...@@ -152,8 +147,8 @@ static int xfp_phy_init(struct efx_nic *efx) ...@@ -152,8 +147,8 @@ static int xfp_phy_init(struct efx_nic *efx)
efx->phy_data = phy_data; efx->phy_data = phy_data;
EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
devid, mdio_id_oui(devid), mdio_id_model(devid), devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
mdio_id_rev(devid)); efx_mdio_id_rev(devid));
phy_data->phy_mode = efx->phy_mode; phy_data->phy_mode = efx->phy_mode;
...@@ -179,7 +174,7 @@ static void xfp_phy_clear_interrupt(struct efx_nic *efx) ...@@ -179,7 +174,7 @@ static void xfp_phy_clear_interrupt(struct efx_nic *efx)
static int xfp_link_ok(struct efx_nic *efx) static int xfp_link_ok(struct efx_nic *efx)
{ {
return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS); return efx_mdio_links_ok(efx, XFP_REQUIRED_DEVS);
} }
static void xfp_phy_poll(struct efx_nic *efx) static void xfp_phy_poll(struct efx_nic *efx)
...@@ -200,9 +195,9 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) ...@@ -200,9 +195,9 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
* or optical transceivers, varying somewhat between * or optical transceivers, varying somewhat between
* firmware versions. Only 'static mode' appears to * firmware versions. Only 'static mode' appears to
* cover everything. */ * cover everything. */
mdio_clause45_set_flag( mdio_set_flag(
efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD,
PMA_PMD_FTX_CTRL2_REG, PMA_PMD_FTX_STATIC_LBN, PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN,
efx->phy_mode & PHY_MODE_TX_DISABLED || efx->phy_mode & PHY_MODE_TX_DISABLED ||
efx->phy_mode & PHY_MODE_LOW_POWER || efx->phy_mode & PHY_MODE_LOW_POWER ||
efx->loopback_mode == LOOPBACK_PCS || efx->loopback_mode == LOOPBACK_PCS ||
...@@ -213,10 +208,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) ...@@ -213,10 +208,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
(phy_data->phy_mode & PHY_MODE_TX_DISABLED)) (phy_data->phy_mode & PHY_MODE_TX_DISABLED))
xfp_reset_phy(efx); xfp_reset_phy(efx);
mdio_clause45_transmit_disable(efx); efx_mdio_transmit_disable(efx);
} }
mdio_clause45_phy_reconfigure(efx); efx_mdio_phy_reconfigure(efx);
phy_data->phy_mode = efx->phy_mode; phy_data->phy_mode = efx->phy_mode;
efx->link_up = xfp_link_ok(efx); efx->link_up = xfp_link_ok(efx);
...@@ -225,6 +220,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) ...@@ -225,6 +220,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
efx->link_fc = efx->wanted_fc; efx->link_fc = efx->wanted_fc;
} }
static void xfp_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
mdio45_ethtool_gset(&efx->mdio, ecmd);
}
static void xfp_phy_fini(struct efx_nic *efx) static void xfp_phy_fini(struct efx_nic *efx)
{ {
...@@ -243,8 +242,8 @@ struct efx_phy_operations falcon_xfp_phy_ops = { ...@@ -243,8 +242,8 @@ struct efx_phy_operations falcon_xfp_phy_ops = {
.poll = xfp_phy_poll, .poll = xfp_phy_poll,
.fini = xfp_phy_fini, .fini = xfp_phy_fini,
.clear_interrupt = xfp_phy_clear_interrupt, .clear_interrupt = xfp_phy_clear_interrupt,
.get_settings = mdio_clause45_get_settings, .get_settings = xfp_phy_get_settings,
.set_settings = mdio_clause45_set_settings, .set_settings = efx_mdio_set_settings,
.mmds = XFP_REQUIRED_DEVS, .mmds = XFP_REQUIRED_DEVS,
.loopbacks = XFP_LOOPBACKS, .loopbacks = XFP_LOOPBACKS,
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment