diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2009-08-14 18:36:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-14 18:36:41 -0400 |
commit | 0ea065e52eb6a0f029b5fa5ed2f142be1b66a153 (patch) | |
tree | f18bfc3027224f724ec00c6f4c0557e3f6861035 /drivers/net/sky2.c | |
parent | 481cea4a4d72aabe76dbb86b1a64f4e8931eca25 (diff) |
sky2: fix pause negotiation
The sky2 driver combines auto speed negotiation with automatic negotiation
of pause parameters; but the ethtool interface expects them to be
split. This patch allows autonegotiation to be used for speed, but
manually disable flow control.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 73 |
1 files changed, 47 insertions, 26 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4944fcc6b076..6788a91d68d5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -321,7 +321,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
321 | struct sky2_port *sky2 = netdev_priv(hw->dev[port]); | 321 | struct sky2_port *sky2 = netdev_priv(hw->dev[port]); |
322 | u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; | 322 | u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; |
323 | 323 | ||
324 | if (sky2->autoneg == AUTONEG_ENABLE && | 324 | if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) && |
325 | !(hw->flags & SKY2_HW_NEWER_PHY)) { | 325 | !(hw->flags & SKY2_HW_NEWER_PHY)) { |
326 | u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); | 326 | u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); |
327 | 327 | ||
@@ -363,7 +363,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
363 | ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); | 363 | ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); |
364 | 364 | ||
365 | /* downshift on PHY 88E1112 and 88E1149 is changed */ | 365 | /* downshift on PHY 88E1112 and 88E1149 is changed */ |
366 | if (sky2->autoneg == AUTONEG_ENABLE | 366 | if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) |
367 | && (hw->flags & SKY2_HW_NEWER_PHY)) { | 367 | && (hw->flags & SKY2_HW_NEWER_PHY)) { |
368 | /* set downshift counter to 3x and enable downshift */ | 368 | /* set downshift counter to 3x and enable downshift */ |
369 | ctrl &= ~PHY_M_PC_DSC_MSK; | 369 | ctrl &= ~PHY_M_PC_DSC_MSK; |
@@ -408,7 +408,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
408 | adv = PHY_AN_CSMA; | 408 | adv = PHY_AN_CSMA; |
409 | reg = 0; | 409 | reg = 0; |
410 | 410 | ||
411 | if (sky2->autoneg == AUTONEG_ENABLE) { | 411 | if (sky2->flags & SKY2_FLAG_AUTO_SPEED) { |
412 | if (sky2_is_copper(hw)) { | 412 | if (sky2_is_copper(hw)) { |
413 | if (sky2->advertising & ADVERTISED_1000baseT_Full) | 413 | if (sky2->advertising & ADVERTISED_1000baseT_Full) |
414 | ct1000 |= PHY_M_1000C_AFD; | 414 | ct1000 |= PHY_M_1000C_AFD; |
@@ -423,14 +423,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
423 | if (sky2->advertising & ADVERTISED_10baseT_Half) | 423 | if (sky2->advertising & ADVERTISED_10baseT_Half) |
424 | adv |= PHY_M_AN_10_HD; | 424 | adv |= PHY_M_AN_10_HD; |
425 | 425 | ||
426 | adv |= copper_fc_adv[sky2->flow_mode]; | ||
427 | } else { /* special defines for FIBER (88E1040S only) */ | 426 | } else { /* special defines for FIBER (88E1040S only) */ |
428 | if (sky2->advertising & ADVERTISED_1000baseT_Full) | 427 | if (sky2->advertising & ADVERTISED_1000baseT_Full) |
429 | adv |= PHY_M_AN_1000X_AFD; | 428 | adv |= PHY_M_AN_1000X_AFD; |
430 | if (sky2->advertising & ADVERTISED_1000baseT_Half) | 429 | if (sky2->advertising & ADVERTISED_1000baseT_Half) |
431 | adv |= PHY_M_AN_1000X_AHD; | 430 | adv |= PHY_M_AN_1000X_AHD; |
432 | |||
433 | adv |= fiber_fc_adv[sky2->flow_mode]; | ||
434 | } | 431 | } |
435 | 432 | ||
436 | /* Restart Auto-negotiation */ | 433 | /* Restart Auto-negotiation */ |
@@ -439,8 +436,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
439 | /* forced speed/duplex settings */ | 436 | /* forced speed/duplex settings */ |
440 | ct1000 = PHY_M_1000C_MSE; | 437 | ct1000 = PHY_M_1000C_MSE; |
441 | 438 | ||
442 | /* Disable auto update for duplex flow control and speed */ | 439 | /* Disable auto update for duplex flow control and duplex */ |
443 | reg |= GM_GPCR_AU_ALL_DIS; | 440 | reg |= GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_SPD_DIS; |
444 | 441 | ||
445 | switch (sky2->speed) { | 442 | switch (sky2->speed) { |
446 | case SPEED_1000: | 443 | case SPEED_1000: |
@@ -458,8 +455,15 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
458 | ctrl |= PHY_CT_DUP_MD; | 455 | ctrl |= PHY_CT_DUP_MD; |
459 | } else if (sky2->speed < SPEED_1000) | 456 | } else if (sky2->speed < SPEED_1000) |
460 | sky2->flow_mode = FC_NONE; | 457 | sky2->flow_mode = FC_NONE; |
458 | } | ||
461 | 459 | ||
462 | 460 | if (sky2->flags & SKY2_FLAG_AUTO_PAUSE) { | |
461 | if (sky2_is_copper(hw)) | ||
462 | adv |= copper_fc_adv[sky2->flow_mode]; | ||
463 | else | ||
464 | adv |= fiber_fc_adv[sky2->flow_mode]; | ||
465 | } else { | ||
466 | reg |= GM_GPCR_AU_FCT_DIS; | ||
463 | reg |= gm_fc_disable[sky2->flow_mode]; | 467 | reg |= gm_fc_disable[sky2->flow_mode]; |
464 | 468 | ||
465 | /* Forward pause packets to GMAC? */ | 469 | /* Forward pause packets to GMAC? */ |
@@ -594,7 +598,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
594 | /* no effect on Yukon-XL */ | 598 | /* no effect on Yukon-XL */ |
595 | gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); | 599 | gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); |
596 | 600 | ||
597 | if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { | 601 | if ( !(sky2->flags & SKY2_FLAG_AUTO_SPEED) |
602 | || sky2->speed == SPEED_100) { | ||
598 | /* turn on 100 Mbps LED (LED_LINK100) */ | 603 | /* turn on 100 Mbps LED (LED_LINK100) */ |
599 | ledover |= PHY_M_LED_MO_100(MO_LED_ON); | 604 | ledover |= PHY_M_LED_MO_100(MO_LED_ON); |
600 | } | 605 | } |
@@ -605,7 +610,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
605 | } | 610 | } |
606 | 611 | ||
607 | /* Enable phy interrupt on auto-negotiation complete (or link up) */ | 612 | /* Enable phy interrupt on auto-negotiation complete (or link up) */ |
608 | if (sky2->autoneg == AUTONEG_ENABLE) | 613 | if (sky2->flags & SKY2_FLAG_AUTO_SPEED) |
609 | gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); | 614 | gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); |
610 | else | 615 | else |
611 | gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); | 616 | gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); |
@@ -661,7 +666,9 @@ static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port) | |||
661 | 666 | ||
662 | /* setup General Purpose Control Register */ | 667 | /* setup General Purpose Control Register */ |
663 | gma_write16(hw, port, GM_GP_CTRL, | 668 | gma_write16(hw, port, GM_GP_CTRL, |
664 | GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); | 669 | GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | |
670 | GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS | | ||
671 | GM_GPCR_AU_SPD_DIS); | ||
665 | 672 | ||
666 | if (hw->chip_id != CHIP_ID_YUKON_EC) { | 673 | if (hw->chip_id != CHIP_ID_YUKON_EC) { |
667 | if (hw->chip_id == CHIP_ID_YUKON_EC_U) { | 674 | if (hw->chip_id == CHIP_ID_YUKON_EC_U) { |
@@ -1117,7 +1124,8 @@ static void rx_set_checksum(struct sky2_port *sky2) | |||
1117 | 1124 | ||
1118 | sky2_write32(sky2->hw, | 1125 | sky2_write32(sky2->hw, |
1119 | Q_ADDR(rxqaddr[sky2->port], Q_CSR), | 1126 | Q_ADDR(rxqaddr[sky2->port], Q_CSR), |
1120 | sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); | 1127 | (sky2->flags & SKY2_FLAG_RX_CHECKSUM) |
1128 | ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); | ||
1121 | } | 1129 | } |
1122 | 1130 | ||
1123 | /* | 1131 | /* |
@@ -2087,7 +2095,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) | |||
2087 | printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", | 2095 | printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", |
2088 | sky2->netdev->name, istatus, phystat); | 2096 | sky2->netdev->name, istatus, phystat); |
2089 | 2097 | ||
2090 | if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) { | 2098 | if (istatus & PHY_M_IS_AN_COMPL) { |
2091 | if (sky2_autoneg_done(sky2, phystat) == 0) | 2099 | if (sky2_autoneg_done(sky2, phystat) == 0) |
2092 | sky2_link_up(sky2); | 2100 | sky2_link_up(sky2); |
2093 | goto out; | 2101 | goto out; |
@@ -2453,7 +2461,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) | |||
2453 | 2461 | ||
2454 | /* This chip reports checksum status differently */ | 2462 | /* This chip reports checksum status differently */ |
2455 | if (hw->flags & SKY2_HW_NEW_LE) { | 2463 | if (hw->flags & SKY2_HW_NEW_LE) { |
2456 | if (sky2->rx_csum && | 2464 | if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) && |
2457 | (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && | 2465 | (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && |
2458 | (le->css & CSS_TCPUDPCSOK)) | 2466 | (le->css & CSS_TCPUDPCSOK)) |
2459 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 2467 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -2480,7 +2488,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) | |||
2480 | /* fall through */ | 2488 | /* fall through */ |
2481 | #endif | 2489 | #endif |
2482 | case OP_RXCHKS: | 2490 | case OP_RXCHKS: |
2483 | if (!sky2->rx_csum) | 2491 | if (!(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) |
2484 | break; | 2492 | break; |
2485 | 2493 | ||
2486 | /* If this happens then driver assuming wrong format */ | 2494 | /* If this happens then driver assuming wrong format */ |
@@ -2505,7 +2513,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) | |||
2505 | printk(KERN_NOTICE PFX "%s: hardware receive " | 2513 | printk(KERN_NOTICE PFX "%s: hardware receive " |
2506 | "checksum problem (status = %#x)\n", | 2514 | "checksum problem (status = %#x)\n", |
2507 | dev->name, status); | 2515 | dev->name, status); |
2508 | sky2->rx_csum = 0; | 2516 | sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; |
2517 | |||
2509 | sky2_write32(sky2->hw, | 2518 | sky2_write32(sky2->hw, |
2510 | Q_ADDR(rxqaddr[port], Q_CSR), | 2519 | Q_ADDR(rxqaddr[port], Q_CSR), |
2511 | BMU_DIS_RX_CHKSUM); | 2520 | BMU_DIS_RX_CHKSUM); |
@@ -3206,7 +3215,8 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
3206 | } | 3215 | } |
3207 | 3216 | ||
3208 | ecmd->advertising = sky2->advertising; | 3217 | ecmd->advertising = sky2->advertising; |
3209 | ecmd->autoneg = sky2->autoneg; | 3218 | ecmd->autoneg = (sky2->flags & SKY2_FLAG_AUTO_SPEED) |
3219 | ? AUTONEG_ENABLE : AUTONEG_DISABLE; | ||
3210 | ecmd->duplex = sky2->duplex; | 3220 | ecmd->duplex = sky2->duplex; |
3211 | return 0; | 3221 | return 0; |
3212 | } | 3222 | } |
@@ -3218,6 +3228,7 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
3218 | u32 supported = sky2_supported_modes(hw); | 3228 | u32 supported = sky2_supported_modes(hw); |
3219 | 3229 | ||
3220 | if (ecmd->autoneg == AUTONEG_ENABLE) { | 3230 | if (ecmd->autoneg == AUTONEG_ENABLE) { |
3231 | sky2->flags |= SKY2_FLAG_AUTO_SPEED; | ||
3221 | ecmd->advertising = supported; | 3232 | ecmd->advertising = supported; |
3222 | sky2->duplex = -1; | 3233 | sky2->duplex = -1; |
3223 | sky2->speed = -1; | 3234 | sky2->speed = -1; |
@@ -3259,9 +3270,9 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
3259 | 3270 | ||
3260 | sky2->speed = ecmd->speed; | 3271 | sky2->speed = ecmd->speed; |
3261 | sky2->duplex = ecmd->duplex; | 3272 | sky2->duplex = ecmd->duplex; |
3273 | sky2->flags &= ~SKY2_FLAG_AUTO_SPEED; | ||
3262 | } | 3274 | } |
3263 | 3275 | ||
3264 | sky2->autoneg = ecmd->autoneg; | ||
3265 | sky2->advertising = ecmd->advertising; | 3276 | sky2->advertising = ecmd->advertising; |
3266 | 3277 | ||
3267 | if (netif_running(dev)) { | 3278 | if (netif_running(dev)) { |
@@ -3331,14 +3342,17 @@ static u32 sky2_get_rx_csum(struct net_device *dev) | |||
3331 | { | 3342 | { |
3332 | struct sky2_port *sky2 = netdev_priv(dev); | 3343 | struct sky2_port *sky2 = netdev_priv(dev); |
3333 | 3344 | ||
3334 | return sky2->rx_csum; | 3345 | return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM); |
3335 | } | 3346 | } |
3336 | 3347 | ||
3337 | static int sky2_set_rx_csum(struct net_device *dev, u32 data) | 3348 | static int sky2_set_rx_csum(struct net_device *dev, u32 data) |
3338 | { | 3349 | { |
3339 | struct sky2_port *sky2 = netdev_priv(dev); | 3350 | struct sky2_port *sky2 = netdev_priv(dev); |
3340 | 3351 | ||
3341 | sky2->rx_csum = data; | 3352 | if (data) |
3353 | sky2->flags |= SKY2_FLAG_RX_CHECKSUM; | ||
3354 | else | ||
3355 | sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; | ||
3342 | 3356 | ||
3343 | sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), | 3357 | sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), |
3344 | data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); | 3358 | data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); |
@@ -3356,7 +3370,7 @@ static int sky2_nway_reset(struct net_device *dev) | |||
3356 | { | 3370 | { |
3357 | struct sky2_port *sky2 = netdev_priv(dev); | 3371 | struct sky2_port *sky2 = netdev_priv(dev); |
3358 | 3372 | ||
3359 | if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE) | 3373 | if (!netif_running(dev) || !(sky2->flags & SKY2_FLAG_AUTO_SPEED)) |
3360 | return -EINVAL; | 3374 | return -EINVAL; |
3361 | 3375 | ||
3362 | sky2_phy_reinit(sky2); | 3376 | sky2_phy_reinit(sky2); |
@@ -3596,7 +3610,8 @@ static void sky2_get_pauseparam(struct net_device *dev, | |||
3596 | ecmd->tx_pause = ecmd->rx_pause = 1; | 3610 | ecmd->tx_pause = ecmd->rx_pause = 1; |
3597 | } | 3611 | } |
3598 | 3612 | ||
3599 | ecmd->autoneg = sky2->autoneg; | 3613 | ecmd->autoneg = (sky2->flags & SKY2_FLAG_AUTO_PAUSE) |
3614 | ? AUTONEG_ENABLE : AUTONEG_DISABLE; | ||
3600 | } | 3615 | } |
3601 | 3616 | ||
3602 | static int sky2_set_pauseparam(struct net_device *dev, | 3617 | static int sky2_set_pauseparam(struct net_device *dev, |
@@ -3604,7 +3619,11 @@ static int sky2_set_pauseparam(struct net_device *dev, | |||
3604 | { | 3619 | { |
3605 | struct sky2_port *sky2 = netdev_priv(dev); | 3620 | struct sky2_port *sky2 = netdev_priv(dev); |
3606 | 3621 | ||
3607 | sky2->autoneg = ecmd->autoneg; | 3622 | if (ecmd->autoneg == AUTONEG_ENABLE) |
3623 | sky2->flags |= SKY2_FLAG_AUTO_PAUSE; | ||
3624 | else | ||
3625 | sky2->flags &= ~SKY2_FLAG_AUTO_PAUSE; | ||
3626 | |||
3608 | sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause); | 3627 | sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause); |
3609 | 3628 | ||
3610 | if (netif_running(dev)) | 3629 | if (netif_running(dev)) |
@@ -4294,13 +4313,15 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, | |||
4294 | sky2->msg_enable = netif_msg_init(debug, default_msg); | 4313 | sky2->msg_enable = netif_msg_init(debug, default_msg); |
4295 | 4314 | ||
4296 | /* Auto speed and flow control */ | 4315 | /* Auto speed and flow control */ |
4297 | sky2->autoneg = AUTONEG_ENABLE; | 4316 | sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE; |
4317 | if (hw->chip_id != CHIP_ID_YUKON_XL) | ||
4318 | sky2->flags |= SKY2_FLAG_RX_CHECKSUM; | ||
4319 | |||
4298 | sky2->flow_mode = FC_BOTH; | 4320 | sky2->flow_mode = FC_BOTH; |
4299 | 4321 | ||
4300 | sky2->duplex = -1; | 4322 | sky2->duplex = -1; |
4301 | sky2->speed = -1; | 4323 | sky2->speed = -1; |
4302 | sky2->advertising = sky2_supported_modes(hw); | 4324 | sky2->advertising = sky2_supported_modes(hw); |
4303 | sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL); | ||
4304 | sky2->wol = wol; | 4325 | sky2->wol = wol; |
4305 | 4326 | ||
4306 | spin_lock_init(&sky2->phy_lock); | 4327 | spin_lock_init(&sky2->phy_lock); |