aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
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
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')
-rw-r--r--drivers/net/sky2.c123
-rw-r--r--drivers/net/sky2.h27
2 files changed, 76 insertions, 74 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}
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 5ab5c1c7c5aa..7bb3ba9bcbd8 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1318,18 +1318,21 @@ enum {
1318 BLINK_670MS = 4,/* 670 ms */ 1318 BLINK_670MS = 4,/* 670 ms */
1319}; 1319};
1320 1320
1321/**** PHY_MARV_LED_OVER 16 bit r/w LED control */ 1321/***** PHY_MARV_LED_OVER 16 bit r/w Manual LED Override Reg *****/
1322enum { 1322#define PHY_M_LED_MO_SGMII(x) ((x)<<14) /* Bit 15..14: SGMII AN Timer */
1323 PHY_M_LED_MO_DUP = 3<<10,/* Bit 11..10: Duplex */ 1323
1324 PHY_M_LED_MO_10 = 3<<8, /* Bit 9.. 8: Link 10 */ 1324#define PHY_M_LED_MO_DUP(x) ((x)<<10) /* Bit 11..10: Duplex */
1325 PHY_M_LED_MO_100 = 3<<6, /* Bit 7.. 6: Link 100 */ 1325#define PHY_M_LED_MO_10(x) ((x)<<8) /* Bit 9.. 8: Link 10 */
1326 PHY_M_LED_MO_1000 = 3<<4, /* Bit 5.. 4: Link 1000 */ 1326#define PHY_M_LED_MO_100(x) ((x)<<6) /* Bit 7.. 6: Link 100 */
1327 PHY_M_LED_MO_RX = 3<<2, /* Bit 3.. 2: Rx */ 1327#define PHY_M_LED_MO_1000(x) ((x)<<4) /* Bit 5.. 4: Link 1000 */
1328 PHY_M_LED_MO_TX = 3<<0, /* Bit 1.. 0: Tx */ 1328#define PHY_M_LED_MO_RX(x) ((x)<<2) /* Bit 3.. 2: Rx */
1329 1329#define PHY_M_LED_MO_TX(x) ((x)<<0) /* Bit 1.. 0: Tx */
1330 PHY_M_LED_ALL = PHY_M_LED_MO_DUP | PHY_M_LED_MO_10 1330
1331 | PHY_M_LED_MO_100 | PHY_M_LED_MO_1000 1331enum led_mode {
1332 | PHY_M_LED_MO_RX, 1332 MO_LED_NORM = 0,
1333 MO_LED_BLINK = 1,
1334 MO_LED_OFF = 2,
1335 MO_LED_ON = 3,
1333}; 1336};
1334 1337
1335/***** PHY_MARV_EXT_CTRL_2 16 bit r/w Ext. PHY Specific Ctrl 2 *****/ 1338/***** PHY_MARV_EXT_CTRL_2 16 bit r/w Ext. PHY Specific Ctrl 2 *****/