Commit 85f9feb6 authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller

amd-xgbe: Convert to using the new link mode settings

Convert from using the old u32 supported, advertising, etc. link settings
to the new link mode settings that support bit positions / settings
greater than 32 bits.
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 606c07f3
...@@ -267,6 +267,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev, ...@@ -267,6 +267,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause) struct ethtool_pauseparam *pause)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
int ret = 0; int ret = 0;
if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) { if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) {
...@@ -279,16 +280,21 @@ static int xgbe_set_pauseparam(struct net_device *netdev, ...@@ -279,16 +280,21 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
pdata->phy.tx_pause = pause->tx_pause; pdata->phy.tx_pause = pause->tx_pause;
pdata->phy.rx_pause = pause->rx_pause; pdata->phy.rx_pause = pause->rx_pause;
pdata->phy.advertising &= ~ADVERTISED_Pause; XGBE_CLR_ADV(lks, Pause);
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; XGBE_CLR_ADV(lks, Asym_Pause);
if (pause->rx_pause) { if (pause->rx_pause) {
pdata->phy.advertising |= ADVERTISED_Pause; XGBE_SET_ADV(lks, Pause);
pdata->phy.advertising |= ADVERTISED_Asym_Pause; XGBE_SET_ADV(lks, Asym_Pause);
} }
if (pause->tx_pause) if (pause->tx_pause) {
pdata->phy.advertising ^= ADVERTISED_Asym_Pause; /* Equivalent to XOR of Asym_Pause */
if (XGBE_ADV(lks, Asym_Pause))
XGBE_CLR_ADV(lks, Asym_Pause);
else
XGBE_SET_ADV(lks, Asym_Pause);
}
if (netif_running(netdev)) if (netif_running(netdev))
ret = pdata->phy_if.phy_config_aneg(pdata); ret = pdata->phy_if.phy_config_aneg(pdata);
...@@ -300,22 +306,20 @@ static int xgbe_get_link_ksettings(struct net_device *netdev, ...@@ -300,22 +306,20 @@ static int xgbe_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd) struct ethtool_link_ksettings *cmd)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
cmd->base.phy_address = pdata->phy.address; cmd->base.phy_address = pdata->phy.address;
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
pdata->phy.supported);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
pdata->phy.advertising);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
pdata->phy.lp_advertising);
cmd->base.autoneg = pdata->phy.autoneg; cmd->base.autoneg = pdata->phy.autoneg;
cmd->base.speed = pdata->phy.speed; cmd->base.speed = pdata->phy.speed;
cmd->base.duplex = pdata->phy.duplex; cmd->base.duplex = pdata->phy.duplex;
cmd->base.port = PORT_NONE; cmd->base.port = PORT_NONE;
XGBE_LM_COPY(cmd, supported, lks, supported);
XGBE_LM_COPY(cmd, advertising, lks, advertising);
XGBE_LM_COPY(cmd, lp_advertising, lks, lp_advertising);
return 0; return 0;
} }
...@@ -323,7 +327,8 @@ static int xgbe_set_link_ksettings(struct net_device *netdev, ...@@ -323,7 +327,8 @@ static int xgbe_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd) const struct ethtool_link_ksettings *cmd)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
u32 advertising; struct ethtool_link_ksettings *lks = &pdata->phy.lks;
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
u32 speed; u32 speed;
int ret; int ret;
...@@ -355,15 +360,17 @@ static int xgbe_set_link_ksettings(struct net_device *netdev, ...@@ -355,15 +360,17 @@ static int xgbe_set_link_ksettings(struct net_device *netdev,
} }
} }
ethtool_convert_link_mode_to_legacy_u32(&advertising,
cmd->link_modes.advertising);
netif_dbg(pdata, link, netdev, netif_dbg(pdata, link, netdev,
"requested advertisement %#x, phy supported %#x\n", "requested advertisement 0x%*pb, phy supported 0x%*pb\n",
advertising, pdata->phy.supported); __ETHTOOL_LINK_MODE_MASK_NBITS, cmd->link_modes.advertising,
__ETHTOOL_LINK_MODE_MASK_NBITS, lks->link_modes.supported);
bitmap_and(advertising,
cmd->link_modes.advertising, lks->link_modes.supported,
__ETHTOOL_LINK_MODE_MASK_NBITS);
advertising &= pdata->phy.supported; if ((cmd->base.autoneg == AUTONEG_ENABLE) &&
if ((cmd->base.autoneg == AUTONEG_ENABLE) && !advertising) { bitmap_empty(advertising, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
netdev_err(netdev, netdev_err(netdev,
"unsupported requested advertisement\n"); "unsupported requested advertisement\n");
return -EINVAL; return -EINVAL;
...@@ -373,12 +380,13 @@ static int xgbe_set_link_ksettings(struct net_device *netdev, ...@@ -373,12 +380,13 @@ static int xgbe_set_link_ksettings(struct net_device *netdev,
pdata->phy.autoneg = cmd->base.autoneg; pdata->phy.autoneg = cmd->base.autoneg;
pdata->phy.speed = speed; pdata->phy.speed = speed;
pdata->phy.duplex = cmd->base.duplex; pdata->phy.duplex = cmd->base.duplex;
pdata->phy.advertising = advertising; bitmap_copy(lks->link_modes.advertising, advertising,
__ETHTOOL_LINK_MODE_MASK_NBITS);
if (cmd->base.autoneg == AUTONEG_ENABLE) if (cmd->base.autoneg == AUTONEG_ENABLE)
pdata->phy.advertising |= ADVERTISED_Autoneg; XGBE_SET_ADV(lks, Autoneg);
else else
pdata->phy.advertising &= ~ADVERTISED_Autoneg; XGBE_CLR_ADV(lks, Autoneg);
if (netif_running(netdev)) if (netif_running(netdev))
ret = pdata->phy_if.phy_config_aneg(pdata); ret = pdata->phy_if.phy_config_aneg(pdata);
......
...@@ -615,12 +615,14 @@ static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata) ...@@ -615,12 +615,14 @@ static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata)
static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
/* Be sure we aren't looping trying to negotiate */ /* Be sure we aren't looping trying to negotiate */
if (xgbe_in_kr_mode(pdata)) { if (xgbe_in_kr_mode(pdata)) {
pdata->kr_state = XGBE_RX_ERROR; pdata->kr_state = XGBE_RX_ERROR;
if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) && if (!XGBE_ADV(lks, 1000baseKX_Full) &&
!(pdata->phy.advertising & ADVERTISED_2500baseX_Full)) !XGBE_ADV(lks, 2500baseX_Full))
return XGBE_AN_NO_LINK; return XGBE_AN_NO_LINK;
if (pdata->kx_state != XGBE_RX_BPA) if (pdata->kx_state != XGBE_RX_BPA)
...@@ -628,7 +630,7 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) ...@@ -628,7 +630,7 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
} else { } else {
pdata->kx_state = XGBE_RX_ERROR; pdata->kx_state = XGBE_RX_ERROR;
if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full)) if (!XGBE_ADV(lks, 10000baseKR_Full))
return XGBE_AN_NO_LINK; return XGBE_AN_NO_LINK;
if (pdata->kr_state != XGBE_RX_BPA) if (pdata->kr_state != XGBE_RX_BPA)
...@@ -944,18 +946,19 @@ static void xgbe_an_state_machine(struct work_struct *work) ...@@ -944,18 +946,19 @@ static void xgbe_an_state_machine(struct work_struct *work)
static void xgbe_an37_init(struct xgbe_prv_data *pdata) static void xgbe_an37_init(struct xgbe_prv_data *pdata)
{ {
unsigned int advertising, reg; struct ethtool_link_ksettings lks;
unsigned int reg;
advertising = pdata->phy_if.phy_impl.an_advertising(pdata); pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
/* Set up Advertisement register */ /* Set up Advertisement register */
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
if (advertising & ADVERTISED_Pause) if (XGBE_ADV(&lks, Pause))
reg |= 0x100; reg |= 0x100;
else else
reg &= ~0x100; reg &= ~0x100;
if (advertising & ADVERTISED_Asym_Pause) if (XGBE_ADV(&lks, Asym_Pause))
reg |= 0x80; reg |= 0x80;
else else
reg &= ~0x80; reg &= ~0x80;
...@@ -992,13 +995,14 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata) ...@@ -992,13 +995,14 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata)
static void xgbe_an73_init(struct xgbe_prv_data *pdata) static void xgbe_an73_init(struct xgbe_prv_data *pdata)
{ {
unsigned int advertising, reg; struct ethtool_link_ksettings lks;
unsigned int reg;
advertising = pdata->phy_if.phy_impl.an_advertising(pdata); pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
/* Set up Advertisement register 3 first */ /* Set up Advertisement register 3 first */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
if (advertising & ADVERTISED_10000baseR_FEC) if (XGBE_ADV(&lks, 10000baseR_FEC))
reg |= 0xc000; reg |= 0xc000;
else else
reg &= ~0xc000; reg &= ~0xc000;
...@@ -1007,13 +1011,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) ...@@ -1007,13 +1011,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
/* Set up Advertisement register 2 next */ /* Set up Advertisement register 2 next */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
if (advertising & ADVERTISED_10000baseKR_Full) if (XGBE_ADV(&lks, 10000baseKR_Full))
reg |= 0x80; reg |= 0x80;
else else
reg &= ~0x80; reg &= ~0x80;
if ((advertising & ADVERTISED_1000baseKX_Full) || if (XGBE_ADV(&lks, 1000baseKX_Full) ||
(advertising & ADVERTISED_2500baseX_Full)) XGBE_ADV(&lks, 2500baseX_Full))
reg |= 0x20; reg |= 0x20;
else else
reg &= ~0x20; reg &= ~0x20;
...@@ -1022,12 +1026,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) ...@@ -1022,12 +1026,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
/* Set up Advertisement register 1 last */ /* Set up Advertisement register 1 last */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
if (advertising & ADVERTISED_Pause) if (XGBE_ADV(&lks, Pause))
reg |= 0x400; reg |= 0x400;
else else
reg &= ~0x400; reg &= ~0x400;
if (advertising & ADVERTISED_Asym_Pause) if (XGBE_ADV(&lks, Asym_Pause))
reg |= 0x800; reg |= 0x800;
else else
reg &= ~0x800; reg &= ~0x800;
...@@ -1283,9 +1287,10 @@ static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) ...@@ -1283,9 +1287,10 @@ static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
pdata->phy.lp_advertising = 0; XGBE_ZERO_LP_ADV(lks);
if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
mode = xgbe_cur_mode(pdata); mode = xgbe_cur_mode(pdata);
...@@ -1515,17 +1520,21 @@ static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) ...@@ -1515,17 +1520,21 @@ static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata) static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
{ {
if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) struct ethtool_link_ksettings *lks = &pdata->phy.lks;
if (XGBE_ADV(lks, 10000baseKR_Full))
return SPEED_10000; return SPEED_10000;
else if (pdata->phy.advertising & ADVERTISED_10000baseT_Full) else if (XGBE_ADV(lks, 10000baseT_Full))
return SPEED_10000; return SPEED_10000;
else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full) else if (XGBE_ADV(lks, 2500baseX_Full))
return SPEED_2500; return SPEED_2500;
else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full) else if (XGBE_ADV(lks, 2500baseT_Full))
return SPEED_2500;
else if (XGBE_ADV(lks, 1000baseKX_Full))
return SPEED_1000; return SPEED_1000;
else if (pdata->phy.advertising & ADVERTISED_1000baseT_Full) else if (XGBE_ADV(lks, 1000baseT_Full))
return SPEED_1000; return SPEED_1000;
else if (pdata->phy.advertising & ADVERTISED_100baseT_Full) else if (XGBE_ADV(lks, 100baseT_Full))
return SPEED_100; return SPEED_100;
return SPEED_UNKNOWN; return SPEED_UNKNOWN;
...@@ -1538,6 +1547,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata) ...@@ -1538,6 +1547,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
static int xgbe_phy_init(struct xgbe_prv_data *pdata) static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
int ret; int ret;
mutex_init(&pdata->an_mutex); mutex_init(&pdata->an_mutex);
...@@ -1555,11 +1565,13 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -1555,11 +1565,13 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
ret = pdata->phy_if.phy_impl.init(pdata); ret = pdata->phy_if.phy_impl.init(pdata);
if (ret) if (ret)
return ret; return ret;
pdata->phy.advertising = pdata->phy.supported;
/* Copy supported link modes to advertising link modes */
XGBE_LM_COPY(lks, advertising, lks, supported);
pdata->phy.address = 0; pdata->phy.address = 0;
if (pdata->phy.advertising & ADVERTISED_Autoneg) { if (XGBE_ADV(lks, Autoneg)) {
pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.autoneg = AUTONEG_ENABLE;
pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.speed = SPEED_UNKNOWN;
pdata->phy.duplex = DUPLEX_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN;
...@@ -1576,16 +1588,21 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -1576,16 +1588,21 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
pdata->phy.rx_pause = pdata->rx_pause; pdata->phy.rx_pause = pdata->rx_pause;
/* Fix up Flow Control advertising */ /* Fix up Flow Control advertising */
pdata->phy.advertising &= ~ADVERTISED_Pause; XGBE_CLR_ADV(lks, Pause);
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; XGBE_CLR_ADV(lks, Asym_Pause);
if (pdata->rx_pause) { if (pdata->rx_pause) {
pdata->phy.advertising |= ADVERTISED_Pause; XGBE_SET_ADV(lks, Pause);
pdata->phy.advertising |= ADVERTISED_Asym_Pause; XGBE_SET_ADV(lks, Asym_Pause);
} }
if (pdata->tx_pause) if (pdata->tx_pause) {
pdata->phy.advertising ^= ADVERTISED_Asym_Pause; /* Equivalent to XOR of Asym_Pause */
if (XGBE_ADV(lks, Asym_Pause))
XGBE_CLR_ADV(lks, Asym_Pause);
else
XGBE_SET_ADV(lks, Asym_Pause);
}
if (netif_msg_drv(pdata)) if (netif_msg_drv(pdata))
xgbe_dump_phy_registers(pdata); xgbe_dump_phy_registers(pdata);
......
...@@ -231,20 +231,21 @@ static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) ...@@ -231,20 +231,21 @@ static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_Backplane; XGBE_SET_LP_ADV(lks, Backplane);
/* Compare Advertisement and Link Partner register 1 */ /* Compare Advertisement and Link Partner register 1 */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
if (lp_reg & 0x400) if (lp_reg & 0x400)
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
if (lp_reg & 0x800) if (lp_reg & 0x800)
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
if (pdata->phy.pause_autoneg) { if (pdata->phy.pause_autoneg) {
/* Set flow control based on auto-negotiation result */ /* Set flow control based on auto-negotiation result */
...@@ -266,12 +267,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -266,12 +267,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
if (lp_reg & 0x20) { if (lp_reg & 0x20) {
if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000)
pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full; XGBE_SET_LP_ADV(lks, 2500baseX_Full);
else else
pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
} }
ad_reg &= lp_reg; ad_reg &= lp_reg;
...@@ -290,14 +291,17 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -290,14 +291,17 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
if (lp_reg & 0xc000) if (lp_reg & 0xc000)
pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
return mode; return mode;
} }
static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
struct ethtool_link_ksettings *dlks)
{ {
return pdata->phy.advertising; struct ethtool_link_ksettings *slks = &pdata->phy.lks;
XGBE_LM_COPY(dlks, advertising, slks, advertising);
} }
static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
...@@ -565,11 +569,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) ...@@ -565,11 +569,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
} }
static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode, u32 advert) enum xgbe_mode mode, bool advert)
{ {
if (pdata->phy.autoneg == AUTONEG_ENABLE) { if (pdata->phy.autoneg == AUTONEG_ENABLE) {
if (pdata->phy.advertising & advert) return advert;
return true;
} else { } else {
enum xgbe_mode cur_mode; enum xgbe_mode cur_mode;
...@@ -583,16 +586,18 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, ...@@ -583,16 +586,18 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_KX_1000: case XGBE_MODE_KX_1000:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseKX_Full); XGBE_ADV(lks, 1000baseKX_Full));
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_2500baseX_Full); XGBE_ADV(lks, 2500baseX_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseKR_Full); XGBE_ADV(lks, 10000baseKR_Full));
default: default:
return false; return false;
} }
...@@ -672,6 +677,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata) ...@@ -672,6 +677,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
static int xgbe_phy_init(struct xgbe_prv_data *pdata) static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data; struct xgbe_phy_data *phy_data;
int ret; int ret;
...@@ -790,21 +796,23 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -790,21 +796,23 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
} }
/* Initialize supported features */ /* Initialize supported features */
pdata->phy.supported = SUPPORTED_Autoneg; XGBE_ZERO_SUP(lks);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Backplane; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_10000baseKR_Full; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, Backplane);
XGBE_SET_SUP(lks, 10000baseKR_Full);
switch (phy_data->speed_set) { switch (phy_data->speed_set) {
case XGBE_SPEEDSET_1000_10000: case XGBE_SPEEDSET_1000_10000:
pdata->phy.supported |= SUPPORTED_1000baseKX_Full; XGBE_SET_SUP(lks, 1000baseKX_Full);
break; break;
case XGBE_SPEEDSET_2500_10000: case XGBE_SPEEDSET_2500_10000:
pdata->phy.supported |= SUPPORTED_2500baseX_Full; XGBE_SET_SUP(lks, 2500baseX_Full);
break; break;
} }
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
pdata->phy.supported |= SUPPORTED_10000baseR_FEC; XGBE_SET_SUP(lks, 10000baseR_FEC);
pdata->phy_data = phy_data; pdata->phy_data = phy_data;
......
...@@ -709,18 +709,13 @@ static int xgbe_phy_mii_read(struct mii_bus *mii, int addr, int reg) ...@@ -709,18 +709,13 @@ static int xgbe_phy_mii_read(struct mii_bus *mii, int addr, int reg)
static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed) if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed)
return; return;
pdata->phy.supported &= ~SUPPORTED_Autoneg; XGBE_ZERO_SUP(lks);
pdata->phy.supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
pdata->phy.supported &= ~SUPPORTED_TP;
pdata->phy.supported &= ~SUPPORTED_FIBRE;
pdata->phy.supported &= ~SUPPORTED_100baseT_Full;
pdata->phy.supported &= ~SUPPORTED_1000baseT_Full;
pdata->phy.supported &= ~SUPPORTED_10000baseT_Full;
if (phy_data->sfp_mod_absent) { if (phy_data->sfp_mod_absent) {
pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.speed = SPEED_UNKNOWN;
...@@ -728,18 +723,13 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -728,18 +723,13 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.autoneg = AUTONEG_ENABLE;
pdata->phy.pause_autoneg = AUTONEG_ENABLE; pdata->phy.pause_autoneg = AUTONEG_ENABLE;
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) XGBE_SET_SUP(lks, FIBRE);
pdata->phy.supported |= SUPPORTED_100baseT_Full;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
pdata->phy.advertising = pdata->phy.supported; XGBE_LM_COPY(lks, advertising, lks, supported);
return; return;
} }
...@@ -753,8 +743,18 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -753,8 +743,18 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
pdata->phy.duplex = DUPLEX_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN;
pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.autoneg = AUTONEG_ENABLE;
pdata->phy.pause_autoneg = AUTONEG_ENABLE; pdata->phy.pause_autoneg = AUTONEG_ENABLE;
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
XGBE_SET_SUP(lks, Asym_Pause);
if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) {
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
XGBE_SET_SUP(lks, 100baseT_Full);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
XGBE_SET_SUP(lks, 1000baseT_Full);
} else {
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
XGBE_SET_SUP(lks, 1000baseX_Full);
}
break; break;
case XGBE_SFP_BASE_10000_SR: case XGBE_SFP_BASE_10000_SR:
case XGBE_SFP_BASE_10000_LR: case XGBE_SFP_BASE_10000_LR:
...@@ -765,6 +765,27 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -765,6 +765,27 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
pdata->phy.duplex = DUPLEX_FULL; pdata->phy.duplex = DUPLEX_FULL;
pdata->phy.autoneg = AUTONEG_DISABLE; pdata->phy.autoneg = AUTONEG_DISABLE;
pdata->phy.pause_autoneg = AUTONEG_DISABLE; pdata->phy.pause_autoneg = AUTONEG_DISABLE;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
switch (phy_data->sfp_base) {
case XGBE_SFP_BASE_10000_SR:
XGBE_SET_SUP(lks, 10000baseSR_Full);
break;
case XGBE_SFP_BASE_10000_LR:
XGBE_SET_SUP(lks, 10000baseLR_Full);
break;
case XGBE_SFP_BASE_10000_LRM:
XGBE_SET_SUP(lks, 10000baseLRM_Full);
break;
case XGBE_SFP_BASE_10000_ER:
XGBE_SET_SUP(lks, 10000baseER_Full);
break;
case XGBE_SFP_BASE_10000_CR:
XGBE_SET_SUP(lks, 10000baseCR_Full);
break;
default:
break;
}
}
break; break;
default: default:
pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.speed = SPEED_UNKNOWN;
...@@ -778,38 +799,14 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -778,38 +799,14 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
case XGBE_SFP_BASE_1000_T: case XGBE_SFP_BASE_1000_T:
case XGBE_SFP_BASE_1000_CX: case XGBE_SFP_BASE_1000_CX:
case XGBE_SFP_BASE_10000_CR: case XGBE_SFP_BASE_10000_CR:
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, TP);
break; break;
default: default:
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, FIBRE);
}
switch (phy_data->sfp_speed) {
case XGBE_SFP_SPEED_100_1000:
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
pdata->phy.supported |= SUPPORTED_100baseT_Full;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
break;
case XGBE_SFP_SPEED_1000:
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
break; break;
case XGBE_SFP_SPEED_10000:
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
break;
default:
/* Choose the fastest supported speed */
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
pdata->phy.supported |= SUPPORTED_100baseT_Full;
} }
pdata->phy.advertising = pdata->phy.supported; XGBE_LM_COPY(lks, advertising, lks, supported);
} }
static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom,
...@@ -886,8 +883,10 @@ static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata) ...@@ -886,8 +883,10 @@ static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
struct phy_device *phydev; struct phy_device *phydev;
u32 advertising;
int ret; int ret;
/* If we already have a PHY, just return */ /* If we already have a PHY, just return */
...@@ -943,7 +942,10 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) ...@@ -943,7 +942,10 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
phy_data->phydev = phydev; phy_data->phydev = phydev;
xgbe_phy_external_phy_quirks(pdata); xgbe_phy_external_phy_quirks(pdata);
phydev->advertising &= pdata->phy.advertising;
ethtool_convert_link_mode_to_legacy_u32(&advertising,
lks->link_modes.advertising);
phydev->advertising &= advertising;
phy_start_aneg(phy_data->phydev); phy_start_aneg(phy_data->phydev);
...@@ -1277,6 +1279,7 @@ static void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata) ...@@ -1277,6 +1279,7 @@ static void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata)
static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
u16 lcl_adv = 0, rmt_adv = 0; u16 lcl_adv = 0, rmt_adv = 0;
u8 fc; u8 fc;
...@@ -1293,11 +1296,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) ...@@ -1293,11 +1296,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
lcl_adv |= ADVERTISE_PAUSE_ASYM; lcl_adv |= ADVERTISE_PAUSE_ASYM;
if (phy_data->phydev->pause) { if (phy_data->phydev->pause) {
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
rmt_adv |= LPA_PAUSE_CAP; rmt_adv |= LPA_PAUSE_CAP;
} }
if (phy_data->phydev->asym_pause) { if (phy_data->phydev->asym_pause) {
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
rmt_adv |= LPA_PAUSE_ASYM; rmt_adv |= LPA_PAUSE_ASYM;
} }
...@@ -1310,10 +1313,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) ...@@ -1310,10 +1313,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_TP; XGBE_SET_LP_ADV(lks, TP);
/* Use external PHY to determine flow control */ /* Use external PHY to determine flow control */
if (pdata->phy.pause_autoneg) if (pdata->phy.pause_autoneg)
...@@ -1322,21 +1326,21 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) ...@@ -1322,21 +1326,21 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) { switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) {
case XGBE_SGMII_AN_LINK_SPEED_100: case XGBE_SGMII_AN_LINK_SPEED_100:
if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
pdata->phy.lp_advertising |= ADVERTISED_100baseT_Full; XGBE_SET_LP_ADV(lks, 100baseT_Full);
mode = XGBE_MODE_SGMII_100; mode = XGBE_MODE_SGMII_100;
} else { } else {
/* Half-duplex not supported */ /* Half-duplex not supported */
pdata->phy.lp_advertising |= ADVERTISED_100baseT_Half; XGBE_SET_LP_ADV(lks, 100baseT_Half);
mode = XGBE_MODE_UNKNOWN; mode = XGBE_MODE_UNKNOWN;
} }
break; break;
case XGBE_SGMII_AN_LINK_SPEED_1000: case XGBE_SGMII_AN_LINK_SPEED_1000:
if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full; XGBE_SET_LP_ADV(lks, 1000baseT_Full);
mode = XGBE_MODE_SGMII_1000; mode = XGBE_MODE_SGMII_1000;
} else { } else {
/* Half-duplex not supported */ /* Half-duplex not supported */
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Half; XGBE_SET_LP_ADV(lks, 1000baseT_Half);
mode = XGBE_MODE_UNKNOWN; mode = XGBE_MODE_UNKNOWN;
} }
break; break;
...@@ -1349,19 +1353,20 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) ...@@ -1349,19 +1353,20 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_FIBRE; XGBE_SET_LP_ADV(lks, FIBRE);
/* Compare Advertisement and Link Partner register */ /* Compare Advertisement and Link Partner register */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY); lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY);
if (lp_reg & 0x100) if (lp_reg & 0x100)
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
if (pdata->phy.pause_autoneg) { if (pdata->phy.pause_autoneg) {
/* Set flow control based on auto-negotiation result */ /* Set flow control based on auto-negotiation result */
...@@ -1379,10 +1384,8 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) ...@@ -1379,10 +1384,8 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
} }
} }
if (lp_reg & 0x40)
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Half;
if (lp_reg & 0x20) if (lp_reg & 0x20)
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full; XGBE_SET_LP_ADV(lks, 1000baseX_Full);
/* Half duplex is not supported */ /* Half duplex is not supported */
ad_reg &= lp_reg; ad_reg &= lp_reg;
...@@ -1393,12 +1396,13 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) ...@@ -1393,12 +1396,13 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_Backplane; XGBE_SET_LP_ADV(lks, Backplane);
/* Use external PHY to determine flow control */ /* Use external PHY to determine flow control */
if (pdata->phy.pause_autoneg) if (pdata->phy.pause_autoneg)
...@@ -1408,9 +1412,9 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) ...@@ -1408,9 +1412,9 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
if (lp_reg & 0x20) if (lp_reg & 0x20)
pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
ad_reg &= lp_reg; ad_reg &= lp_reg;
if (ad_reg & 0x80) { if (ad_reg & 0x80) {
...@@ -1463,26 +1467,27 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) ...@@ -1463,26 +1467,27 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
if (lp_reg & 0xc000) if (lp_reg & 0xc000)
pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
return mode; return mode;
} }
static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_Backplane; XGBE_SET_LP_ADV(lks, Backplane);
/* Compare Advertisement and Link Partner register 1 */ /* Compare Advertisement and Link Partner register 1 */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
if (lp_reg & 0x400) if (lp_reg & 0x400)
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
if (lp_reg & 0x800) if (lp_reg & 0x800)
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
if (pdata->phy.pause_autoneg) { if (pdata->phy.pause_autoneg) {
/* Set flow control based on auto-negotiation result */ /* Set flow control based on auto-negotiation result */
...@@ -1504,9 +1509,9 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) ...@@ -1504,9 +1509,9 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
if (lp_reg & 0x20) if (lp_reg & 0x20)
pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
ad_reg &= lp_reg; ad_reg &= lp_reg;
if (ad_reg & 0x80) if (ad_reg & 0x80)
...@@ -1520,7 +1525,7 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) ...@@ -1520,7 +1525,7 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
if (lp_reg & 0xc000) if (lp_reg & 0xc000)
pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
return mode; return mode;
} }
...@@ -1541,41 +1546,43 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -1541,41 +1546,43 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
} }
} }
static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
struct ethtool_link_ksettings *dlks)
{ {
struct ethtool_link_ksettings *slks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
unsigned int advertising;
XGBE_LM_COPY(dlks, advertising, slks, advertising);
/* Without a re-driver, just return current advertising */ /* Without a re-driver, just return current advertising */
if (!phy_data->redrv) if (!phy_data->redrv)
return pdata->phy.advertising; return;
/* With the KR re-driver we need to advertise a single speed */ /* With the KR re-driver we need to advertise a single speed */
advertising = pdata->phy.advertising; XGBE_CLR_ADV(dlks, 1000baseKX_Full);
advertising &= ~ADVERTISED_1000baseKX_Full; XGBE_CLR_ADV(dlks, 10000baseKR_Full);
advertising &= ~ADVERTISED_10000baseKR_Full;
switch (phy_data->port_mode) { switch (phy_data->port_mode) {
case XGBE_PORT_MODE_BACKPLANE: case XGBE_PORT_MODE_BACKPLANE:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
case XGBE_PORT_MODE_BACKPLANE_2500: case XGBE_PORT_MODE_BACKPLANE_2500:
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
case XGBE_PORT_MODE_1000BASE_T: case XGBE_PORT_MODE_1000BASE_T:
case XGBE_PORT_MODE_1000BASE_X: case XGBE_PORT_MODE_1000BASE_X:
case XGBE_PORT_MODE_NBASE_T: case XGBE_PORT_MODE_NBASE_T:
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
case XGBE_PORT_MODE_10GBASE_T: case XGBE_PORT_MODE_10GBASE_T:
if (phy_data->phydev && if (phy_data->phydev &&
(phy_data->phydev->speed == SPEED_10000)) (phy_data->phydev->speed == SPEED_10000))
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
else else
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
case XGBE_PORT_MODE_10GBASE_R: case XGBE_PORT_MODE_10GBASE_R:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
case XGBE_PORT_MODE_SFP: case XGBE_PORT_MODE_SFP:
switch (phy_data->sfp_base) { switch (phy_data->sfp_base) {
...@@ -1583,24 +1590,24 @@ static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) ...@@ -1583,24 +1590,24 @@ static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata)
case XGBE_SFP_BASE_1000_SX: case XGBE_SFP_BASE_1000_SX:
case XGBE_SFP_BASE_1000_LX: case XGBE_SFP_BASE_1000_LX:
case XGBE_SFP_BASE_1000_CX: case XGBE_SFP_BASE_1000_CX:
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
default: default:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
} }
break; break;
default: default:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
} }
return advertising;
} }
static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
u32 advertising;
int ret; int ret;
ret = xgbe_phy_find_phy_device(pdata); ret = xgbe_phy_find_phy_device(pdata);
...@@ -1610,9 +1617,12 @@ static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) ...@@ -1610,9 +1617,12 @@ static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
if (!phy_data->phydev) if (!phy_data->phydev)
return 0; return 0;
ethtool_convert_link_mode_to_legacy_u32(&advertising,
lks->link_modes.advertising);
phy_data->phydev->autoneg = pdata->phy.autoneg; phy_data->phydev->autoneg = pdata->phy.autoneg;
phy_data->phydev->advertising = phy_data->phydev->supported & phy_data->phydev->advertising = phy_data->phydev->supported &
pdata->phy.advertising; advertising;
if (pdata->phy.autoneg != AUTONEG_ENABLE) { if (pdata->phy.autoneg != AUTONEG_ENABLE) {
phy_data->phydev->speed = pdata->phy.speed; phy_data->phydev->speed = pdata->phy.speed;
...@@ -2073,11 +2083,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) ...@@ -2073,11 +2083,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
} }
static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode, u32 advert) enum xgbe_mode mode, bool advert)
{ {
if (pdata->phy.autoneg == AUTONEG_ENABLE) { if (pdata->phy.autoneg == AUTONEG_ENABLE) {
if (pdata->phy.advertising & advert) return advert;
return true;
} else { } else {
enum xgbe_mode cur_mode; enum xgbe_mode cur_mode;
...@@ -2092,13 +2101,15 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, ...@@ -2092,13 +2101,15 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_X: case XGBE_MODE_X:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseX_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseT_Full); XGBE_ADV(lks, 10000baseKR_Full));
default: default:
return false; return false;
} }
...@@ -2107,19 +2118,21 @@ static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata, ...@@ -2107,19 +2118,21 @@ static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_100:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_100baseT_Full); XGBE_ADV(lks, 100baseT_Full));
case XGBE_MODE_SGMII_1000: case XGBE_MODE_SGMII_1000:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseT_Full));
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_2500baseX_Full); XGBE_ADV(lks, 2500baseT_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseT_Full); XGBE_ADV(lks, 10000baseT_Full));
default: default:
return false; return false;
} }
...@@ -2128,6 +2141,7 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, ...@@ -2128,6 +2141,7 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
switch (mode) { switch (mode) {
...@@ -2135,22 +2149,26 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, ...@@ -2135,22 +2149,26 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T)
return false; return false;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseX_Full));
case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_100:
if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
return false; return false;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_100baseT_Full); XGBE_ADV(lks, 100baseT_Full));
case XGBE_MODE_SGMII_1000: case XGBE_MODE_SGMII_1000:
if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
return false; return false;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseT_Full));
case XGBE_MODE_SFI: case XGBE_MODE_SFI:
if (phy_data->sfp_mod_absent) if (phy_data->sfp_mod_absent)
return true; return true;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseT_Full); XGBE_ADV(lks, 10000baseSR_Full) ||
XGBE_ADV(lks, 10000baseLR_Full) ||
XGBE_ADV(lks, 10000baseLRM_Full) ||
XGBE_ADV(lks, 10000baseER_Full) ||
XGBE_ADV(lks, 10000baseCR_Full));
default: default:
return false; return false;
} }
...@@ -2159,10 +2177,12 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, ...@@ -2159,10 +2177,12 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_2500baseX_Full); XGBE_ADV(lks, 2500baseX_Full));
default: default:
return false; return false;
} }
...@@ -2171,13 +2191,15 @@ static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata, ...@@ -2171,13 +2191,15 @@ static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_KX_1000: case XGBE_MODE_KX_1000:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseKX_Full); XGBE_ADV(lks, 1000baseKX_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseKR_Full); XGBE_ADV(lks, 10000baseKR_Full));
default: default:
return false; return false;
} }
...@@ -2744,6 +2766,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata) ...@@ -2744,6 +2766,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
static int xgbe_phy_init(struct xgbe_prv_data *pdata) static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data; struct xgbe_phy_data *phy_data;
struct mii_bus *mii; struct mii_bus *mii;
unsigned int reg; unsigned int reg;
...@@ -2823,32 +2846,33 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2823,32 +2846,33 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
phy_data->cur_mode = XGBE_MODE_UNKNOWN; phy_data->cur_mode = XGBE_MODE_UNKNOWN;
/* Initialize supported features */ /* Initialize supported features */
pdata->phy.supported = 0; XGBE_ZERO_SUP(lks);
switch (phy_data->port_mode) { switch (phy_data->port_mode) {
/* Backplane support */ /* Backplane support */
case XGBE_PORT_MODE_BACKPLANE: case XGBE_PORT_MODE_BACKPLANE:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_Backplane; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, Backplane);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseKX_Full; XGBE_SET_SUP(lks, 1000baseKX_Full);
phy_data->start_mode = XGBE_MODE_KX_1000; phy_data->start_mode = XGBE_MODE_KX_1000;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
pdata->phy.supported |= SUPPORTED_10000baseKR_Full; XGBE_SET_SUP(lks, 10000baseKR_Full);
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
pdata->phy.supported |= XGBE_SET_SUP(lks, 10000baseR_FEC);
SUPPORTED_10000baseR_FEC;
phy_data->start_mode = XGBE_MODE_KR; phy_data->start_mode = XGBE_MODE_KR;
} }
phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
break; break;
case XGBE_PORT_MODE_BACKPLANE_2500: case XGBE_PORT_MODE_BACKPLANE_2500:
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_Backplane; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_2500baseX_Full; XGBE_SET_SUP(lks, Backplane);
XGBE_SET_SUP(lks, 2500baseX_Full);
phy_data->start_mode = XGBE_MODE_KX_2500; phy_data->start_mode = XGBE_MODE_KX_2500;
phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
...@@ -2856,15 +2880,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2856,15 +2880,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* MDIO 1GBase-T support */ /* MDIO 1GBase-T support */
case XGBE_PORT_MODE_1000BASE_T: case XGBE_PORT_MODE_1000BASE_T:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
pdata->phy.supported |= SUPPORTED_100baseT_Full; XGBE_SET_SUP(lks, 100baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, 1000baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} }
...@@ -2873,10 +2898,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2873,10 +2898,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* MDIO Base-X support */ /* MDIO Base-X support */
case XGBE_PORT_MODE_1000BASE_X: case XGBE_PORT_MODE_1000BASE_X:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, FIBRE);
XGBE_SET_SUP(lks, 1000baseX_Full);
phy_data->start_mode = XGBE_MODE_X; phy_data->start_mode = XGBE_MODE_X;
phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
...@@ -2884,19 +2910,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2884,19 +2910,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* MDIO NBase-T support */ /* MDIO NBase-T support */
case XGBE_PORT_MODE_NBASE_T: case XGBE_PORT_MODE_NBASE_T:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
pdata->phy.supported |= SUPPORTED_100baseT_Full; XGBE_SET_SUP(lks, 100baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, 1000baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) {
pdata->phy.supported |= SUPPORTED_2500baseX_Full; XGBE_SET_SUP(lks, 2500baseT_Full);
phy_data->start_mode = XGBE_MODE_KX_2500; phy_data->start_mode = XGBE_MODE_KX_2500;
} }
...@@ -2905,19 +2932,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2905,19 +2932,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* 10GBase-T support */ /* 10GBase-T support */
case XGBE_PORT_MODE_10GBASE_T: case XGBE_PORT_MODE_10GBASE_T:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
pdata->phy.supported |= SUPPORTED_100baseT_Full; XGBE_SET_SUP(lks, 100baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, 1000baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
pdata->phy.supported |= SUPPORTED_10000baseT_Full; XGBE_SET_SUP(lks, 10000baseT_Full);
phy_data->start_mode = XGBE_MODE_KR; phy_data->start_mode = XGBE_MODE_KR;
} }
...@@ -2926,12 +2954,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2926,12 +2954,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* 10GBase-R support */ /* 10GBase-R support */
case XGBE_PORT_MODE_10GBASE_R: case XGBE_PORT_MODE_10GBASE_R:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_10000baseT_Full; XGBE_SET_SUP(lks, FIBRE);
XGBE_SET_SUP(lks, 10000baseSR_Full);
XGBE_SET_SUP(lks, 10000baseLR_Full);
XGBE_SET_SUP(lks, 10000baseLRM_Full);
XGBE_SET_SUP(lks, 10000baseER_Full);
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
pdata->phy.supported |= SUPPORTED_10000baseR_FEC; XGBE_SET_SUP(lks, 10000baseR_FEC);
phy_data->start_mode = XGBE_MODE_SFI; phy_data->start_mode = XGBE_MODE_SFI;
phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
...@@ -2939,22 +2971,17 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2939,22 +2971,17 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* SFP support */ /* SFP support */
case XGBE_PORT_MODE_SFP: case XGBE_PORT_MODE_SFP:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { XGBE_SET_SUP(lks, FIBRE);
pdata->phy.supported |= SUPPORTED_100baseT_Full; if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
phy_data->start_mode = XGBE_MODE_SFI; phy_data->start_mode = XGBE_MODE_SFI;
}
phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
...@@ -2965,8 +2992,9 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2965,8 +2992,9 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
} }
if (netif_msg_probe(pdata)) if (netif_msg_probe(pdata))
dev_dbg(pdata->dev, "phy supported=%#x\n", dev_dbg(pdata->dev, "phy supported=0x%*pb\n",
pdata->phy.supported); __ETHTOOL_LINK_MODE_MASK_NBITS,
lks->link_modes.supported);
if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) && if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) &&
(phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) { (phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) {
......
...@@ -131,6 +131,7 @@ ...@@ -131,6 +131,7 @@
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/ethtool.h>
#define XGBE_DRV_NAME "amd-xgbe" #define XGBE_DRV_NAME "amd-xgbe"
#define XGBE_DRV_VERSION "1.0.3" #define XGBE_DRV_VERSION "1.0.3"
...@@ -296,6 +297,48 @@ ...@@ -296,6 +297,48 @@
/* MDIO port types */ /* MDIO port types */
#define XGMAC_MAX_C22_PORT 3 #define XGMAC_MAX_C22_PORT 3
/* Link mode bit operations */
#define XGBE_ZERO_SUP(_ls) \
ethtool_link_ksettings_zero_link_mode((_ls), supported)
#define XGBE_SET_SUP(_ls, _mode) \
ethtool_link_ksettings_add_link_mode((_ls), supported, _mode)
#define XGBE_CLR_SUP(_ls, _mode) \
ethtool_link_ksettings_del_link_mode((_ls), supported, _mode)
#define XGBE_IS_SUP(_ls, _mode) \
ethtool_link_ksettings_test_link_mode((_ls), supported, _mode)
#define XGBE_ZERO_ADV(_ls) \
ethtool_link_ksettings_zero_link_mode((_ls), advertising)
#define XGBE_SET_ADV(_ls, _mode) \
ethtool_link_ksettings_add_link_mode((_ls), advertising, _mode)
#define XGBE_CLR_ADV(_ls, _mode) \
ethtool_link_ksettings_del_link_mode((_ls), advertising, _mode)
#define XGBE_ADV(_ls, _mode) \
ethtool_link_ksettings_test_link_mode((_ls), advertising, _mode)
#define XGBE_ZERO_LP_ADV(_ls) \
ethtool_link_ksettings_zero_link_mode((_ls), lp_advertising)
#define XGBE_SET_LP_ADV(_ls, _mode) \
ethtool_link_ksettings_add_link_mode((_ls), lp_advertising, _mode)
#define XGBE_CLR_LP_ADV(_ls, _mode) \
ethtool_link_ksettings_del_link_mode((_ls), lp_advertising, _mode)
#define XGBE_LP_ADV(_ls, _mode) \
ethtool_link_ksettings_test_link_mode((_ls), lp_advertising, _mode)
#define XGBE_LM_COPY(_dst, _dname, _src, _sname) \
bitmap_copy((_dst)->link_modes._dname, \
(_src)->link_modes._sname, \
__ETHTOOL_LINK_MODE_MASK_NBITS)
struct xgbe_prv_data; struct xgbe_prv_data;
struct xgbe_packet_data { struct xgbe_packet_data {
...@@ -563,9 +606,7 @@ enum xgbe_mdio_mode { ...@@ -563,9 +606,7 @@ enum xgbe_mdio_mode {
}; };
struct xgbe_phy { struct xgbe_phy {
u32 supported; struct ethtool_link_ksettings lks;
u32 advertising;
u32 lp_advertising;
int address; int address;
...@@ -817,7 +858,8 @@ struct xgbe_phy_impl_if { ...@@ -817,7 +858,8 @@ struct xgbe_phy_impl_if {
int (*an_config)(struct xgbe_prv_data *); int (*an_config)(struct xgbe_prv_data *);
/* Set/override auto-negotiation advertisement settings */ /* Set/override auto-negotiation advertisement settings */
unsigned int (*an_advertising)(struct xgbe_prv_data *); void (*an_advertising)(struct xgbe_prv_data *,
struct ethtool_link_ksettings *);
/* Process results of auto-negotiation */ /* Process results of auto-negotiation */
enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *); enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);
......
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