mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 07:01:57 +00:00
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: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1b1c2e9510
commit
68e7f45e11
@ -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
|
||||
|
@ -1300,10 +1300,16 @@ out_requeue:
|
||||
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);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -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);
|
||||
|
@ -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"
|
||||
@ -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,
|
||||
@ -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)
|
||||
@ -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");
|
||||
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
@ -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, ®, 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, ®, MD_ID_REG_KER);
|
||||
|
||||
/* Write data */
|
||||
@ -2163,7 +2123,8 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
|
||||
falcon_write(efx, ®, 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,
|
||||
@ -2174,45 +2135,28 @@ 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, ®, 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, ®, MD_ID_REG_KER);
|
||||
|
||||
/* Request data to be read */
|
||||
@ -2220,12 +2164,12 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
|
||||
falcon_write(efx, ®, 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, ®, 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,
|
||||
@ -2233,22 +2177,13 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
|
||||
MD_GC, 1);
|
||||
falcon_write(efx, ®, 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)
|
||||
@ -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)
|
||||
@ -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) {
|
||||
@ -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) {
|
||||
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "boards.h"
|
||||
#include "workarounds.h"
|
||||
|
||||
unsigned mdio_id_oui(u32 id)
|
||||
unsigned efx_mdio_id_oui(u32 id)
|
||||
{
|
||||
unsigned oui = 0;
|
||||
int i;
|
||||
@ -32,52 +32,45 @@ unsigned mdio_id_oui(u32 id)
|
||||
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)
|
||||
{
|
||||
u32 ctrl;
|
||||
int phy_id = port->mii.phy_id;
|
||||
|
||||
/* Catch callers passing values in the wrong units (or just silly) */
|
||||
EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
|
||||
|
||||
mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1,
|
||||
(1 << MDIO_MMDREG_CTRL1_RESET_LBN));
|
||||
efx_mdio_write(port, mmd, MDIO_CTRL1, MDIO_CTRL1_RESET);
|
||||
/* Wait for the reset bit to clear. */
|
||||
do {
|
||||
msleep(spintime);
|
||||
ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1);
|
||||
ctrl = efx_mdio_read(port, mmd, MDIO_CTRL1);
|
||||
spins--;
|
||||
|
||||
} while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)));
|
||||
} while (spins && (ctrl & MDIO_CTRL1_RESET));
|
||||
|
||||
return spins ? spins : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
|
||||
int fault_fatal)
|
||||
static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal)
|
||||
{
|
||||
int status;
|
||||
int phy_id = efx->mii.phy_id;
|
||||
|
||||
if (LOOPBACK_INTERNAL(efx))
|
||||
return 0;
|
||||
|
||||
if (mmd != MDIO_MMD_AN) {
|
||||
/* Read MMD STATUS2 to check it is responding. */
|
||||
status = mdio_clause45_read(efx, phy_id, mmd,
|
||||
MDIO_MMDREG_STAT2);
|
||||
if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
|
||||
((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
|
||||
MDIO_MMDREG_STAT2_PRESENT_VAL) {
|
||||
status = efx_mdio_read(efx, mmd, MDIO_STAT2);
|
||||
if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) {
|
||||
EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read MMD STATUS 1 to check for fault. */
|
||||
status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1);
|
||||
if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) {
|
||||
status = efx_mdio_read(efx, mmd, MDIO_STAT1);
|
||||
if (status & MDIO_STAT1_FAULT) {
|
||||
if (fault_fatal) {
|
||||
EFX_ERR(efx, "PHY MMD %d reporting fatal"
|
||||
" fault: status %x\n", mmd, status);
|
||||
@ -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_ITERS 100
|
||||
|
||||
int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
|
||||
unsigned int mmd_mask)
|
||||
int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask)
|
||||
{
|
||||
const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
|
||||
int tries = MDIO45_RESET_ITERS;
|
||||
@ -109,16 +101,13 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
|
||||
in_reset = 0;
|
||||
while (mask) {
|
||||
if (mask & 1) {
|
||||
stat = mdio_clause45_read(efx,
|
||||
efx->mii.phy_id,
|
||||
mmd,
|
||||
MDIO_MMDREG_CTRL1);
|
||||
stat = efx_mdio_read(efx, mmd, MDIO_CTRL1);
|
||||
if (stat < 0) {
|
||||
EFX_ERR(efx, "failed to read status of"
|
||||
" MMD %d\n", mmd);
|
||||
return -EIO;
|
||||
}
|
||||
if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
|
||||
if (stat & MDIO_CTRL1_RESET)
|
||||
in_reset |= (1 << mmd);
|
||||
}
|
||||
mask = mask >> 1;
|
||||
@ -137,28 +126,26 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mdio_clause45_check_mmds(struct efx_nic *efx,
|
||||
unsigned int mmd_mask, unsigned int fatal_mask)
|
||||
int efx_mdio_check_mmds(struct efx_nic *efx,
|
||||
unsigned int mmd_mask, unsigned int fatal_mask)
|
||||
{
|
||||
int mmd = 0, probe_mmd, devs0, devs1;
|
||||
int mmd = 0, probe_mmd, devs1, devs2;
|
||||
u32 devices;
|
||||
|
||||
/* 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
|
||||
* 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);
|
||||
|
||||
/* Check all the expected MMDs are present */
|
||||
devs0 = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
probe_mmd, MDIO_MMDREG_DEVS0);
|
||||
devs1 = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
probe_mmd, MDIO_MMDREG_DEVS1);
|
||||
if (devs0 < 0 || devs1 < 0) {
|
||||
devs1 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS1);
|
||||
devs2 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS2);
|
||||
if (devs1 < 0 || devs2 < 0) {
|
||||
EFX_ERR(efx, "failed to read devices present\n");
|
||||
return -EIO;
|
||||
}
|
||||
devices = devs0 | (devs1 << 16);
|
||||
devices = devs1 | (devs2 << 16);
|
||||
if ((devices & mmd_mask) != mmd_mask) {
|
||||
EFX_ERR(efx, "required MMDs not present: got %x, "
|
||||
"wanted %x\n", devices, mmd_mask);
|
||||
@ -170,7 +157,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx,
|
||||
while (mmd_mask) {
|
||||
if (mmd_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;
|
||||
}
|
||||
mmd_mask = mmd_mask >> 1;
|
||||
@ -181,13 +168,8 @@ int mdio_clause45_check_mmds(struct efx_nic *efx,
|
||||
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
|
||||
* of mmd's */
|
||||
if (LOOPBACK_INTERNAL(efx))
|
||||
@ -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))
|
||||
return false;
|
||||
else if (efx->loopback_mode == LOOPBACK_PHYXS)
|
||||
mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS |
|
||||
MDIO_MMDREG_DEVS_PCS |
|
||||
MDIO_MMDREG_DEVS_PMAPMD |
|
||||
MDIO_MMDREG_DEVS_AN);
|
||||
mmd_mask &= ~(MDIO_DEVS_PHYXS |
|
||||
MDIO_DEVS_PCS |
|
||||
MDIO_DEVS_PMAPMD |
|
||||
MDIO_DEVS_AN);
|
||||
else if (efx->loopback_mode == LOOPBACK_PCS)
|
||||
mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS |
|
||||
MDIO_MMDREG_DEVS_PMAPMD |
|
||||
MDIO_MMDREG_DEVS_AN);
|
||||
mmd_mask &= ~(MDIO_DEVS_PCS |
|
||||
MDIO_DEVS_PMAPMD |
|
||||
MDIO_DEVS_AN);
|
||||
else if (efx->loopback_mode == LOOPBACK_PMAPMD)
|
||||
mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD |
|
||||
MDIO_MMDREG_DEVS_AN);
|
||||
mmd_mask &= ~(MDIO_DEVS_PMAPMD |
|
||||
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) {
|
||||
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;
|
||||
return mdio45_links_ok(&efx->mdio, mmd_mask);
|
||||
}
|
||||
|
||||
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,
|
||||
MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN,
|
||||
efx->phy_mode & PHY_MODE_TX_DISABLED);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
|
||||
MDIO_PMA_TXDIS, MDIO_PMD_TXDIS_GLOBAL,
|
||||
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;
|
||||
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN,
|
||||
efx->loopback_mode == LOOPBACK_PMAPMD);
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS,
|
||||
MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN,
|
||||
efx->loopback_mode == LOOPBACK_PCS);
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS,
|
||||
MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN,
|
||||
efx->loopback_mode == LOOPBACK_NETWORK);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
|
||||
MDIO_CTRL1, MDIO_PMA_CTRL1_LOOPBACK,
|
||||
efx->loopback_mode == LOOPBACK_PMAPMD);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_PCS,
|
||||
MDIO_CTRL1, MDIO_PCS_CTRL1_LOOPBACK,
|
||||
efx->loopback_mode == LOOPBACK_PCS);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_PHYXS,
|
||||
MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK,
|
||||
efx->loopback_mode == LOOPBACK_NETWORK);
|
||||
}
|
||||
|
||||
static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx,
|
||||
int lpower, int mmd)
|
||||
static void efx_mdio_set_mmd_lpower(struct efx_nic *efx,
|
||||
int lpower, int mmd)
|
||||
{
|
||||
int phy = efx->mii.phy_id;
|
||||
int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1);
|
||||
int stat = efx_mdio_read(efx, mmd, MDIO_STAT1);
|
||||
|
||||
EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n",
|
||||
mmd, lpower);
|
||||
|
||||
if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) {
|
||||
mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1,
|
||||
MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower);
|
||||
if (stat & MDIO_STAT1_LPOWERABLE) {
|
||||
efx_mdio_set_flag(efx, mmd, MDIO_CTRL1,
|
||||
MDIO_CTRL1_LPOWER, lpower);
|
||||
}
|
||||
}
|
||||
|
||||
void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
|
||||
int low_power, unsigned int mmd_mask)
|
||||
void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
|
||||
int low_power, unsigned int mmd_mask)
|
||||
{
|
||||
int mmd = 0;
|
||||
mmd_mask &= ~MDIO_MMDREG_DEVS_AN;
|
||||
mmd_mask &= ~MDIO_DEVS_AN;
|
||||
while (mmd_mask) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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: 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_mdio_set_settings - Set (some of) the PHY settings over MDIO.
|
||||
* @efx: Efx NIC
|
||||
* @ecmd: New settings
|
||||
*/
|
||||
int mdio_clause45_set_settings(struct efx_nic *efx,
|
||||
struct ethtool_cmd *ecmd)
|
||||
int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
||||
{
|
||||
int phy_id = efx->mii.phy_id;
|
||||
struct ethtool_cmd prev;
|
||||
u32 required;
|
||||
int reg;
|
||||
@ -489,94 +305,67 @@ int mdio_clause45_set_settings(struct efx_nic *efx,
|
||||
ADVERTISED_1000baseT_Full))
|
||||
reg |= ADVERTISE_NPAGE;
|
||||
reg |= efx_fc_advertise(efx->wanted_fc);
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_AN_ADVERTISE, reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
|
||||
|
||||
/* Set up the (extended) next page if necessary */
|
||||
if (efx->phy_op->set_npage_adv)
|
||||
efx->phy_op->set_npage_adv(efx, ecmd->advertising);
|
||||
|
||||
/* Enable and restart AN */
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_MMDREG_CTRL1);
|
||||
reg |= BMCR_ANENABLE;
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
|
||||
reg |= MDIO_AN_CTRL1_ENABLE;
|
||||
if (!(EFX_WORKAROUND_15195(efx) &&
|
||||
LOOPBACK_MASK(efx) & efx->phy_op->loopbacks))
|
||||
reg |= BMCR_ANRESTART;
|
||||
reg |= MDIO_AN_CTRL1_RESTART;
|
||||
if (xnp)
|
||||
reg |= 1 << MDIO_AN_CTRL_XNP_LBN;
|
||||
reg |= MDIO_AN_CTRL1_XNP;
|
||||
else
|
||||
reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN);
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_MMDREG_CTRL1, reg);
|
||||
reg &= ~MDIO_AN_CTRL1_XNP;
|
||||
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
|
||||
} else {
|
||||
/* Disable AN */
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_MMDREG_CTRL1,
|
||||
__ffs(BMCR_ANENABLE), false);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1,
|
||||
MDIO_AN_CTRL1_ENABLE, false);
|
||||
|
||||
/* Set the basic control bits */
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_MMDREG_CTRL1);
|
||||
reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX |
|
||||
0x003c);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1);
|
||||
reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX);
|
||||
if (ecmd->speed == SPEED_100)
|
||||
reg |= BMCR_SPEED100;
|
||||
reg |= MDIO_PMA_CTRL1_SPEED100;
|
||||
if (ecmd->duplex)
|
||||
reg |= BMCR_FULLDPLX;
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_MMDREG_CTRL1, reg);
|
||||
reg |= MDIO_CTRL1_FULLDPLX;
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) {
|
||||
if (efx->phy_op->mmds & MDIO_DEVS_AN) {
|
||||
/* Set pause capability advertising */
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_AN_ADVERTISE);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
|
||||
reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
|
||||
reg |= efx_fc_advertise(efx->wanted_fc);
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_AN_ADVERTISE, reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
|
||||
|
||||
/* Restart auto-negotiation */
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_MMDREG_CTRL1);
|
||||
if (reg & BMCR_ANENABLE) {
|
||||
reg |= BMCR_ANRESTART;
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_MMDREG_CTRL1, reg);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
|
||||
if (reg & MDIO_AN_CTRL1_ENABLE) {
|
||||
reg |= MDIO_AN_CTRL1_RESTART;
|
||||
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_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;
|
||||
|
||||
if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)))
|
||||
if (!(efx->phy_op->mmds & MDIO_DEVS_AN))
|
||||
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);
|
||||
}
|
||||
|
||||
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 @@
|
||||
#ifndef EFX_MDIO_10G_H
|
||||
#define EFX_MDIO_10G_H
|
||||
|
||||
#include <linux/mdio.h>
|
||||
|
||||
/*
|
||||
* Definitions needed for doing 10G MDIO as specified in clause 45
|
||||
* MDIO, which do not appear in Linux yet. Also some helper functions.
|
||||
* Helper functions for doing 10G MDIO as specified in IEEE 802.3 clause 45.
|
||||
*/
|
||||
|
||||
#include "efx.h"
|
||||
#include "boards.h"
|
||||
|
||||
/* Numbering of the MDIO Manageable Devices (MMDs) */
|
||||
/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
|
||||
#define MDIO_MMD_PMAPMD (1)
|
||||
/* 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
|
||||
static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; }
|
||||
static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; }
|
||||
extern unsigned efx_mdio_id_oui(u32 id);
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
/* 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)
|
||||
static inline int efx_mdio_read(struct efx_nic *efx, int devad, int addr)
|
||||
{
|
||||
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);
|
||||
return efx->mdio.mdio_read(efx->net_dev, efx->mdio.prtad, devad, addr);
|
||||
}
|
||||
|
||||
static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
|
||||
static inline void
|
||||
efx_mdio_write(struct efx_nic *efx, int devad, int addr, int value)
|
||||
{
|
||||
efx_dword_t phy_id;
|
||||
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);
|
||||
efx->mdio.mdio_write(efx->net_dev, efx->mdio.prtad, devad, addr, value);
|
||||
}
|
||||
|
||||
static inline int mdio_clause45_read(struct efx_nic *efx,
|
||||
u8 prt, u8 dev, u16 addr)
|
||||
static inline u32 efx_mdio_read_id(struct efx_nic *efx, int mmd)
|
||||
{
|
||||
return efx->mii.mdio_read(efx->net_dev,
|
||||
mdio_clause45_pack(prt, dev), addr);
|
||||
}
|
||||
|
||||
static inline void mdio_clause45_write(struct efx_nic *efx,
|
||||
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 = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW);
|
||||
u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
|
||||
u16 id_low = efx_mdio_read(efx, mmd, MDIO_DEVID2);
|
||||
u16 id_hi = efx_mdio_read(efx, mmd, MDIO_DEVID1);
|
||||
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;
|
||||
bool sync;
|
||||
|
||||
for (i = 0; i < 2; ++i)
|
||||
lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PHYXS,
|
||||
MDIO_PHYXS_LANE_STATE);
|
||||
lane_status = efx_mdio_read(efx, MDIO_MMD_PHYXS,
|
||||
MDIO_PHYXS_LNSTAT);
|
||||
|
||||
sync = !!(lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN));
|
||||
sync = !!(lane_status & MDIO_PHYXS_LNSTAT_ALIGN);
|
||||
if (!sync)
|
||||
EFX_LOG(efx, "XGXS lane status: %x\n", lane_status);
|
||||
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.
|
||||
@ -258,54 +64,47 @@ extern const char *mdio_clause45_mmd_name(int mmd);
|
||||
*
|
||||
* This function will sleep
|
||||
*/
|
||||
extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd,
|
||||
int spins, int spintime);
|
||||
extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd,
|
||||
int spins, int spintime);
|
||||
|
||||
/* As mdio_clause45_check_mmd but for multiple MMDs */
|
||||
int mdio_clause45_check_mmds(struct efx_nic *efx,
|
||||
unsigned int mmd_mask, unsigned int fatal_mask);
|
||||
/* As efx_mdio_check_mmd but for multiple MMDs */
|
||||
int efx_mdio_check_mmds(struct efx_nic *efx,
|
||||
unsigned int mmd_mask, unsigned int fatal_mask);
|
||||
|
||||
/* Check the link status of specified mmds in bit mask */
|
||||
extern bool mdio_clause45_links_ok(struct efx_nic *efx,
|
||||
unsigned int mmd_mask);
|
||||
extern bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask);
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
|
||||
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);
|
||||
extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
|
||||
int low_power, unsigned int mmd_mask);
|
||||
|
||||
/* Set (some of) the PHY settings over MDIO */
|
||||
extern int mdio_clause45_set_settings(struct efx_nic *efx,
|
||||
struct ethtool_cmd *ecmd);
|
||||
extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd);
|
||||
|
||||
/* 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
|
||||
* 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 */
|
||||
extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
|
||||
unsigned int mmd_mask);
|
||||
extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx,
|
||||
unsigned int mmd_mask);
|
||||
|
||||
/* Set or clear flag, debouncing */
|
||||
extern void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev,
|
||||
u16 addr, int bit, bool sense);
|
||||
static inline void
|
||||
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 */
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/device.h>
|
||||
@ -458,8 +458,6 @@ enum phy_type {
|
||||
PHY_TYPE_MAX /* Insert any new items before this */
|
||||
};
|
||||
|
||||
#define PHY_ADDR_INVALID 0xff
|
||||
|
||||
#define EFX_IS10G(efx) ((efx)->link_speed == 10000)
|
||||
|
||||
enum nic_state {
|
||||
@ -758,7 +756,7 @@ union efx_multicast_hash {
|
||||
* @phy_lock: PHY access lock
|
||||
* @phy_op: PHY interface
|
||||
* @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.
|
||||
* @mac_up: MAC link state
|
||||
* @link_up: Link status
|
||||
@ -845,7 +843,7 @@ struct efx_nic {
|
||||
struct work_struct phy_work;
|
||||
struct efx_phy_operations *phy_op;
|
||||
void *phy_data;
|
||||
struct mii_if_info mii;
|
||||
struct mdio_if_info mdio;
|
||||
enum efx_phy_mode phy_mode;
|
||||
|
||||
bool mac_up;
|
||||
|
@ -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 devad = __ffs(efx->mdio.mmds);
|
||||
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)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&efx->mac_lock);
|
||||
tests->mii = -1;
|
||||
tests->mdio = -1;
|
||||
|
||||
physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1);
|
||||
physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2);
|
||||
physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
|
||||
physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
|
||||
|
||||
if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
|
||||
(physid2 == 0x0000) || (physid2 == 0xffff)) {
|
||||
EFX_ERR(efx, "no MII PHY present with ID %d\n",
|
||||
mii->phy_id);
|
||||
EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
|
||||
efx->mdio.prtad);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&efx->mac_lock);
|
||||
tests->mii = rc ? -1 : 1;
|
||||
tests->mdio = rc ? -1 : 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -673,7 +672,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
|
||||
/* Online (i.e. non-disruptive) testing
|
||||
* 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)
|
||||
rc_test = rc;
|
||||
|
||||
|
@ -32,7 +32,7 @@ struct efx_loopback_self_tests {
|
||||
*/
|
||||
struct efx_self_tests {
|
||||
/* online tests */
|
||||
int mii;
|
||||
int mdio;
|
||||
int nvram;
|
||||
int interrupt;
|
||||
int eventq_dma[EFX_MAX_CHANNELS];
|
||||
|
@ -23,10 +23,10 @@
|
||||
* clause 22 extension MMD, but since it doesn't have all the generic
|
||||
* MMD registers it is pointless to include it here.
|
||||
*/
|
||||
#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \
|
||||
MDIO_MMDREG_DEVS_PCS | \
|
||||
MDIO_MMDREG_DEVS_PHYXS | \
|
||||
MDIO_MMDREG_DEVS_AN)
|
||||
#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \
|
||||
MDIO_DEVS_PCS | \
|
||||
MDIO_DEVS_PHYXS | \
|
||||
MDIO_DEVS_AN)
|
||||
|
||||
#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \
|
||||
(1 << LOOPBACK_PCS) | \
|
||||
@ -153,10 +153,6 @@
|
||||
#define LOOPBACK_NEAR_LBN (8)
|
||||
#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 */
|
||||
#define PCS_BOOT_STATUS_REG 53248
|
||||
#define PCS_BOOT_FATAL_ERROR_LBN 0
|
||||
@ -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));
|
||||
int reg;
|
||||
|
||||
reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_PMAPMD_10GBT_TXPWR);
|
||||
return sprintf(buf, "%d\n",
|
||||
!!(reg & (1 << MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN)));
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR);
|
||||
return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT));
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
rtnl_lock();
|
||||
mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_PMAPMD_10GBT_TXPWR,
|
||||
MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN,
|
||||
count != 0 && *buf != '0');
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
|
||||
MDIO_PMA_10GBT_TXPWR_SHORT,
|
||||
count != 0 && *buf != '0');
|
||||
efx_reconfigure_port(efx);
|
||||
rtnl_unlock();
|
||||
|
||||
@ -238,9 +231,8 @@ int sft9001_wait_boot(struct efx_nic *efx)
|
||||
int boot_stat;
|
||||
|
||||
for (;;) {
|
||||
boot_stat = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PCS,
|
||||
PCS_BOOT_STATUS_REG);
|
||||
boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS,
|
||||
PCS_BOOT_STATUS_REG);
|
||||
if (boot_stat >= 0) {
|
||||
EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat);
|
||||
switch (boot_stat &
|
||||
@ -286,38 +278,32 @@ int sft9001_wait_boot(struct efx_nic *efx)
|
||||
|
||||
static int tenxpress_init(struct efx_nic *efx)
|
||||
{
|
||||
int phy_id = efx->mii.phy_id;
|
||||
int reg;
|
||||
|
||||
if (efx->phy_type == PHY_TYPE_SFX7101) {
|
||||
/* Enable 312.5 MHz clock */
|
||||
mdio_clause45_write(efx, phy_id,
|
||||
MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
|
||||
1 << CLK312_EN_LBN);
|
||||
efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
|
||||
1 << CLK312_EN_LBN);
|
||||
} else {
|
||||
/* Enable 312.5 MHz clock and GMII */
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
|
||||
reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) |
|
||||
(1 << PMA_PMD_EXT_CLK_OUT_LBN) |
|
||||
(1 << PMA_PMD_EXT_CLK312_LBN) |
|
||||
(1 << PMA_PMD_EXT_ROBUST_LBN));
|
||||
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG, reg);
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT,
|
||||
GPHY_XCONTROL_REG, GPHY_ISOLATE_LBN,
|
||||
false);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_C22EXT,
|
||||
GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN,
|
||||
false);
|
||||
}
|
||||
|
||||
/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
|
||||
if (efx->phy_type == PHY_TYPE_SFX7101) {
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LED_CTRL_REG,
|
||||
PMA_PMA_LED_ACTIVITY_LBN,
|
||||
true);
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
|
||||
1 << PMA_PMA_LED_ACTIVITY_LBN, true);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
|
||||
PMA_PMD_LED_DEFAULT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -337,22 +323,19 @@ static int tenxpress_phy_init(struct efx_nic *efx)
|
||||
if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
|
||||
if (efx->phy_type == PHY_TYPE_SFT9001A) {
|
||||
int reg;
|
||||
reg = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG);
|
||||
reg |= (1 << PMA_PMD_EXT_SSR_LBN);
|
||||
mdio_clause45_write(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG, reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG, reg);
|
||||
mdelay(200);
|
||||
}
|
||||
|
||||
rc = mdio_clause45_wait_reset_mmds(efx,
|
||||
TENXPRESS_REQUIRED_DEVS);
|
||||
rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
|
||||
if (rc < 0)
|
||||
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)
|
||||
goto fail;
|
||||
}
|
||||
@ -360,7 +343,7 @@ static int tenxpress_phy_init(struct efx_nic *efx)
|
||||
rc = tenxpress_init(efx);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
mdio_clause45_set_pause(efx);
|
||||
efx_mdio_set_pause(efx);
|
||||
|
||||
if (efx->phy_type == PHY_TYPE_SFT9001B) {
|
||||
rc = device_create_file(&efx->pci_dev->dev,
|
||||
@ -395,17 +378,14 @@ static int tenxpress_special_reset(struct efx_nic *efx)
|
||||
efx_stats_disable(efx);
|
||||
|
||||
/* Initiate reset */
|
||||
reg = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
|
||||
reg |= (1 << PMA_PMD_EXT_SSR_LBN);
|
||||
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG, reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
|
||||
|
||||
mdelay(200);
|
||||
|
||||
/* Wait for the blocks to come out of reset */
|
||||
rc = mdio_clause45_wait_reset_mmds(efx,
|
||||
TENXPRESS_REQUIRED_DEVS);
|
||||
rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
@ -424,7 +404,6 @@ out:
|
||||
static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
|
||||
{
|
||||
struct tenxpress_phy_data *pd = efx->phy_data;
|
||||
int phy_id = efx->mii.phy_id;
|
||||
bool bad_lp;
|
||||
int reg;
|
||||
|
||||
@ -432,11 +411,10 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
|
||||
bad_lp = false;
|
||||
} else {
|
||||
/* Check that AN has started but not completed. */
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_AN_STATUS);
|
||||
if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN)))
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1);
|
||||
if (!(reg & MDIO_AN_STAT1_LPABLE))
|
||||
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)
|
||||
pd->bad_lp_tries++;
|
||||
}
|
||||
@ -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
|
||||
* failure several times in a row, and also log a message. */
|
||||
if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LED_OVERR_REG);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LED_OVERR_REG);
|
||||
reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);
|
||||
if (!bad_lp) {
|
||||
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)
|
||||
" supports 10GBASE-T ONLY, so no link can"
|
||||
" be established\n");
|
||||
}
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LED_OVERR_REG, reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LED_OVERR_REG, reg);
|
||||
pd->bad_lp_tries = bad_lp;
|
||||
}
|
||||
}
|
||||
|
||||
static bool sfx7101_link_ok(struct efx_nic *efx)
|
||||
{
|
||||
return mdio_clause45_links_ok(efx,
|
||||
MDIO_MMDREG_DEVS_PMAPMD |
|
||||
MDIO_MMDREG_DEVS_PCS |
|
||||
MDIO_MMDREG_DEVS_PHYXS);
|
||||
return efx_mdio_links_ok(efx,
|
||||
MDIO_DEVS_PMAPMD |
|
||||
MDIO_DEVS_PCS |
|
||||
MDIO_DEVS_PHYXS);
|
||||
}
|
||||
|
||||
static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
||||
{
|
||||
int phy_id = efx->mii.phy_id;
|
||||
u32 reg;
|
||||
|
||||
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)
|
||||
else if (efx->loopback_mode == LOOPBACK_GPHY)
|
||||
return true;
|
||||
else if (efx->loopback_mode)
|
||||
return mdio_clause45_links_ok(efx,
|
||||
MDIO_MMDREG_DEVS_PMAPMD |
|
||||
MDIO_MMDREG_DEVS_PHYXS);
|
||||
return efx_mdio_links_ok(efx,
|
||||
MDIO_DEVS_PMAPMD |
|
||||
MDIO_DEVS_PHYXS);
|
||||
|
||||
/* We must use the same definition of link state as LASI,
|
||||
* otherwise we can miss a link state transition
|
||||
*/
|
||||
if (ecmd->speed == 10000) {
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
|
||||
PCS_10GBASET_STAT1);
|
||||
return reg & (1 << PCS_10GBASET_BLKLK_LBN);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
|
||||
return reg & MDIO_PCS_10GBRT_STAT1_BLKLK;
|
||||
} else {
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT,
|
||||
C22EXT_STATUS_REG);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG);
|
||||
return reg & (1 << C22EXT_STATUS_LINK_LBN);
|
||||
}
|
||||
}
|
||||
|
||||
static void tenxpress_ext_loopback(struct efx_nic *efx)
|
||||
{
|
||||
int phy_id = efx->mii.phy_id;
|
||||
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS,
|
||||
PHYXS_TEST1, LOOPBACK_NEAR_LBN,
|
||||
efx->loopback_mode == LOOPBACK_PHYXS);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,
|
||||
1 << LOOPBACK_NEAR_LBN,
|
||||
efx->loopback_mode == LOOPBACK_PHYXS);
|
||||
if (efx->phy_type != PHY_TYPE_SFX7101)
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT,
|
||||
GPHY_XCONTROL_REG,
|
||||
GPHY_LOOPBACK_NEAR_LBN,
|
||||
efx->loopback_mode == LOOPBACK_GPHY);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG,
|
||||
1 << GPHY_LOOPBACK_NEAR_LBN,
|
||||
efx->loopback_mode == LOOPBACK_GPHY);
|
||||
}
|
||||
|
||||
static void tenxpress_low_power(struct efx_nic *efx)
|
||||
{
|
||||
int phy_id = efx->mii.phy_id;
|
||||
|
||||
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),
|
||||
TENXPRESS_REQUIRED_DEVS);
|
||||
else
|
||||
mdio_clause45_set_flag(
|
||||
efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG, PMA_PMD_EXT_LPOWER_LBN,
|
||||
efx_mdio_set_flag(
|
||||
efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG,
|
||||
1 << PMA_PMD_EXT_LPOWER_LBN,
|
||||
!!(efx->phy_mode & PHY_MODE_LOW_POWER));
|
||||
}
|
||||
|
||||
@ -568,8 +538,8 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx)
|
||||
WARN_ON(rc);
|
||||
}
|
||||
|
||||
mdio_clause45_transmit_disable(efx);
|
||||
mdio_clause45_phy_reconfigure(efx);
|
||||
efx_mdio_transmit_disable(efx);
|
||||
efx_mdio_phy_reconfigure(efx);
|
||||
tenxpress_ext_loopback(efx);
|
||||
|
||||
phy_data->loopback_mode = efx->loopback_mode;
|
||||
@ -585,7 +555,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx)
|
||||
efx->link_fd = ecmd.duplex == DUPLEX_FULL;
|
||||
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 */
|
||||
@ -599,7 +569,7 @@ static void tenxpress_phy_poll(struct efx_nic *efx)
|
||||
if (link_ok != efx->link_up) {
|
||||
change = true;
|
||||
} 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)
|
||||
change = true;
|
||||
}
|
||||
@ -609,9 +579,8 @@ static void tenxpress_phy_poll(struct efx_nic *efx)
|
||||
if (link_ok != efx->link_up)
|
||||
change = true;
|
||||
} else {
|
||||
u32 status = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LASI_STATUS);
|
||||
int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LASI_STATUS);
|
||||
if (status & (1 << PMA_PMD_LS_ALARM_LBN))
|
||||
change = true;
|
||||
}
|
||||
@ -634,8 +603,7 @@ static void tenxpress_phy_fini(struct efx_nic *efx)
|
||||
if (efx->phy_type == PHY_TYPE_SFX7101) {
|
||||
/* Power down the LNPGA */
|
||||
reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
|
||||
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_XCONTROL_REG, reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
|
||||
|
||||
/* Waiting here ensures that the board fini, which can turn
|
||||
* 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)
|
||||
else
|
||||
reg = PMA_PMD_LED_DEFAULT;
|
||||
|
||||
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_LED_OVERR_REG, reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg);
|
||||
}
|
||||
|
||||
static const char *const sfx7101_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)
|
||||
{
|
||||
struct ethtool_cmd ecmd;
|
||||
int phy_id = efx->mii.phy_id;
|
||||
int rc = 0, rc2, i, ctrl_reg, res_reg;
|
||||
|
||||
if (flags & ETH_TEST_FL_OFFLINE)
|
||||
@ -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. */
|
||||
ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN);
|
||||
}
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_CDIAG_CTRL_REG, ctrl_reg);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG,
|
||||
ctrl_reg);
|
||||
i = 0;
|
||||
while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_CDIAG_CTRL_REG) &
|
||||
while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) &
|
||||
(1 << CDIAG_CTRL_IN_PROG_LBN)) {
|
||||
if (++i == 50) {
|
||||
rc = -ETIMEDOUT;
|
||||
@ -729,15 +694,13 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
|
||||
}
|
||||
msleep(100);
|
||||
}
|
||||
res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_CDIAG_RES_REG);
|
||||
res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG);
|
||||
for (i = 0; i < 4; i++) {
|
||||
int pair_res =
|
||||
(res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH))
|
||||
& ((1 << CDIAG_RES_WIDTH) - 1);
|
||||
int len_reg = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_CDIAG_LEN_REG + i);
|
||||
int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_CDIAG_LEN_REG + i);
|
||||
if (pair_res == CDIAG_RES_OK)
|
||||
results[1 + i] = 1;
|
||||
else if (pair_res == CDIAG_RES_INVALID)
|
||||
@ -769,32 +732,27 @@ out:
|
||||
static void
|
||||
tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
||||
{
|
||||
int phy_id = efx->mii.phy_id;
|
||||
u32 adv = 0, lpa = 0;
|
||||
int reg;
|
||||
|
||||
if (efx->phy_type != PHY_TYPE_SFX7101) {
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT,
|
||||
C22EXT_MSTSLV_CTRL);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL);
|
||||
if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN))
|
||||
adv |= ADVERTISED_1000baseT_Full;
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT,
|
||||
C22EXT_MSTSLV_STATUS);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS);
|
||||
if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN))
|
||||
lpa |= ADVERTISED_1000baseT_Half;
|
||||
if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN))
|
||||
lpa |= ADVERTISED_1000baseT_Full;
|
||||
}
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_AN_10GBT_CTRL);
|
||||
if (reg & (1 << MDIO_AN_10GBT_CTRL_ADV_10G_LBN))
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
|
||||
if (reg & MDIO_AN_10GBT_CTRL_ADV10G)
|
||||
adv |= ADVERTISED_10000baseT_Full;
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
|
||||
MDIO_AN_10GBT_STATUS);
|
||||
if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN))
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
|
||||
if (reg & MDIO_AN_10GBT_STAT_LP10G)
|
||||
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)
|
||||
ecmd->supported |= (SUPPORTED_100baseT_Full |
|
||||
@ -813,29 +771,24 @@ static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
||||
if (!ecmd->autoneg)
|
||||
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)
|
||||
{
|
||||
mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN,
|
||||
MDIO_AN_10GBT_CTRL,
|
||||
MDIO_AN_10GBT_CTRL_ADV_10G_LBN,
|
||||
advertising & ADVERTISED_10000baseT_Full);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
|
||||
MDIO_AN_10GBT_CTRL_ADV10G,
|
||||
advertising & ADVERTISED_10000baseT_Full);
|
||||
}
|
||||
|
||||
static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
|
||||
{
|
||||
int phy_id = efx->mii.phy_id;
|
||||
|
||||
mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT,
|
||||
C22EXT_MSTSLV_CTRL,
|
||||
C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN,
|
||||
advertising & ADVERTISED_1000baseT_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);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL,
|
||||
1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN,
|
||||
advertising & ADVERTISED_1000baseT_Full);
|
||||
efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
|
||||
MDIO_AN_10GBT_CTRL_ADV10G,
|
||||
advertising & ADVERTISED_10000baseT_Full);
|
||||
}
|
||||
|
||||
struct efx_phy_operations falcon_sfx7101_phy_ops = {
|
||||
|
@ -34,29 +34,24 @@
|
||||
/* Enable LASI interrupts for PHY */
|
||||
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 */
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_XP_LASI_STAT);
|
||||
efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
|
||||
|
||||
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL,
|
||||
XP_LASI_LS_ALARM);
|
||||
}
|
||||
|
||||
/* Read the LASI interrupt status to clear the interrupt. */
|
||||
static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
|
||||
{
|
||||
/* Read to clear link status alarm */
|
||||
return mdio_clause45_read(efx, efx->mii.phy_id,
|
||||
MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
|
||||
return efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
|
||||
}
|
||||
|
||||
/* Turn off LASI interrupts */
|
||||
static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
|
||||
{
|
||||
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
MDIO_XP_LASI_CTRL, 0);
|
||||
efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_XP_LASI_CTRL, 0);
|
||||
}
|
||||
|
||||
#endif /* EFX_XENPACK_H */
|
||||
|
@ -19,9 +19,9 @@
|
||||
#include "phy.h"
|
||||
#include "falcon.h"
|
||||
|
||||
#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PCS | \
|
||||
MDIO_MMDREG_DEVS_PMAPMD | \
|
||||
MDIO_MMDREG_DEVS_PHYXS)
|
||||
#define XFP_REQUIRED_DEVS (MDIO_DEVS_PCS | \
|
||||
MDIO_DEVS_PMAPMD | \
|
||||
MDIO_DEVS_PHYXS)
|
||||
|
||||
#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \
|
||||
(1 << LOOPBACK_PMAPMD) | \
|
||||
@ -49,8 +49,7 @@
|
||||
void xfp_set_led(struct efx_nic *p, int led, int mode)
|
||||
{
|
||||
int addr = MDIO_QUAKE_LED0_REG + led;
|
||||
mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr,
|
||||
mode);
|
||||
efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode);
|
||||
}
|
||||
|
||||
struct xfp_phy_data {
|
||||
@ -63,14 +62,12 @@ struct xfp_phy_data {
|
||||
static int qt2025c_wait_reset(struct efx_nic *efx)
|
||||
{
|
||||
unsigned long timeout = jiffies + 10 * HZ;
|
||||
int phy_id = efx->mii.phy_id;
|
||||
int reg, old_counter = 0;
|
||||
|
||||
/* Wait for firmware heartbeat to start */
|
||||
for (;;) {
|
||||
int counter;
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
|
||||
PCS_FW_HEARTBEAT_REG);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG);
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
counter = ((reg >> PCS_FW_HEARTB_LBN) &
|
||||
@ -86,8 +83,7 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
|
||||
|
||||
/* Wait for firmware status to look good */
|
||||
for (;;) {
|
||||
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
|
||||
PCS_UC8051_STATUS_REG);
|
||||
reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG);
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
if ((reg &
|
||||
@ -109,9 +105,9 @@ static int xfp_reset_phy(struct efx_nic *efx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS,
|
||||
XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
|
||||
XFP_RESET_WAIT);
|
||||
rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS,
|
||||
XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
|
||||
XFP_RESET_WAIT);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
@ -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
|
||||
* expect faults on some if the link is down, but not on the PHY XS */
|
||||
rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
|
||||
MDIO_MMDREG_DEVS_PHYXS);
|
||||
rc = efx_mdio_check_mmds(efx, XFP_REQUIRED_DEVS, MDIO_DEVS_PHYXS);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
@ -143,7 +138,7 @@ static int xfp_reset_phy(struct efx_nic *efx)
|
||||
static int xfp_phy_init(struct efx_nic *efx)
|
||||
{
|
||||
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;
|
||||
|
||||
phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
|
||||
@ -152,8 +147,8 @@ static int xfp_phy_init(struct efx_nic *efx)
|
||||
efx->phy_data = phy_data;
|
||||
|
||||
EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
|
||||
devid, mdio_id_oui(devid), mdio_id_model(devid),
|
||||
mdio_id_rev(devid));
|
||||
devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
|
||||
efx_mdio_id_rev(devid));
|
||||
|
||||
phy_data->phy_mode = efx->phy_mode;
|
||||
|
||||
@ -179,7 +174,7 @@ static void xfp_phy_clear_interrupt(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)
|
||||
@ -200,9 +195,9 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
|
||||
* or optical transceivers, varying somewhat between
|
||||
* firmware versions. Only 'static mode' appears to
|
||||
* cover everything. */
|
||||
mdio_clause45_set_flag(
|
||||
efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_FTX_CTRL2_REG, PMA_PMD_FTX_STATIC_LBN,
|
||||
mdio_set_flag(
|
||||
&efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD,
|
||||
PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN,
|
||||
efx->phy_mode & PHY_MODE_TX_DISABLED ||
|
||||
efx->phy_mode & PHY_MODE_LOW_POWER ||
|
||||
efx->loopback_mode == LOOPBACK_PCS ||
|
||||
@ -213,10 +208,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
|
||||
(phy_data->phy_mode & PHY_MODE_TX_DISABLED))
|
||||
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;
|
||||
efx->link_up = xfp_link_ok(efx);
|
||||
@ -225,6 +220,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
|
||||
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)
|
||||
{
|
||||
@ -243,8 +242,8 @@ struct efx_phy_operations falcon_xfp_phy_ops = {
|
||||
.poll = xfp_phy_poll,
|
||||
.fini = xfp_phy_fini,
|
||||
.clear_interrupt = xfp_phy_clear_interrupt,
|
||||
.get_settings = mdio_clause45_get_settings,
|
||||
.set_settings = mdio_clause45_set_settings,
|
||||
.get_settings = xfp_phy_get_settings,
|
||||
.set_settings = efx_mdio_set_settings,
|
||||
.mmds = XFP_REQUIRED_DEVS,
|
||||
.loopbacks = XFP_LOOPBACKS,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user