aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2006-11-19 17:07:28 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:24:18 -0500
commit80be44348e30b68d2d8c5b6d1b7e53f2c5659134 (patch)
tree6bf7e3c6f9dd11f8ee90ec90a1e7df98f741dd02 /drivers
parent7510873d8659f4192cb5b3327f748e401d216399 (diff)
[BNX2]: Improve SerDes handling.
1. Add support for 2.5Gbps forced speed setting. 2. Remove a long udelay() loop and change to msleep(). 3. Other misc. SerDes fixes. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/bnx2.c60
-rw-r--r--drivers/net/bnx2.h2
2 files changed, 41 insertions, 21 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index b60e45d1ce3d..9b391cf80a32 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -860,7 +860,7 @@ bnx2_set_link(struct bnx2 *bp)
860 u32 bmsr; 860 u32 bmsr;
861 u8 link_up; 861 u8 link_up;
862 862
863 if (bp->loopback == MAC_LOOPBACK) { 863 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
864 bp->link_up = 1; 864 bp->link_up = 1;
865 return 0; 865 return 0;
866 } 866 }
@@ -902,6 +902,7 @@ bnx2_set_link(struct bnx2 *bp)
902 u32 bmcr; 902 u32 bmcr;
903 903
904 bnx2_read_phy(bp, MII_BMCR, &bmcr); 904 bnx2_read_phy(bp, MII_BMCR, &bmcr);
905 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
905 if (!(bmcr & BMCR_ANENABLE)) { 906 if (!(bmcr & BMCR_ANENABLE)) {
906 bnx2_write_phy(bp, MII_BMCR, bmcr | 907 bnx2_write_phy(bp, MII_BMCR, bmcr |
907 BMCR_ANENABLE); 908 BMCR_ANENABLE);
@@ -988,7 +989,21 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
988 u32 new_bmcr; 989 u32 new_bmcr;
989 int force_link_down = 0; 990 int force_link_down = 0;
990 991
991 if (CHIP_NUM(bp) == CHIP_NUM_5708) { 992 bnx2_read_phy(bp, MII_ADVERTISE, &adv);
993 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
994
995 bnx2_read_phy(bp, MII_BMCR, &bmcr);
996 new_bmcr = bmcr & ~(BMCR_ANENABLE | BCM5708S_BMCR_FORCE_2500);
997 new_bmcr |= BMCR_SPEED1000;
998 if (bp->req_line_speed == SPEED_2500) {
999 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1000 bnx2_read_phy(bp, BCM5708S_UP1, &up1);
1001 if (!(up1 & BCM5708S_UP1_2G5)) {
1002 up1 |= BCM5708S_UP1_2G5;
1003 bnx2_write_phy(bp, BCM5708S_UP1, up1);
1004 force_link_down = 1;
1005 }
1006 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
992 bnx2_read_phy(bp, BCM5708S_UP1, &up1); 1007 bnx2_read_phy(bp, BCM5708S_UP1, &up1);
993 if (up1 & BCM5708S_UP1_2G5) { 1008 if (up1 & BCM5708S_UP1_2G5) {
994 up1 &= ~BCM5708S_UP1_2G5; 1009 up1 &= ~BCM5708S_UP1_2G5;
@@ -997,12 +1012,6 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
997 } 1012 }
998 } 1013 }
999 1014
1000 bnx2_read_phy(bp, MII_ADVERTISE, &adv);
1001 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1002
1003 bnx2_read_phy(bp, MII_BMCR, &bmcr);
1004 new_bmcr = bmcr & ~BMCR_ANENABLE;
1005 new_bmcr |= BMCR_SPEED1000;
1006 if (bp->req_duplex == DUPLEX_FULL) { 1015 if (bp->req_duplex == DUPLEX_FULL) {
1007 adv |= ADVERTISE_1000XFULL; 1016 adv |= ADVERTISE_1000XFULL;
1008 new_bmcr |= BMCR_FULLDPLX; 1017 new_bmcr |= BMCR_FULLDPLX;
@@ -1023,6 +1032,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
1023 bp->link_up = 0; 1032 bp->link_up = 0;
1024 netif_carrier_off(bp->dev); 1033 netif_carrier_off(bp->dev);
1025 bnx2_write_phy(bp, MII_BMCR, new_bmcr); 1034 bnx2_write_phy(bp, MII_BMCR, new_bmcr);
1035 bnx2_report_link(bp);
1026 } 1036 }
1027 bnx2_write_phy(bp, MII_ADVERTISE, adv); 1037 bnx2_write_phy(bp, MII_ADVERTISE, adv);
1028 bnx2_write_phy(bp, MII_BMCR, new_bmcr); 1038 bnx2_write_phy(bp, MII_BMCR, new_bmcr);
@@ -1048,12 +1058,10 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
1048 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) { 1058 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1049 /* Force a link down visible on the other side */ 1059 /* Force a link down visible on the other side */
1050 if (bp->link_up) { 1060 if (bp->link_up) {
1051 int i;
1052
1053 bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK); 1061 bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
1054 for (i = 0; i < 110; i++) { 1062 spin_unlock_bh(&bp->phy_lock);
1055 udelay(100); 1063 msleep(20);
1056 } 1064 spin_lock_bh(&bp->phy_lock);
1057 } 1065 }
1058 1066
1059 bnx2_write_phy(bp, MII_ADVERTISE, new_adv); 1067 bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
@@ -1397,7 +1405,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp)
1397 for (i = 0; i < 10; i++) { 1405 for (i = 0; i < 10; i++) {
1398 if (bnx2_test_link(bp) == 0) 1406 if (bnx2_test_link(bp) == 0)
1399 break; 1407 break;
1400 udelay(10); 1408 msleep(100);
1401 } 1409 }
1402 1410
1403 mac_mode = REG_RD(bp, BNX2_EMAC_MODE); 1411 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
@@ -3713,7 +3721,9 @@ bnx2_init_nic(struct bnx2 *bp)
3713 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0) 3721 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
3714 return rc; 3722 return rc;
3715 3723
3724 spin_lock_bh(&bp->phy_lock);
3716 bnx2_init_phy(bp); 3725 bnx2_init_phy(bp);
3726 spin_unlock_bh(&bp->phy_lock);
3717 bnx2_set_link(bp); 3727 bnx2_set_link(bp);
3718 return 0; 3728 return 0;
3719} 3729}
@@ -3953,7 +3963,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
3953 bnx2_set_mac_loopback(bp); 3963 bnx2_set_mac_loopback(bp);
3954 } 3964 }
3955 else if (loopback_mode == BNX2_PHY_LOOPBACK) { 3965 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
3956 bp->loopback = 0; 3966 bp->loopback = PHY_LOOPBACK;
3957 bnx2_set_phy_loopback(bp); 3967 bnx2_set_phy_loopback(bp);
3958 } 3968 }
3959 else 3969 else
@@ -4744,10 +4754,14 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
4744 } 4754 }
4745 else { 4755 else {
4746 if (bp->phy_flags & PHY_SERDES_FLAG) { 4756 if (bp->phy_flags & PHY_SERDES_FLAG) {
4747 if ((cmd->speed != SPEED_1000) || 4757 if ((cmd->speed != SPEED_1000 &&
4748 (cmd->duplex != DUPLEX_FULL)) { 4758 cmd->speed != SPEED_2500) ||
4759 (cmd->duplex != DUPLEX_FULL))
4760 return -EINVAL;
4761
4762 if (cmd->speed == SPEED_2500 &&
4763 !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
4749 return -EINVAL; 4764 return -EINVAL;
4750 }
4751 } 4765 }
4752 else if (cmd->speed == SPEED_1000) { 4766 else if (cmd->speed == SPEED_1000) {
4753 return -EINVAL; 4767 return -EINVAL;
@@ -5289,6 +5303,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
5289 5303
5290 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS); 5304 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
5291 if (etest->flags & ETH_TEST_FL_OFFLINE) { 5305 if (etest->flags & ETH_TEST_FL_OFFLINE) {
5306 int i;
5307
5292 bnx2_netif_stop(bp); 5308 bnx2_netif_stop(bp);
5293 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG); 5309 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
5294 bnx2_free_skbs(bp); 5310 bnx2_free_skbs(bp);
@@ -5313,9 +5329,11 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
5313 } 5329 }
5314 5330
5315 /* wait for link up */ 5331 /* wait for link up */
5316 msleep_interruptible(3000); 5332 for (i = 0; i < 7; i++) {
5317 if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG)) 5333 if (bp->link_up)
5318 msleep_interruptible(4000); 5334 break;
5335 msleep_interruptible(1000);
5336 }
5319 } 5337 }
5320 5338
5321 if (bnx2_test_nvram(bp) != 0) { 5339 if (bnx2_test_nvram(bp) != 0) {
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index ca31904893ea..78ff09d70de4 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -3696,6 +3696,8 @@ struct l2_fhdr {
3696 3696
3697/* 5708 Serdes PHY registers */ 3697/* 5708 Serdes PHY registers */
3698 3698
3699#define BCM5708S_BMCR_FORCE_2500 0x20
3700
3699#define BCM5708S_UP1 0xb 3701#define BCM5708S_UP1 0xb
3700 3702
3701#define BCM5708S_UP1_2G5 0x1 3703#define BCM5708S_UP1_2G5 0x1