aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ucc_geth.c85
-rw-r--r--drivers/net/ucc_geth.h1
-rw-r--r--drivers/net/ucc_geth_ethtool.c40
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
3502err: 3506err:
@@ -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
3571static 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
3598static 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
3564static phy_interface_t to_phy_interface(const char *phy_connection_type) 3647static 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
3857static int __init ucc_geth_init(void) 3942static 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
364static 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
377static 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
362static const struct ethtool_ops uec_ethtool_ops = { 400static 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
382void uec_set_ethtool_ops(struct net_device *netdev) 422void uec_set_ethtool_ops(struct net_device *netdev)