Commit 771efeda authored by Hayes Wang's avatar Hayes Wang Committed by David S. Miller

r8152: modify rtl8152_set_speed function

First, for AUTONEG_DISABLE, we only need to modify MII_BMCR.

Second, add advertising parameter for rtl8152_set_speed(). Add
RTL_ADVERTISED_xxx for advertising parameter of rtl8152_set_speed().
Then, the advertising settings from ethtool could be saved.
Signed-off-by: default avatarHayes Wang <hayeswang@realtek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 472e12e7
...@@ -757,6 +757,7 @@ struct r8152 { ...@@ -757,6 +757,7 @@ struct r8152 {
u32 msg_enable; u32 msg_enable;
u32 tx_qlen; u32 tx_qlen;
u32 coalesce; u32 coalesce;
u32 advertising;
u32 rx_buf_sz; u32 rx_buf_sz;
u32 rx_copybreak; u32 rx_copybreak;
u32 rx_pending; u32 rx_pending;
...@@ -790,6 +791,13 @@ enum tx_csum_stat { ...@@ -790,6 +791,13 @@ enum tx_csum_stat {
TX_CSUM_NONE TX_CSUM_NONE
}; };
#define RTL_ADVERTISED_10_HALF BIT(0)
#define RTL_ADVERTISED_10_FULL BIT(1)
#define RTL_ADVERTISED_100_HALF BIT(2)
#define RTL_ADVERTISED_100_FULL BIT(3)
#define RTL_ADVERTISED_1000_HALF BIT(4)
#define RTL_ADVERTISED_1000_FULL BIT(5)
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
* The RTL chips use a 64 element hash table based on the Ethernet CRC. * The RTL chips use a 64 element hash table based on the Ethernet CRC.
*/ */
...@@ -3801,90 +3809,117 @@ static void rtl8153b_disable(struct r8152 *tp) ...@@ -3801,90 +3809,117 @@ static void rtl8153b_disable(struct r8152 *tp)
r8153b_aldps_en(tp, true); r8153b_aldps_en(tp, true);
} }
static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u32 speed, u8 duplex,
u32 advertising)
{ {
u16 bmcr, anar, gbcr;
enum spd_duplex speed_duplex; enum spd_duplex speed_duplex;
u16 bmcr;
int ret = 0; int ret = 0;
anar = r8152_mdio_read(tp, MII_ADVERTISE);
anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL);
if (tp->mii.supports_gmii) {
gbcr = r8152_mdio_read(tp, MII_CTRL1000);
gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
} else {
gbcr = 0;
}
if (autoneg == AUTONEG_DISABLE) { if (autoneg == AUTONEG_DISABLE) {
if (speed == SPEED_10) { if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL)
bmcr = 0; return -EINVAL;
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
speed_duplex = FORCE_10M_HALF;
} else if (speed == SPEED_100) {
bmcr = BMCR_SPEED100;
anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
speed_duplex = FORCE_100M_HALF;
} else if (speed == SPEED_1000 && tp->mii.supports_gmii) {
bmcr = BMCR_SPEED1000;
gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
speed_duplex = NWAY_1000M_FULL;
} else {
ret = -EINVAL;
goto out;
}
if (duplex == DUPLEX_FULL) { switch (speed) {
bmcr |= BMCR_FULLDPLX; case SPEED_10:
if (speed != SPEED_1000) bmcr = BMCR_SPEED10;
speed_duplex++;
}
} else {
if (speed == SPEED_10) {
if (duplex == DUPLEX_FULL) { if (duplex == DUPLEX_FULL) {
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; bmcr |= BMCR_FULLDPLX;
speed_duplex = NWAY_10M_FULL; speed_duplex = FORCE_10M_FULL;
} else { } else {
anar |= ADVERTISE_10HALF; speed_duplex = FORCE_10M_HALF;
speed_duplex = NWAY_10M_HALF;
} }
} else if (speed == SPEED_100) { break;
case SPEED_100:
bmcr = BMCR_SPEED100;
if (duplex == DUPLEX_FULL) { if (duplex == DUPLEX_FULL) {
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; bmcr |= BMCR_FULLDPLX;
anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; speed_duplex = FORCE_100M_FULL;
speed_duplex = NWAY_100M_FULL;
} else { } else {
anar |= ADVERTISE_10HALF; speed_duplex = FORCE_100M_HALF;
anar |= ADVERTISE_100HALF;
speed_duplex = NWAY_100M_HALF;
} }
} else if (speed == SPEED_1000 && tp->mii.supports_gmii) { break;
if (duplex == DUPLEX_FULL) { case SPEED_1000:
anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; if (tp->mii.supports_gmii) {
anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; bmcr = BMCR_SPEED1000 | BMCR_FULLDPLX;
gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; speed_duplex = NWAY_1000M_FULL;
} else { break;
anar |= ADVERTISE_10HALF;
anar |= ADVERTISE_100HALF;
gbcr |= ADVERTISE_1000HALF;
} }
speed_duplex = NWAY_1000M_FULL; /* fall through */
} else { default:
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (duplex == DUPLEX_FULL)
tp->mii.full_duplex = 1;
else
tp->mii.full_duplex = 0;
tp->mii.force_media = 1;
} else {
u16 anar, tmp1;
u32 support;
support = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;
if (tp->mii.supports_gmii)
support |= RTL_ADVERTISED_1000_FULL;
if (!(advertising & support))
return -EINVAL;
anar = r8152_mdio_read(tp, MII_ADVERTISE);
tmp1 = anar & ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL);
if (advertising & RTL_ADVERTISED_10_HALF) {
tmp1 |= ADVERTISE_10HALF;
speed_duplex = NWAY_10M_HALF;
}
if (advertising & RTL_ADVERTISED_10_FULL) {
tmp1 |= ADVERTISE_10FULL;
speed_duplex = NWAY_10M_FULL;
}
if (advertising & RTL_ADVERTISED_100_HALF) {
tmp1 |= ADVERTISE_100HALF;
speed_duplex = NWAY_100M_HALF;
}
if (advertising & RTL_ADVERTISED_100_FULL) {
tmp1 |= ADVERTISE_100FULL;
speed_duplex = NWAY_100M_FULL;
}
if (anar != tmp1) {
r8152_mdio_write(tp, MII_ADVERTISE, tmp1);
tp->mii.advertising = tmp1;
}
if (tp->mii.supports_gmii) {
u16 gbcr;
gbcr = r8152_mdio_read(tp, MII_CTRL1000);
tmp1 = gbcr & ~(ADVERTISE_1000FULL |
ADVERTISE_1000HALF);
if (advertising & RTL_ADVERTISED_1000_FULL) {
tmp1 |= ADVERTISE_1000FULL;
speed_duplex = NWAY_1000M_FULL;
}
if (gbcr != tmp1)
r8152_mdio_write(tp, MII_CTRL1000, tmp1);
}
bmcr = BMCR_ANENABLE | BMCR_ANRESTART; bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
tp->mii.force_media = 0;
} }
if (test_and_clear_bit(PHY_RESET, &tp->flags)) if (test_and_clear_bit(PHY_RESET, &tp->flags))
bmcr |= BMCR_RESET; bmcr |= BMCR_RESET;
if (tp->mii.supports_gmii)
r8152_mdio_write(tp, MII_CTRL1000, gbcr);
r8152_mdio_write(tp, MII_ADVERTISE, anar);
r8152_mdio_write(tp, MII_BMCR, bmcr); r8152_mdio_write(tp, MII_BMCR, bmcr);
switch (tp->version) { switch (tp->version) {
...@@ -4122,7 +4157,8 @@ static void rtl_hw_phy_work_func_t(struct work_struct *work) ...@@ -4122,7 +4157,8 @@ static void rtl_hw_phy_work_func_t(struct work_struct *work)
tp->rtl_ops.hw_phy_cfg(tp); tp->rtl_ops.hw_phy_cfg(tp);
rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex); rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex,
tp->advertising);
mutex_unlock(&tp->control); mutex_unlock(&tp->control);
...@@ -4840,20 +4876,46 @@ static int rtl8152_set_link_ksettings(struct net_device *dev, ...@@ -4840,20 +4876,46 @@ static int rtl8152_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd) const struct ethtool_link_ksettings *cmd)
{ {
struct r8152 *tp = netdev_priv(dev); struct r8152 *tp = netdev_priv(dev);
u32 advertising = 0;
int ret; int ret;
ret = usb_autopm_get_interface(tp->intf); ret = usb_autopm_get_interface(tp->intf);
if (ret < 0) if (ret < 0)
goto out; goto out;
if (test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
cmd->link_modes.advertising))
advertising |= RTL_ADVERTISED_10_HALF;
if (test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
cmd->link_modes.advertising))
advertising |= RTL_ADVERTISED_10_FULL;
if (test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
cmd->link_modes.advertising))
advertising |= RTL_ADVERTISED_100_HALF;
if (test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
cmd->link_modes.advertising))
advertising |= RTL_ADVERTISED_100_FULL;
if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
cmd->link_modes.advertising))
advertising |= RTL_ADVERTISED_1000_HALF;
if (test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
cmd->link_modes.advertising))
advertising |= RTL_ADVERTISED_1000_FULL;
mutex_lock(&tp->control); mutex_lock(&tp->control);
ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed, ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed,
cmd->base.duplex); cmd->base.duplex, advertising);
if (!ret) { if (!ret) {
tp->autoneg = cmd->base.autoneg; tp->autoneg = cmd->base.autoneg;
tp->speed = cmd->base.speed; tp->speed = cmd->base.speed;
tp->duplex = cmd->base.duplex; tp->duplex = cmd->base.duplex;
tp->advertising = advertising;
} }
mutex_unlock(&tp->control); mutex_unlock(&tp->control);
...@@ -5568,7 +5630,13 @@ static int rtl8152_probe(struct usb_interface *intf, ...@@ -5568,7 +5630,13 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->mii.phy_id = R8152_PHY_ID; tp->mii.phy_id = R8152_PHY_ID;
tp->autoneg = AUTONEG_ENABLE; tp->autoneg = AUTONEG_ENABLE;
tp->speed = tp->mii.supports_gmii ? SPEED_1000 : SPEED_100; tp->speed = SPEED_100;
tp->advertising = RTL_ADVERTISED_10_HALF | RTL_ADVERTISED_10_FULL |
RTL_ADVERTISED_100_HALF | RTL_ADVERTISED_100_FULL;
if (tp->mii.supports_gmii) {
tp->speed = SPEED_1000;
tp->advertising |= RTL_ADVERTISED_1000_FULL;
}
tp->duplex = DUPLEX_FULL; tp->duplex = DUPLEX_FULL;
tp->rx_copybreak = RTL8152_RXFG_HEADSZ; tp->rx_copybreak = RTL8152_RXFG_HEADSZ;
......
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