diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ucc_geth.c | 85 | ||||
-rw-r--r-- | drivers/net/ucc_geth.h | 1 | ||||
-rw-r--r-- | drivers/net/ucc_geth_ethtool.c | 40 |
3 files changed, 126 insertions, 0 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index d2ca61d3dffc..7fb96f33bade 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -3497,6 +3497,10 @@ static int ucc_geth_open(struct net_device *dev) | |||
3497 | napi_enable(&ugeth->napi); | 3497 | napi_enable(&ugeth->napi); |
3498 | netif_start_queue(dev); | 3498 | netif_start_queue(dev); |
3499 | 3499 | ||
3500 | device_set_wakeup_capable(&dev->dev, | ||
3501 | qe_alive_during_sleep() || ugeth->phydev->irq); | ||
3502 | device_set_wakeup_enable(&dev->dev, ugeth->wol_en); | ||
3503 | |||
3500 | return err; | 3504 | return err; |
3501 | 3505 | ||
3502 | err: | 3506 | err: |
@@ -3561,6 +3565,85 @@ static void ucc_geth_timeout(struct net_device *dev) | |||
3561 | schedule_work(&ugeth->timeout_work); | 3565 | schedule_work(&ugeth->timeout_work); |
3562 | } | 3566 | } |
3563 | 3567 | ||
3568 | |||
3569 | #ifdef CONFIG_PM | ||
3570 | |||
3571 | static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state) | ||
3572 | { | ||
3573 | struct net_device *ndev = dev_get_drvdata(&ofdev->dev); | ||
3574 | struct ucc_geth_private *ugeth = netdev_priv(ndev); | ||
3575 | |||
3576 | if (!netif_running(ndev)) | ||
3577 | return 0; | ||
3578 | |||
3579 | napi_disable(&ugeth->napi); | ||
3580 | |||
3581 | /* | ||
3582 | * Disable the controller, otherwise we'll wakeup on any network | ||
3583 | * activity. | ||
3584 | */ | ||
3585 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); | ||
3586 | |||
3587 | if (ugeth->wol_en & WAKE_MAGIC) { | ||
3588 | setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); | ||
3589 | setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); | ||
3590 | ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX); | ||
3591 | } else if (!(ugeth->wol_en & WAKE_PHY)) { | ||
3592 | phy_stop(ugeth->phydev); | ||
3593 | } | ||
3594 | |||
3595 | return 0; | ||
3596 | } | ||
3597 | |||
3598 | static int ucc_geth_resume(struct of_device *ofdev) | ||
3599 | { | ||
3600 | struct net_device *ndev = dev_get_drvdata(&ofdev->dev); | ||
3601 | struct ucc_geth_private *ugeth = netdev_priv(ndev); | ||
3602 | int err; | ||
3603 | |||
3604 | if (!netif_running(ndev)) | ||
3605 | return 0; | ||
3606 | |||
3607 | if (qe_alive_during_sleep()) { | ||
3608 | if (ugeth->wol_en & WAKE_MAGIC) { | ||
3609 | ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX); | ||
3610 | clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); | ||
3611 | clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); | ||
3612 | } | ||
3613 | ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); | ||
3614 | } else { | ||
3615 | /* | ||
3616 | * Full reinitialization is required if QE shuts down | ||
3617 | * during sleep. | ||
3618 | */ | ||
3619 | ucc_geth_memclean(ugeth); | ||
3620 | |||
3621 | err = ucc_geth_init_mac(ugeth); | ||
3622 | if (err) { | ||
3623 | ugeth_err("%s: Cannot initialize MAC, aborting.", | ||
3624 | ndev->name); | ||
3625 | return err; | ||
3626 | } | ||
3627 | } | ||
3628 | |||
3629 | ugeth->oldlink = 0; | ||
3630 | ugeth->oldspeed = 0; | ||
3631 | ugeth->oldduplex = -1; | ||
3632 | |||
3633 | phy_stop(ugeth->phydev); | ||
3634 | phy_start(ugeth->phydev); | ||
3635 | |||
3636 | napi_enable(&ugeth->napi); | ||
3637 | netif_start_queue(ndev); | ||
3638 | |||
3639 | return 0; | ||
3640 | } | ||
3641 | |||
3642 | #else | ||
3643 | #define ucc_geth_suspend NULL | ||
3644 | #define ucc_geth_resume NULL | ||
3645 | #endif | ||
3646 | |||
3564 | static phy_interface_t to_phy_interface(const char *phy_connection_type) | 3647 | static phy_interface_t to_phy_interface(const char *phy_connection_type) |
3565 | { | 3648 | { |
3566 | if (strcasecmp(phy_connection_type, "mii") == 0) | 3649 | if (strcasecmp(phy_connection_type, "mii") == 0) |
@@ -3852,6 +3935,8 @@ static struct of_platform_driver ucc_geth_driver = { | |||
3852 | .match_table = ucc_geth_match, | 3935 | .match_table = ucc_geth_match, |
3853 | .probe = ucc_geth_probe, | 3936 | .probe = ucc_geth_probe, |
3854 | .remove = ucc_geth_remove, | 3937 | .remove = ucc_geth_remove, |
3938 | .suspend = ucc_geth_suspend, | ||
3939 | .resume = ucc_geth_resume, | ||
3855 | }; | 3940 | }; |
3856 | 3941 | ||
3857 | static int __init ucc_geth_init(void) | 3942 | static int __init ucc_geth_init(void) |
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index cfb31afc08a9..03a6ca016d5a 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h | |||
@@ -1222,6 +1222,7 @@ struct ucc_geth_private { | |||
1222 | int oldspeed; | 1222 | int oldspeed; |
1223 | int oldduplex; | 1223 | int oldduplex; |
1224 | int oldlink; | 1224 | int oldlink; |
1225 | int wol_en; | ||
1225 | 1226 | ||
1226 | struct device_node *node; | 1227 | struct device_node *node; |
1227 | }; | 1228 | }; |
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 304128fa6058..7075f26e97da 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c | |||
@@ -359,6 +359,44 @@ uec_get_drvinfo(struct net_device *netdev, | |||
359 | drvinfo->regdump_len = uec_get_regs_len(netdev); | 359 | drvinfo->regdump_len = uec_get_regs_len(netdev); |
360 | } | 360 | } |
361 | 361 | ||
362 | #ifdef CONFIG_PM | ||
363 | |||
364 | static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) | ||
365 | { | ||
366 | struct ucc_geth_private *ugeth = netdev_priv(netdev); | ||
367 | struct phy_device *phydev = ugeth->phydev; | ||
368 | |||
369 | if (phydev && phydev->irq) | ||
370 | wol->supported |= WAKE_PHY; | ||
371 | if (qe_alive_during_sleep()) | ||
372 | wol->supported |= WAKE_MAGIC; | ||
373 | |||
374 | wol->wolopts = ugeth->wol_en; | ||
375 | } | ||
376 | |||
377 | static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) | ||
378 | { | ||
379 | struct ucc_geth_private *ugeth = netdev_priv(netdev); | ||
380 | struct phy_device *phydev = ugeth->phydev; | ||
381 | |||
382 | if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC)) | ||
383 | return -EINVAL; | ||
384 | else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq)) | ||
385 | return -EINVAL; | ||
386 | else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep()) | ||
387 | return -EINVAL; | ||
388 | |||
389 | ugeth->wol_en = wol->wolopts; | ||
390 | device_set_wakeup_enable(&netdev->dev, ugeth->wol_en); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | #else | ||
396 | #define uec_get_wol NULL | ||
397 | #define uec_set_wol NULL | ||
398 | #endif /* CONFIG_PM */ | ||
399 | |||
362 | static const struct ethtool_ops uec_ethtool_ops = { | 400 | static const struct ethtool_ops uec_ethtool_ops = { |
363 | .get_settings = uec_get_settings, | 401 | .get_settings = uec_get_settings, |
364 | .set_settings = uec_set_settings, | 402 | .set_settings = uec_set_settings, |
@@ -377,6 +415,8 @@ static const struct ethtool_ops uec_ethtool_ops = { | |||
377 | .get_sset_count = uec_get_sset_count, | 415 | .get_sset_count = uec_get_sset_count, |
378 | .get_strings = uec_get_strings, | 416 | .get_strings = uec_get_strings, |
379 | .get_ethtool_stats = uec_get_ethtool_stats, | 417 | .get_ethtool_stats = uec_get_ethtool_stats, |
418 | .get_wol = uec_get_wol, | ||
419 | .set_wol = uec_set_wol, | ||
380 | }; | 420 | }; |
381 | 421 | ||
382 | void uec_set_ethtool_ops(struct net_device *netdev) | 422 | void uec_set_ethtool_ops(struct net_device *netdev) |