Commit 7b6b8347 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

[BNX2]: Add ethtool support for remote PHY.

Modify the driver's ethtool_ops->get_settings and set_settings
functions to support remote PHY.  Users control the remote copper
PHY settings by specifying link settings for the tp (twisted pair)
port.

The nway_reset function is also modified to support remote PHY.
mii-tool operations are not supported on remote PHY and we will
return -EOPNOTSUPP.
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0d8a6571
...@@ -5363,17 +5363,25 @@ static int ...@@ -5363,17 +5363,25 @@ static int
bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
struct bnx2 *bp = netdev_priv(dev); struct bnx2 *bp = netdev_priv(dev);
int support_serdes = 0, support_copper = 0;
cmd->supported = SUPPORTED_Autoneg; cmd->supported = SUPPORTED_Autoneg;
if (bp->phy_flags & PHY_SERDES_FLAG) { if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
support_serdes = 1;
support_copper = 1;
} else if (bp->phy_port == PORT_FIBRE)
support_serdes = 1;
else
support_copper = 1;
if (support_serdes) {
cmd->supported |= SUPPORTED_1000baseT_Full | cmd->supported |= SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE; SUPPORTED_FIBRE;
if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
cmd->supported |= SUPPORTED_2500baseX_Full; cmd->supported |= SUPPORTED_2500baseX_Full;
cmd->port = PORT_FIBRE;
} }
else { if (support_copper) {
cmd->supported |= SUPPORTED_10baseT_Half | cmd->supported |= SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Half |
...@@ -5381,9 +5389,10 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -5381,9 +5389,10 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Full |
SUPPORTED_TP; SUPPORTED_TP;
cmd->port = PORT_TP;
} }
spin_lock_bh(&bp->phy_lock);
cmd->port = bp->phy_port;
cmd->advertising = bp->advertising; cmd->advertising = bp->advertising;
if (bp->autoneg & AUTONEG_SPEED) { if (bp->autoneg & AUTONEG_SPEED) {
...@@ -5401,6 +5410,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -5401,6 +5410,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->speed = -1; cmd->speed = -1;
cmd->duplex = -1; cmd->duplex = -1;
} }
spin_unlock_bh(&bp->phy_lock);
cmd->transceiver = XCVR_INTERNAL; cmd->transceiver = XCVR_INTERNAL;
cmd->phy_address = bp->phy_addr; cmd->phy_address = bp->phy_addr;
...@@ -5416,6 +5426,15 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -5416,6 +5426,15 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
u8 req_duplex = bp->req_duplex; u8 req_duplex = bp->req_duplex;
u16 req_line_speed = bp->req_line_speed; u16 req_line_speed = bp->req_line_speed;
u32 advertising = bp->advertising; u32 advertising = bp->advertising;
int err = -EINVAL;
spin_lock_bh(&bp->phy_lock);
if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
goto err_out_unlock;
if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG))
goto err_out_unlock;
if (cmd->autoneg == AUTONEG_ENABLE) { if (cmd->autoneg == AUTONEG_ENABLE) {
autoneg |= AUTONEG_SPEED; autoneg |= AUTONEG_SPEED;
...@@ -5428,44 +5447,41 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -5428,44 +5447,41 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
(cmd->advertising == ADVERTISED_100baseT_Half) || (cmd->advertising == ADVERTISED_100baseT_Half) ||
(cmd->advertising == ADVERTISED_100baseT_Full)) { (cmd->advertising == ADVERTISED_100baseT_Full)) {
if (bp->phy_flags & PHY_SERDES_FLAG) if (cmd->port == PORT_FIBRE)
return -EINVAL; goto err_out_unlock;
advertising = cmd->advertising; advertising = cmd->advertising;
} else if (cmd->advertising == ADVERTISED_2500baseX_Full) { } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ||
return -EINVAL; (cmd->port == PORT_TP))
} else if (cmd->advertising == ADVERTISED_1000baseT_Full) { goto err_out_unlock;
} else if (cmd->advertising == ADVERTISED_1000baseT_Full)
advertising = cmd->advertising; advertising = cmd->advertising;
} else if (cmd->advertising == ADVERTISED_1000baseT_Half)
else if (cmd->advertising == ADVERTISED_1000baseT_Half) { goto err_out_unlock;
return -EINVAL;
}
else { else {
if (bp->phy_flags & PHY_SERDES_FLAG) { if (cmd->port == PORT_FIBRE)
advertising = ETHTOOL_ALL_FIBRE_SPEED; advertising = ETHTOOL_ALL_FIBRE_SPEED;
} else
else {
advertising = ETHTOOL_ALL_COPPER_SPEED; advertising = ETHTOOL_ALL_COPPER_SPEED;
} }
}
advertising |= ADVERTISED_Autoneg; advertising |= ADVERTISED_Autoneg;
} }
else { else {
if (bp->phy_flags & PHY_SERDES_FLAG) { if (cmd->port == PORT_FIBRE) {
if ((cmd->speed != SPEED_1000 && if ((cmd->speed != SPEED_1000 &&
cmd->speed != SPEED_2500) || cmd->speed != SPEED_2500) ||
(cmd->duplex != DUPLEX_FULL)) (cmd->duplex != DUPLEX_FULL))
return -EINVAL; goto err_out_unlock;
if (cmd->speed == SPEED_2500 && if (cmd->speed == SPEED_2500 &&
!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
return -EINVAL; goto err_out_unlock;
}
else if (cmd->speed == SPEED_1000) {
return -EINVAL;
} }
else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
goto err_out_unlock;
autoneg &= ~AUTONEG_SPEED; autoneg &= ~AUTONEG_SPEED;
req_line_speed = cmd->speed; req_line_speed = cmd->speed;
req_duplex = cmd->duplex; req_duplex = cmd->duplex;
...@@ -5477,13 +5493,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -5477,13 +5493,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
bp->req_line_speed = req_line_speed; bp->req_line_speed = req_line_speed;
bp->req_duplex = req_duplex; bp->req_duplex = req_duplex;
spin_lock_bh(&bp->phy_lock); err = bnx2_setup_phy(bp, cmd->port);
bnx2_setup_phy(bp, bp->phy_port);
err_out_unlock:
spin_unlock_bh(&bp->phy_lock); spin_unlock_bh(&bp->phy_lock);
return 0; return err;
} }
static void static void
...@@ -5610,6 +5625,14 @@ bnx2_nway_reset(struct net_device *dev) ...@@ -5610,6 +5625,14 @@ bnx2_nway_reset(struct net_device *dev)
spin_lock_bh(&bp->phy_lock); spin_lock_bh(&bp->phy_lock);
if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
int rc;
rc = bnx2_setup_remote_phy(bp, bp->phy_port);
spin_unlock_bh(&bp->phy_lock);
return rc;
}
/* Force a link down visible on the other side */ /* Force a link down visible on the other side */
if (bp->phy_flags & PHY_SERDES_FLAG) { if (bp->phy_flags & PHY_SERDES_FLAG) {
bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
...@@ -6219,6 +6242,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -6219,6 +6242,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG: { case SIOCGMIIREG: {
u32 mii_regval; u32 mii_regval;
if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
return -EOPNOTSUPP;
if (!netif_running(dev)) if (!netif_running(dev))
return -EAGAIN; return -EAGAIN;
...@@ -6235,6 +6261,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -6235,6 +6261,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
return -EOPNOTSUPP;
if (!netif_running(dev)) if (!netif_running(dev))
return -EAGAIN; return -EAGAIN;
......
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