Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Stephen Hemminger and committed by
Jeff Garzik
a84d0a3d f11cf25e

+75 -73
+61 -62
drivers/net/sky2.c
··· 572 572 default: 573 573 /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ 574 574 ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; 575 + 575 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 580 if (hw->chip_id == CHIP_ID_YUKON_EC_U && ··· 603 602 604 603 if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { 605 604 /* turn on 100 Mbps LED (LED_LINK100) */ 606 - ledover |= PHY_M_LED_MO_100; 605 + ledover |= PHY_M_LED_MO_100(MO_LED_ON); 607 606 } 608 607 609 608 if (ledover) ··· 3323 3322 /* Can have one global because blinking is controlled by 3324 3323 * ethtool and that is always under RTNL mutex 3325 3324 */ 3326 - static void sky2_led(struct sky2_hw *hw, unsigned port, int on) 3325 + static void sky2_led(struct sky2_port *sky2, enum led_mode mode) 3327 3326 { 3328 - u16 pg; 3327 + struct sky2_hw *hw = sky2->hw; 3328 + unsigned port = sky2->port; 3329 3329 3330 - switch (hw->chip_id) { 3331 - case CHIP_ID_YUKON_XL: 3330 + spin_lock_bh(&sky2->phy_lock); 3331 + if (hw->chip_id == CHIP_ID_YUKON_EC_U || 3332 + hw->chip_id == CHIP_ID_YUKON_EX || 3333 + hw->chip_id == CHIP_ID_YUKON_SUPR) { 3334 + u16 pg; 3332 3335 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 3333 3336 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); 3334 - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, 3335 - on ? (PHY_M_LEDC_LOS_CTRL(1) | 3336 - PHY_M_LEDC_INIT_CTRL(7) | 3337 - PHY_M_LEDC_STA1_CTRL(7) | 3338 - PHY_M_LEDC_STA0_CTRL(7)) 3339 - : 0); 3337 + 3338 + switch (mode) { 3339 + case MO_LED_OFF: 3340 + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, 3341 + PHY_M_LEDC_LOS_CTRL(8) | 3342 + PHY_M_LEDC_INIT_CTRL(8) | 3343 + PHY_M_LEDC_STA1_CTRL(8) | 3344 + PHY_M_LEDC_STA0_CTRL(8)); 3345 + break; 3346 + case MO_LED_ON: 3347 + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, 3348 + PHY_M_LEDC_LOS_CTRL(9) | 3349 + PHY_M_LEDC_INIT_CTRL(9) | 3350 + PHY_M_LEDC_STA1_CTRL(9) | 3351 + PHY_M_LEDC_STA0_CTRL(9)); 3352 + break; 3353 + case MO_LED_BLINK: 3354 + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, 3355 + PHY_M_LEDC_LOS_CTRL(0xa) | 3356 + PHY_M_LEDC_INIT_CTRL(0xa) | 3357 + PHY_M_LEDC_STA1_CTRL(0xa) | 3358 + PHY_M_LEDC_STA0_CTRL(0xa)); 3359 + break; 3360 + case MO_LED_NORM: 3361 + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, 3362 + PHY_M_LEDC_LOS_CTRL(1) | 3363 + PHY_M_LEDC_INIT_CTRL(8) | 3364 + PHY_M_LEDC_STA1_CTRL(7) | 3365 + PHY_M_LEDC_STA0_CTRL(7)); 3366 + } 3340 3367 3341 3368 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); 3342 - break; 3343 - 3344 - default: 3345 - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); 3369 + } else 3346 3370 gm_phy_write(hw, port, PHY_MARV_LED_OVER, 3347 - on ? PHY_M_LED_ALL : 0); 3348 - } 3371 + PHY_M_LED_MO_DUP(mode) | 3372 + PHY_M_LED_MO_10(mode) | 3373 + PHY_M_LED_MO_100(mode) | 3374 + PHY_M_LED_MO_1000(mode) | 3375 + PHY_M_LED_MO_RX(mode) | 3376 + PHY_M_LED_MO_TX(mode)); 3377 + 3378 + spin_unlock_bh(&sky2->phy_lock); 3349 3379 } 3350 3380 3351 3381 /* blink LED's for finding board */ 3352 3382 static int sky2_phys_id(struct net_device *dev, u32 data) 3353 3383 { 3354 3384 struct sky2_port *sky2 = netdev_priv(dev); 3355 - struct sky2_hw *hw = sky2->hw; 3356 - unsigned port = sky2->port; 3357 - u16 ledctrl, ledover = 0; 3358 - long ms; 3359 - int interrupted; 3360 - int onoff = 1; 3385 + unsigned int i; 3361 3386 3362 - if (!data || data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)) 3363 - ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT); 3364 - else 3365 - ms = data * 1000; 3387 + if (data == 0) 3388 + data = UINT_MAX; 3366 3389 3367 - /* save initial values */ 3368 - spin_lock_bh(&sky2->phy_lock); 3369 - if (hw->chip_id == CHIP_ID_YUKON_XL) { 3370 - u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 3371 - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); 3372 - ledctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); 3373 - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); 3374 - } else { 3375 - ledctrl = gm_phy_read(hw, port, PHY_MARV_LED_CTRL); 3376 - ledover = gm_phy_read(hw, port, PHY_MARV_LED_OVER); 3390 + for (i = 0; i < data; i++) { 3391 + sky2_led(sky2, MO_LED_ON); 3392 + if (msleep_interruptible(500)) 3393 + break; 3394 + sky2_led(sky2, MO_LED_OFF); 3395 + if (msleep_interruptible(500)) 3396 + break; 3377 3397 } 3378 - 3379 - interrupted = 0; 3380 - while (!interrupted && ms > 0) { 3381 - sky2_led(hw, port, onoff); 3382 - onoff = !onoff; 3383 - 3384 - spin_unlock_bh(&sky2->phy_lock); 3385 - interrupted = msleep_interruptible(250); 3386 - spin_lock_bh(&sky2->phy_lock); 3387 - 3388 - ms -= 250; 3389 - } 3390 - 3391 - /* resume regularly scheduled programming */ 3392 - if (hw->chip_id == CHIP_ID_YUKON_XL) { 3393 - u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 3394 - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); 3395 - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ledctrl); 3396 - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); 3397 - } else { 3398 - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); 3399 - gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); 3400 - } 3401 - spin_unlock_bh(&sky2->phy_lock); 3398 + sky2_led(sky2, MO_LED_NORM); 3402 3399 3403 3400 return 0; 3404 3401 }
+14 -11
drivers/net/sky2.h
··· 1318 1318 BLINK_670MS = 4,/* 670 ms */ 1319 1319 }; 1320 1320 1321 - /**** PHY_MARV_LED_OVER 16 bit r/w LED control */ 1322 - enum { 1323 - PHY_M_LED_MO_DUP = 3<<10,/* Bit 11..10: Duplex */ 1324 - PHY_M_LED_MO_10 = 3<<8, /* Bit 9.. 8: Link 10 */ 1325 - PHY_M_LED_MO_100 = 3<<6, /* Bit 7.. 6: Link 100 */ 1326 - PHY_M_LED_MO_1000 = 3<<4, /* Bit 5.. 4: Link 1000 */ 1327 - PHY_M_LED_MO_RX = 3<<2, /* Bit 3.. 2: Rx */ 1328 - PHY_M_LED_MO_TX = 3<<0, /* Bit 1.. 0: Tx */ 1321 + /***** PHY_MARV_LED_OVER 16 bit r/w Manual LED Override Reg *****/ 1322 + #define PHY_M_LED_MO_SGMII(x) ((x)<<14) /* Bit 15..14: SGMII AN Timer */ 1329 1323 1330 - PHY_M_LED_ALL = PHY_M_LED_MO_DUP | PHY_M_LED_MO_10 1331 - | PHY_M_LED_MO_100 | PHY_M_LED_MO_1000 1332 - | PHY_M_LED_MO_RX, 1324 + #define PHY_M_LED_MO_DUP(x) ((x)<<10) /* Bit 11..10: Duplex */ 1325 + #define PHY_M_LED_MO_10(x) ((x)<<8) /* Bit 9.. 8: Link 10 */ 1326 + #define PHY_M_LED_MO_100(x) ((x)<<6) /* Bit 7.. 6: Link 100 */ 1327 + #define PHY_M_LED_MO_1000(x) ((x)<<4) /* Bit 5.. 4: Link 1000 */ 1328 + #define PHY_M_LED_MO_RX(x) ((x)<<2) /* Bit 3.. 2: Rx */ 1329 + #define PHY_M_LED_MO_TX(x) ((x)<<0) /* Bit 1.. 0: Tx */ 1330 + 1331 + enum led_mode { 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 1338 /***** PHY_MARV_EXT_CTRL_2 16 bit r/w Ext. PHY Specific Ctrl 2 *****/