aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2008-02-22 19:00:33 -0500
committerJeff Garzik <jeff@garzik.org>2008-02-24 00:07:39 -0500
commita84d0a3d6909c871bfa617a45a7517ce9292d4fb (patch)
treea137bb82a4746a66f5bb7a33829b454e83026392 /drivers/net/sky2.c
parentf11cf25ef345a320b152aa68a014c8a65cf4ed44 (diff)
sky2: fix LED management
Fix problems in LED management, so ethtool -p works correctly on Yukon-EC and other chips. The driver was incorrectly setting the PHY LED overide bits. Moral: read the spec sheet, not the vendor driver. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c123
1 files changed, 61 insertions, 62 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 9a6295909e43..54c662690f65 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -572,8 +572,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
572 default: 572 default:
573 /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ 573 /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
574 ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; 574 ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
575
575 /* turn off the Rx LED (LED_RX) */ 576 /* turn off the Rx LED (LED_RX) */
576 ledover &= ~PHY_M_LED_MO_RX; 577 ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
577 } 578 }
578 579
579 if (hw->chip_id == CHIP_ID_YUKON_EC_U && 580 if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
@@ -602,7 +603,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
602 603
603 if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { 604 if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
604 /* turn on 100 Mbps LED (LED_LINK100) */ 605 /* turn on 100 Mbps LED (LED_LINK100) */
605 ledover |= PHY_M_LED_MO_100; 606 ledover |= PHY_M_LED_MO_100(MO_LED_ON);
606 } 607 }
607 608
608 if (ledover) 609 if (ledover)
@@ -3322,82 +3323,80 @@ static void sky2_set_multicast(struct net_device *dev)
3322/* Can have one global because blinking is controlled by 3323/* Can have one global because blinking is controlled by
3323 * ethtool and that is always under RTNL mutex 3324 * ethtool and that is always under RTNL mutex
3324 */ 3325 */
3325static void sky2_led(struct sky2_hw *hw, unsigned port, int on) 3326static void sky2_led(struct sky2_port *sky2, enum led_mode mode)
3326{ 3327{
3327 u16 pg; 3328 struct sky2_hw *hw = sky2->hw;
3329 unsigned port = sky2->port;
3328 3330
3329 switch (hw->chip_id) { 3331 spin_lock_bh(&sky2->phy_lock);
3330 case CHIP_ID_YUKON_XL: 3332 if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
3333 hw->chip_id == CHIP_ID_YUKON_EX ||
3334 hw->chip_id == CHIP_ID_YUKON_SUPR) {
3335 u16 pg;
3331 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 3336 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
3332 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); 3337 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
3333 gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
3334 on ? (PHY_M_LEDC_LOS_CTRL(1) |
3335 PHY_M_LEDC_INIT_CTRL(7) |
3336 PHY_M_LEDC_STA1_CTRL(7) |
3337 PHY_M_LEDC_STA0_CTRL(7))
3338 : 0);
3339 3338
3340 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); 3339 switch (mode) {
3341 break; 3340 case MO_LED_OFF:
3341 gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
3342 PHY_M_LEDC_LOS_CTRL(8) |
3343 PHY_M_LEDC_INIT_CTRL(8) |
3344 PHY_M_LEDC_STA1_CTRL(8) |
3345 PHY_M_LEDC_STA0_CTRL(8));
3346 break;
3347 case MO_LED_ON:
3348 gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
3349 PHY_M_LEDC_LOS_CTRL(9) |
3350 PHY_M_LEDC_INIT_CTRL(9) |
3351 PHY_M_LEDC_STA1_CTRL(9) |
3352 PHY_M_LEDC_STA0_CTRL(9));
3353 break;
3354 case MO_LED_BLINK:
3355 gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
3356 PHY_M_LEDC_LOS_CTRL(0xa) |
3357 PHY_M_LEDC_INIT_CTRL(0xa) |
3358 PHY_M_LEDC_STA1_CTRL(0xa) |
3359 PHY_M_LEDC_STA0_CTRL(0xa));
3360 break;
3361 case MO_LED_NORM:
3362 gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
3363 PHY_M_LEDC_LOS_CTRL(1) |
3364 PHY_M_LEDC_INIT_CTRL(8) |
3365 PHY_M_LEDC_STA1_CTRL(7) |
3366 PHY_M_LEDC_STA0_CTRL(7));
3367 }
3342 3368
3343 default: 3369 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
3344 gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); 3370 } else
3345 gm_phy_write(hw, port, PHY_MARV_LED_OVER, 3371 gm_phy_write(hw, port, PHY_MARV_LED_OVER,
3346 on ? PHY_M_LED_ALL : 0); 3372 PHY_M_LED_MO_DUP(mode) |
3347 } 3373 PHY_M_LED_MO_10(mode) |
3374 PHY_M_LED_MO_100(mode) |
3375 PHY_M_LED_MO_1000(mode) |
3376 PHY_M_LED_MO_RX(mode) |
3377 PHY_M_LED_MO_TX(mode));
3378
3379 spin_unlock_bh(&sky2->phy_lock);
3348} 3380}
3349 3381
3350/* blink LED's for finding board */ 3382/* blink LED's for finding board */
3351static int sky2_phys_id(struct net_device *dev, u32 data) 3383static int sky2_phys_id(struct net_device *dev, u32 data)
3352{ 3384{
3353 struct sky2_port *sky2 = netdev_priv(dev); 3385 struct sky2_port *sky2 = netdev_priv(dev);
3354 struct sky2_hw *hw = sky2->hw; 3386 unsigned int i;
3355 unsigned port = sky2->port;
3356 u16 ledctrl, ledover = 0;
3357 long ms;
3358 int interrupted;
3359 int onoff = 1;
3360 3387
3361 if (!data || data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)) 3388 if (data == 0)
3362 ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT); 3389 data = UINT_MAX;
3363 else
3364 ms = data * 1000;
3365
3366 /* save initial values */
3367 spin_lock_bh(&sky2->phy_lock);
3368 if (hw->chip_id == CHIP_ID_YUKON_XL) {
3369 u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
3370 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
3371 ledctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
3372 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
3373 } else {
3374 ledctrl = gm_phy_read(hw, port, PHY_MARV_LED_CTRL);
3375 ledover = gm_phy_read(hw, port, PHY_MARV_LED_OVER);
3376 }
3377
3378 interrupted = 0;
3379 while (!interrupted && ms > 0) {
3380 sky2_led(hw, port, onoff);
3381 onoff = !onoff;
3382
3383 spin_unlock_bh(&sky2->phy_lock);
3384 interrupted = msleep_interruptible(250);
3385 spin_lock_bh(&sky2->phy_lock);
3386
3387 ms -= 250;
3388 }
3389 3390
3390 /* resume regularly scheduled programming */ 3391 for (i = 0; i < data; i++) {
3391 if (hw->chip_id == CHIP_ID_YUKON_XL) { 3392 sky2_led(sky2, MO_LED_ON);
3392 u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 3393 if (msleep_interruptible(500))
3393 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); 3394 break;
3394 gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ledctrl); 3395 sky2_led(sky2, MO_LED_OFF);
3395 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); 3396 if (msleep_interruptible(500))
3396 } else { 3397 break;
3397 gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
3398 gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
3399 } 3398 }
3400 spin_unlock_bh(&sky2->phy_lock); 3399 sky2_led(sky2, MO_LED_NORM);
3401 3400
3402 return 0; 3401 return 0;
3403} 3402}