diff options
author | Michael Chan <mchan@broadcom.com> | 2007-07-08 01:50:15 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 01:18:33 -0400 |
commit | 7b6b83474cb9bdd07dadfb7497a29c3005ad9d1d (patch) | |
tree | 64fbf2a9c6a28f6f5e041b1da65b0cd12335a8c4 /drivers/net/bnx2.c | |
parent | 0d8a6571051d23c214d7a316976138a6fd8bda1c (diff) |
[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: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r-- | drivers/net/bnx2.c | 83 |
1 files changed, 56 insertions, 27 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index c571da60241d..d7fad6938bdd 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -5363,17 +5363,25 @@ static int | |||
5363 | bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 5363 | bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
5364 | { | 5364 | { |
5365 | struct bnx2 *bp = netdev_priv(dev); | 5365 | struct bnx2 *bp = netdev_priv(dev); |
5366 | int support_serdes = 0, support_copper = 0; | ||
5366 | 5367 | ||
5367 | cmd->supported = SUPPORTED_Autoneg; | 5368 | cmd->supported = SUPPORTED_Autoneg; |
5368 | if (bp->phy_flags & PHY_SERDES_FLAG) { | 5369 | if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) { |
5370 | support_serdes = 1; | ||
5371 | support_copper = 1; | ||
5372 | } else if (bp->phy_port == PORT_FIBRE) | ||
5373 | support_serdes = 1; | ||
5374 | else | ||
5375 | support_copper = 1; | ||
5376 | |||
5377 | if (support_serdes) { | ||
5369 | cmd->supported |= SUPPORTED_1000baseT_Full | | 5378 | cmd->supported |= SUPPORTED_1000baseT_Full | |
5370 | SUPPORTED_FIBRE; | 5379 | SUPPORTED_FIBRE; |
5371 | if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) | 5380 | if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) |
5372 | cmd->supported |= SUPPORTED_2500baseX_Full; | 5381 | cmd->supported |= SUPPORTED_2500baseX_Full; |
5373 | 5382 | ||
5374 | cmd->port = PORT_FIBRE; | ||
5375 | } | 5383 | } |
5376 | else { | 5384 | if (support_copper) { |
5377 | cmd->supported |= SUPPORTED_10baseT_Half | | 5385 | cmd->supported |= SUPPORTED_10baseT_Half | |
5378 | SUPPORTED_10baseT_Full | | 5386 | SUPPORTED_10baseT_Full | |
5379 | SUPPORTED_100baseT_Half | | 5387 | SUPPORTED_100baseT_Half | |
@@ -5381,9 +5389,10 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
5381 | SUPPORTED_1000baseT_Full | | 5389 | SUPPORTED_1000baseT_Full | |
5382 | SUPPORTED_TP; | 5390 | SUPPORTED_TP; |
5383 | 5391 | ||
5384 | cmd->port = PORT_TP; | ||
5385 | } | 5392 | } |
5386 | 5393 | ||
5394 | spin_lock_bh(&bp->phy_lock); | ||
5395 | cmd->port = bp->phy_port; | ||
5387 | cmd->advertising = bp->advertising; | 5396 | cmd->advertising = bp->advertising; |
5388 | 5397 | ||
5389 | if (bp->autoneg & AUTONEG_SPEED) { | 5398 | if (bp->autoneg & AUTONEG_SPEED) { |
@@ -5401,6 +5410,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
5401 | cmd->speed = -1; | 5410 | cmd->speed = -1; |
5402 | cmd->duplex = -1; | 5411 | cmd->duplex = -1; |
5403 | } | 5412 | } |
5413 | spin_unlock_bh(&bp->phy_lock); | ||
5404 | 5414 | ||
5405 | cmd->transceiver = XCVR_INTERNAL; | 5415 | cmd->transceiver = XCVR_INTERNAL; |
5406 | cmd->phy_address = bp->phy_addr; | 5416 | cmd->phy_address = bp->phy_addr; |
@@ -5416,6 +5426,15 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
5416 | u8 req_duplex = bp->req_duplex; | 5426 | u8 req_duplex = bp->req_duplex; |
5417 | u16 req_line_speed = bp->req_line_speed; | 5427 | u16 req_line_speed = bp->req_line_speed; |
5418 | u32 advertising = bp->advertising; | 5428 | u32 advertising = bp->advertising; |
5429 | int err = -EINVAL; | ||
5430 | |||
5431 | spin_lock_bh(&bp->phy_lock); | ||
5432 | |||
5433 | if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE) | ||
5434 | goto err_out_unlock; | ||
5435 | |||
5436 | if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG)) | ||
5437 | goto err_out_unlock; | ||
5419 | 5438 | ||
5420 | if (cmd->autoneg == AUTONEG_ENABLE) { | 5439 | if (cmd->autoneg == AUTONEG_ENABLE) { |
5421 | autoneg |= AUTONEG_SPEED; | 5440 | autoneg |= AUTONEG_SPEED; |
@@ -5428,44 +5447,41 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
5428 | (cmd->advertising == ADVERTISED_100baseT_Half) || | 5447 | (cmd->advertising == ADVERTISED_100baseT_Half) || |
5429 | (cmd->advertising == ADVERTISED_100baseT_Full)) { | 5448 | (cmd->advertising == ADVERTISED_100baseT_Full)) { |
5430 | 5449 | ||
5431 | if (bp->phy_flags & PHY_SERDES_FLAG) | 5450 | if (cmd->port == PORT_FIBRE) |
5432 | return -EINVAL; | 5451 | goto err_out_unlock; |
5433 | 5452 | ||
5434 | advertising = cmd->advertising; | 5453 | advertising = cmd->advertising; |
5435 | 5454 | ||
5436 | } else if (cmd->advertising == ADVERTISED_2500baseX_Full) { | 5455 | } else if (cmd->advertising == ADVERTISED_2500baseX_Full) { |
5437 | if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) | 5456 | if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) || |
5438 | return -EINVAL; | 5457 | (cmd->port == PORT_TP)) |
5439 | } else if (cmd->advertising == ADVERTISED_1000baseT_Full) { | 5458 | goto err_out_unlock; |
5459 | } else if (cmd->advertising == ADVERTISED_1000baseT_Full) | ||
5440 | advertising = cmd->advertising; | 5460 | advertising = cmd->advertising; |
5441 | } | 5461 | else if (cmd->advertising == ADVERTISED_1000baseT_Half) |
5442 | else if (cmd->advertising == ADVERTISED_1000baseT_Half) { | 5462 | goto err_out_unlock; |
5443 | return -EINVAL; | ||
5444 | } | ||
5445 | else { | 5463 | else { |
5446 | if (bp->phy_flags & PHY_SERDES_FLAG) { | 5464 | if (cmd->port == PORT_FIBRE) |
5447 | advertising = ETHTOOL_ALL_FIBRE_SPEED; | 5465 | advertising = ETHTOOL_ALL_FIBRE_SPEED; |
5448 | } | 5466 | else |
5449 | else { | ||
5450 | advertising = ETHTOOL_ALL_COPPER_SPEED; | 5467 | advertising = ETHTOOL_ALL_COPPER_SPEED; |
5451 | } | ||
5452 | } | 5468 | } |
5453 | advertising |= ADVERTISED_Autoneg; | 5469 | advertising |= ADVERTISED_Autoneg; |
5454 | } | 5470 | } |
5455 | else { | 5471 | else { |
5456 | if (bp->phy_flags & PHY_SERDES_FLAG) { | 5472 | if (cmd->port == PORT_FIBRE) { |
5457 | if ((cmd->speed != SPEED_1000 && | 5473 | if ((cmd->speed != SPEED_1000 && |
5458 | cmd->speed != SPEED_2500) || | 5474 | cmd->speed != SPEED_2500) || |
5459 | (cmd->duplex != DUPLEX_FULL)) | 5475 | (cmd->duplex != DUPLEX_FULL)) |
5460 | return -EINVAL; | 5476 | goto err_out_unlock; |
5461 | 5477 | ||
5462 | if (cmd->speed == SPEED_2500 && | 5478 | if (cmd->speed == SPEED_2500 && |
5463 | !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) | 5479 | !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) |
5464 | return -EINVAL; | 5480 | goto err_out_unlock; |
5465 | } | ||
5466 | else if (cmd->speed == SPEED_1000) { | ||
5467 | return -EINVAL; | ||
5468 | } | 5481 | } |
5482 | else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500) | ||
5483 | goto err_out_unlock; | ||
5484 | |||
5469 | autoneg &= ~AUTONEG_SPEED; | 5485 | autoneg &= ~AUTONEG_SPEED; |
5470 | req_line_speed = cmd->speed; | 5486 | req_line_speed = cmd->speed; |
5471 | req_duplex = cmd->duplex; | 5487 | req_duplex = cmd->duplex; |
@@ -5477,13 +5493,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
5477 | bp->req_line_speed = req_line_speed; | 5493 | bp->req_line_speed = req_line_speed; |
5478 | bp->req_duplex = req_duplex; | 5494 | bp->req_duplex = req_duplex; |
5479 | 5495 | ||
5480 | spin_lock_bh(&bp->phy_lock); | 5496 | err = bnx2_setup_phy(bp, cmd->port); |
5481 | |||
5482 | bnx2_setup_phy(bp, bp->phy_port); | ||
5483 | 5497 | ||
5498 | err_out_unlock: | ||
5484 | spin_unlock_bh(&bp->phy_lock); | 5499 | spin_unlock_bh(&bp->phy_lock); |
5485 | 5500 | ||
5486 | return 0; | 5501 | return err; |
5487 | } | 5502 | } |
5488 | 5503 | ||
5489 | static void | 5504 | static void |
@@ -5610,6 +5625,14 @@ bnx2_nway_reset(struct net_device *dev) | |||
5610 | 5625 | ||
5611 | spin_lock_bh(&bp->phy_lock); | 5626 | spin_lock_bh(&bp->phy_lock); |
5612 | 5627 | ||
5628 | if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) { | ||
5629 | int rc; | ||
5630 | |||
5631 | rc = bnx2_setup_remote_phy(bp, bp->phy_port); | ||
5632 | spin_unlock_bh(&bp->phy_lock); | ||
5633 | return rc; | ||
5634 | } | ||
5635 | |||
5613 | /* Force a link down visible on the other side */ | 5636 | /* Force a link down visible on the other side */ |
5614 | if (bp->phy_flags & PHY_SERDES_FLAG) { | 5637 | if (bp->phy_flags & PHY_SERDES_FLAG) { |
5615 | bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); | 5638 | 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 | case SIOCGMIIREG: { | 6242 | case SIOCGMIIREG: { |
6220 | u32 mii_regval; | 6243 | u32 mii_regval; |
6221 | 6244 | ||
6245 | if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) | ||
6246 | return -EOPNOTSUPP; | ||
6247 | |||
6222 | if (!netif_running(dev)) | 6248 | if (!netif_running(dev)) |
6223 | return -EAGAIN; | 6249 | return -EAGAIN; |
6224 | 6250 | ||
@@ -6235,6 +6261,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
6235 | if (!capable(CAP_NET_ADMIN)) | 6261 | if (!capable(CAP_NET_ADMIN)) |
6236 | return -EPERM; | 6262 | return -EPERM; |
6237 | 6263 | ||
6264 | if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) | ||
6265 | return -EOPNOTSUPP; | ||
6266 | |||
6238 | if (!netif_running(dev)) | 6267 | if (!netif_running(dev)) |
6239 | return -EAGAIN; | 6268 | return -EAGAIN; |
6240 | 6269 | ||