Commit 28011cf1 authored by Matt Carlson's avatar Matt Carlson Committed by David S. Miller

net: Add ethtool to mii advertisment conversion helpers

Translating between ethtool advertisement settings and MII
advertisements are common operations for ethernet drivers.  This patch
adds a set of helper functions that implements the conversion.  The
patch then modifies a couple of the drivers to use the new functions.
Signed-off-by: default avatarMatt Carlson <mcarlson@broadcom.com>
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f85fa279
...@@ -2064,21 +2064,12 @@ __acquires(&bp->phy_lock) ...@@ -2064,21 +2064,12 @@ __acquires(&bp->phy_lock)
bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg); bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
adv1000_reg &= PHY_ALL_1000_SPEED; adv1000_reg &= PHY_ALL_1000_SPEED;
if (bp->advertising & ADVERTISED_10baseT_Half) new_adv_reg = ethtool_adv_to_mii_100bt(bp->advertising);
new_adv_reg |= ADVERTISE_10HALF;
if (bp->advertising & ADVERTISED_10baseT_Full)
new_adv_reg |= ADVERTISE_10FULL;
if (bp->advertising & ADVERTISED_100baseT_Half)
new_adv_reg |= ADVERTISE_100HALF;
if (bp->advertising & ADVERTISED_100baseT_Full)
new_adv_reg |= ADVERTISE_100FULL;
if (bp->advertising & ADVERTISED_1000baseT_Full)
new_adv1000_reg |= ADVERTISE_1000FULL;
new_adv_reg |= ADVERTISE_CSMA; new_adv_reg |= ADVERTISE_CSMA;
new_adv_reg |= bnx2_phy_get_pause_adv(bp); new_adv_reg |= bnx2_phy_get_pause_adv(bp);
new_adv1000_reg |= ethtool_adv_to_mii_1000T(bp->advertising);
if ((adv1000_reg != new_adv1000_reg) || if ((adv1000_reg != new_adv1000_reg) ||
(adv_reg != new_adv_reg) || (adv_reg != new_adv_reg) ||
((bmcr & BMCR_ANENABLE) == 0)) { ((bmcr & BMCR_ANENABLE) == 0)) {
......
...@@ -3594,15 +3594,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) ...@@ -3594,15 +3594,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
u32 val, new_adv; u32 val, new_adv;
new_adv = ADVERTISE_CSMA; new_adv = ADVERTISE_CSMA;
if (advertise & ADVERTISED_10baseT_Half) new_adv |= ethtool_adv_to_mii_100bt(advertise);
new_adv |= ADVERTISE_10HALF;
if (advertise & ADVERTISED_10baseT_Full)
new_adv |= ADVERTISE_10FULL;
if (advertise & ADVERTISED_100baseT_Half)
new_adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
new_adv |= ADVERTISE_100FULL;
new_adv |= tg3_advert_flowctrl_1000T(flowctrl); new_adv |= tg3_advert_flowctrl_1000T(flowctrl);
err = tg3_writephy(tp, MII_ADVERTISE, new_adv); err = tg3_writephy(tp, MII_ADVERTISE, new_adv);
...@@ -3612,11 +3604,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) ...@@ -3612,11 +3604,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
goto done; goto done;
new_adv = 0; new_adv = ethtool_adv_to_mii_1000T(advertise);
if (advertise & ADVERTISED_1000baseT_Half)
new_adv |= ADVERTISE_1000HALF;
if (advertise & ADVERTISED_1000baseT_Full)
new_adv |= ADVERTISE_1000FULL;
if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
...@@ -3790,14 +3778,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask) ...@@ -3790,14 +3778,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
{ {
u32 adv_reg, all_mask = 0; u32 adv_reg, all_mask = 0;
if (mask & ADVERTISED_10baseT_Half) all_mask = ethtool_adv_to_mii_100bt(mask);
all_mask |= ADVERTISE_10HALF;
if (mask & ADVERTISED_10baseT_Full)
all_mask |= ADVERTISE_10FULL;
if (mask & ADVERTISED_100baseT_Half)
all_mask |= ADVERTISE_100HALF;
if (mask & ADVERTISED_100baseT_Full)
all_mask |= ADVERTISE_100FULL;
if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg)) if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
return 0; return 0;
...@@ -3808,11 +3789,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask) ...@@ -3808,11 +3789,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
u32 tg3_ctrl; u32 tg3_ctrl;
all_mask = 0; all_mask = ethtool_adv_to_mii_1000T(mask);
if (mask & ADVERTISED_1000baseT_Half)
all_mask |= ADVERTISE_1000HALF;
if (mask & ADVERTISED_1000baseT_Full)
all_mask |= ADVERTISE_1000FULL;
if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl)) if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl))
return 0; return 0;
...@@ -4903,23 +4880,19 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) ...@@ -4903,23 +4880,19 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
(tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) { (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
/* do nothing, just check for link up at the end */ /* do nothing, just check for link up at the end */
} else if (tp->link_config.autoneg == AUTONEG_ENABLE) { } else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 adv, new_adv; u32 adv, newadv;
err |= tg3_readphy(tp, MII_ADVERTISE, &adv); err |= tg3_readphy(tp, MII_ADVERTISE, &adv);
new_adv = adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF | newadv = adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF |
ADVERTISE_1000XPAUSE | ADVERTISE_1000XPAUSE |
ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM |
ADVERTISE_SLCT); ADVERTISE_SLCT);
new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) newadv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
new_adv |= ADVERTISE_1000XHALF; newadv |= ethtool_adv_to_mii_1000X(tp->link_config.advertising);
if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
new_adv |= ADVERTISE_1000XFULL;
if ((new_adv != adv) || !(bmcr & BMCR_ANENABLE)) { if ((newadv != adv) || !(bmcr & BMCR_ANENABLE)) {
tg3_writephy(tp, MII_ADVERTISE, new_adv); tg3_writephy(tp, MII_ADVERTISE, newadv);
bmcr |= BMCR_ANENABLE | BMCR_ANRESTART; bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
tg3_writephy(tp, MII_BMCR, bmcr); tg3_writephy(tp, MII_BMCR, bmcr);
......
...@@ -1151,19 +1151,8 @@ static int link_status_mii(struct niu *np, int *link_up_p) ...@@ -1151,19 +1151,8 @@ static int link_status_mii(struct niu *np, int *link_up_p)
supported |= SUPPORTED_1000baseT_Full; supported |= SUPPORTED_1000baseT_Full;
lp->supported = supported; lp->supported = supported;
advertising = 0; advertising = mii_adv_to_ethtool_100bt(advert);
if (advert & ADVERTISE_10HALF) advertising |= mii_adv_to_ethtool_1000T(ctrl1000);
advertising |= ADVERTISED_10baseT_Half;
if (advert & ADVERTISE_10FULL)
advertising |= ADVERTISED_10baseT_Full;
if (advert & ADVERTISE_100HALF)
advertising |= ADVERTISED_100baseT_Half;
if (advert & ADVERTISE_100FULL)
advertising |= ADVERTISED_100baseT_Full;
if (ctrl1000 & ADVERTISE_1000HALF)
advertising |= ADVERTISED_1000baseT_Half;
if (ctrl1000 & ADVERTISE_1000FULL)
advertising |= ADVERTISED_1000baseT_Full;
if (bmcr & BMCR_ANENABLE) { if (bmcr & BMCR_ANENABLE) {
int neg, neg1000; int neg, neg1000;
......
...@@ -41,20 +41,8 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) ...@@ -41,20 +41,8 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
advert = mii->mdio_read(mii->dev, mii->phy_id, addr); advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
if (advert & LPA_LPACK) if (advert & LPA_LPACK)
result |= ADVERTISED_Autoneg; result |= ADVERTISED_Autoneg;
if (advert & ADVERTISE_10HALF)
result |= ADVERTISED_10baseT_Half; return result | mii_adv_to_ethtool_100bt(advert);
if (advert & ADVERTISE_10FULL)
result |= ADVERTISED_10baseT_Full;
if (advert & ADVERTISE_100HALF)
result |= ADVERTISED_100baseT_Half;
if (advert & ADVERTISE_100FULL)
result |= ADVERTISED_100baseT_Full;
if (advert & ADVERTISE_PAUSE_CAP)
result |= ADVERTISED_Pause;
if (advert & ADVERTISE_PAUSE_ASYM)
result |= ADVERTISED_Asym_Pause;
return result;
} }
/** /**
...@@ -104,19 +92,13 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ...@@ -104,19 +92,13 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
ecmd->autoneg = AUTONEG_ENABLE; ecmd->autoneg = AUTONEG_ENABLE;
ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE); ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
if (ctrl1000 & ADVERTISE_1000HALF) if (mii->supports_gmii)
ecmd->advertising |= ADVERTISED_1000baseT_Half; ecmd->advertising |= mii_adv_to_ethtool_1000T(ctrl1000);
if (ctrl1000 & ADVERTISE_1000FULL)
ecmd->advertising |= ADVERTISED_1000baseT_Full;
if (bmsr & BMSR_ANEGCOMPLETE) { if (bmsr & BMSR_ANEGCOMPLETE) {
ecmd->lp_advertising = mii_get_an(mii, MII_LPA); ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
if (stat1000 & LPA_1000HALF) ecmd->lp_advertising |=
ecmd->lp_advertising |= mii_lpa_to_ethtool_1000T(stat1000);
ADVERTISED_1000baseT_Half;
if (stat1000 & LPA_1000FULL)
ecmd->lp_advertising |=
ADVERTISED_1000baseT_Full;
} else { } else {
ecmd->lp_advertising = 0; ecmd->lp_advertising = 0;
} }
...@@ -204,20 +186,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ...@@ -204,20 +186,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
} }
if (ecmd->advertising & ADVERTISED_10baseT_Half) tmp |= ethtool_adv_to_mii_100bt(ecmd->advertising);
tmp |= ADVERTISE_10HALF;
if (ecmd->advertising & ADVERTISED_10baseT_Full) if (mii->supports_gmii)
tmp |= ADVERTISE_10FULL; tmp2 |= ethtool_adv_to_mii_1000T(ecmd->advertising);
if (ecmd->advertising & ADVERTISED_100baseT_Half)
tmp |= ADVERTISE_100HALF;
if (ecmd->advertising & ADVERTISED_100baseT_Full)
tmp |= ADVERTISE_100FULL;
if (mii->supports_gmii) {
if (ecmd->advertising & ADVERTISED_1000baseT_Half)
tmp2 |= ADVERTISE_1000HALF;
if (ecmd->advertising & ADVERTISED_1000baseT_Full)
tmp2 |= ADVERTISE_1000FULL;
}
if (advert != tmp) { if (advert != tmp) {
mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
mii->advertising = tmp; mii->advertising = tmp;
......
...@@ -563,20 +563,9 @@ static int genphy_config_advert(struct phy_device *phydev) ...@@ -563,20 +563,9 @@ static int genphy_config_advert(struct phy_device *phydev)
if (adv < 0) if (adv < 0)
return adv; return adv;
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM); ADVERTISE_PAUSE_ASYM);
if (advertise & ADVERTISED_10baseT_Half) adv |= ethtool_adv_to_mii_100bt(advertise);
adv |= ADVERTISE_10HALF;
if (advertise & ADVERTISED_10baseT_Full)
adv |= ADVERTISE_10FULL;
if (advertise & ADVERTISED_100baseT_Half)
adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
if (advertise & ADVERTISED_Pause)
adv |= ADVERTISE_PAUSE_CAP;
if (advertise & ADVERTISED_Asym_Pause)
adv |= ADVERTISE_PAUSE_ASYM;
if (adv != oldadv) { if (adv != oldadv) {
err = phy_write(phydev, MII_ADVERTISE, adv); err = phy_write(phydev, MII_ADVERTISE, adv);
...@@ -595,10 +584,7 @@ static int genphy_config_advert(struct phy_device *phydev) ...@@ -595,10 +584,7 @@ static int genphy_config_advert(struct phy_device *phydev)
return adv; return adv;
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
if (advertise & SUPPORTED_1000baseT_Half) adv |= ethtool_adv_to_mii_1000T(advertise);
adv |= ADVERTISE_1000HALF;
if (advertise & SUPPORTED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
if (adv != oldadv) { if (adv != oldadv) {
err = phy_write(phydev, MII_CTRL1000, adv); err = phy_write(phydev, MII_CTRL1000, adv);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define __LINUX_MII_H__ #define __LINUX_MII_H__
#include <linux/types.h> #include <linux/types.h>
#include <linux/ethtool.h>
/* Generic MII registers. */ /* Generic MII registers. */
#define MII_BMCR 0x00 /* Basic mode control register */ #define MII_BMCR 0x00 /* Basic mode control register */
...@@ -239,6 +240,171 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock, ...@@ -239,6 +240,171 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock,
return 0; return 0;
} }
/**
* ethtool_adv_to_mii_100bt
* @ethadv: the ethtool advertisement settings
*
* A small helper function that translates ethtool advertisement
* settings to phy autonegotiation advertisements for the
* MII_ADVERTISE register.
*/
static inline u32 ethtool_adv_to_mii_100bt(u32 ethadv)
{
u32 result = 0;
if (ethadv & ADVERTISED_10baseT_Half)
result |= ADVERTISE_10HALF;
if (ethadv & ADVERTISED_10baseT_Full)
result |= ADVERTISE_10FULL;
if (ethadv & ADVERTISED_100baseT_Half)
result |= ADVERTISE_100HALF;
if (ethadv & ADVERTISED_100baseT_Full)
result |= ADVERTISE_100FULL;
if (ethadv & ADVERTISED_Pause)
result |= ADVERTISE_PAUSE_CAP;
if (ethadv & ADVERTISED_Asym_Pause)
result |= ADVERTISE_PAUSE_ASYM;
return result;
}
/**
* mii_adv_to_ethtool_100bt
* @adv: value of the MII_ADVERTISE register
*
* A small helper function that translates MII_ADVERTISE bits
* to ethtool advertisement settings.
*/
static inline u32 mii_adv_to_ethtool_100bt(u32 adv)
{
u32 result = 0;
if (adv & ADVERTISE_10HALF)
result |= ADVERTISED_10baseT_Half;
if (adv & ADVERTISE_10FULL)
result |= ADVERTISED_10baseT_Full;
if (adv & ADVERTISE_100HALF)
result |= ADVERTISED_100baseT_Half;
if (adv & ADVERTISE_100FULL)
result |= ADVERTISED_100baseT_Full;
if (adv & ADVERTISE_PAUSE_CAP)
result |= ADVERTISED_Pause;
if (adv & ADVERTISE_PAUSE_ASYM)
result |= ADVERTISED_Asym_Pause;
return result;
}
/**
* ethtool_adv_to_mii_1000T
* @ethadv: the ethtool advertisement settings
*
* A small helper function that translates ethtool advertisement
* settings to phy autonegotiation advertisements for the
* MII_CTRL1000 register when in 1000T mode.
*/
static inline u32 ethtool_adv_to_mii_1000T(u32 ethadv)
{
u32 result = 0;
if (ethadv & ADVERTISED_1000baseT_Half)
result |= ADVERTISE_1000HALF;
if (ethadv & ADVERTISED_1000baseT_Full)
result |= ADVERTISE_1000FULL;
return result;
}
/**
* mii_adv_to_ethtool_1000T
* @adv: value of the MII_CTRL1000 register
*
* A small helper function that translates MII_CTRL1000
* bits, when in 1000Base-T mode, to ethtool
* advertisement settings.
*/
static inline u32 mii_adv_to_ethtool_1000T(u32 adv)
{
u32 result = 0;
if (adv & ADVERTISE_1000HALF)
result |= ADVERTISED_1000baseT_Half;
if (adv & ADVERTISE_1000FULL)
result |= ADVERTISED_1000baseT_Full;
return result;
}
#define mii_lpa_to_ethtool_100bt(lpa) mii_adv_to_ethtool_100bt(lpa)
/**
* mii_lpa_to_ethtool_1000T
* @adv: value of the MII_STAT1000 register
*
* A small helper function that translates MII_STAT1000
* bits, when in 1000Base-T mode, to ethtool
* advertisement settings.
*/
static inline u32 mii_lpa_to_ethtool_1000T(u32 lpa)
{
u32 result = 0;
if (lpa & LPA_1000HALF)
result |= ADVERTISED_1000baseT_Half;
if (lpa & LPA_1000FULL)
result |= ADVERTISED_1000baseT_Full;
return result;
}
/**
* ethtool_adv_to_mii_1000X
* @ethadv: the ethtool advertisement settings
*
* A small helper function that translates ethtool advertisement
* settings to phy autonegotiation advertisements for the
* MII_CTRL1000 register when in 1000Base-X mode.
*/
static inline u32 ethtool_adv_to_mii_1000X(u32 ethadv)
{
u32 result = 0;
if (ethadv & ADVERTISED_1000baseT_Half)
result |= ADVERTISE_1000XHALF;
if (ethadv & ADVERTISED_1000baseT_Full)
result |= ADVERTISE_1000XFULL;
if (ethadv & ADVERTISED_Pause)
result |= ADVERTISE_1000XPAUSE;
if (ethadv & ADVERTISED_Asym_Pause)
result |= ADVERTISE_1000XPSE_ASYM;
return result;
}
/**
* mii_adv_to_ethtool_1000X
* @adv: value of the MII_CTRL1000 register
*
* A small helper function that translates MII_CTRL1000
* bits, when in 1000Base-X mode, to ethtool
* advertisement settings.
*/
static inline u32 mii_adv_to_ethtool_1000X(u32 adv)
{
u32 result = 0;
if (adv & ADVERTISE_1000XHALF)
result |= ADVERTISED_1000baseT_Half;
if (adv & ADVERTISE_1000XFULL)
result |= ADVERTISED_1000baseT_Full;
if (adv & ADVERTISE_1000XPAUSE)
result |= ADVERTISED_Pause;
if (adv & ADVERTISE_1000XPSE_ASYM)
result |= ADVERTISED_Asym_Pause;
return result;
}
/** /**
* mii_advertise_flowctrl - get flow control advertisement flags * mii_advertise_flowctrl - get flow control advertisement flags
* @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both) * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
......
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