diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2014-07-21 18:29:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-21 19:04:30 -0400 |
commit | b6e978e50444a063f066f058d134173de877b968 (patch) | |
tree | dbf1782c10978273644fdcdae276ea90789e511c | |
parent | 909ff5efbab85f2724c5f91ec200ebc9df50c440 (diff) |
net: bcmgenet: add suspend/resume callbacks
Implement suspend/resume callbacks in the GENET driver. This makes sure
that we de-initialize and re-initialize the hardware correctly before
entering suspend and when resuming.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 5cab188ee323..bbd8bf326a35 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c | |||
@@ -2584,6 +2584,100 @@ static int bcmgenet_remove(struct platform_device *pdev) | |||
2584 | return 0; | 2584 | return 0; |
2585 | } | 2585 | } |
2586 | 2586 | ||
2587 | #ifdef CONFIG_PM_SLEEP | ||
2588 | static int bcmgenet_suspend(struct device *d) | ||
2589 | { | ||
2590 | struct net_device *dev = dev_get_drvdata(d); | ||
2591 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
2592 | int ret; | ||
2593 | |||
2594 | if (!netif_running(dev)) | ||
2595 | return 0; | ||
2596 | |||
2597 | bcmgenet_netif_stop(dev); | ||
2598 | |||
2599 | netif_device_detach(dev); | ||
2600 | |||
2601 | /* Disable MAC receive */ | ||
2602 | umac_enable_set(priv, CMD_RX_EN, false); | ||
2603 | |||
2604 | ret = bcmgenet_dma_teardown(priv); | ||
2605 | if (ret) | ||
2606 | return ret; | ||
2607 | |||
2608 | /* Disable MAC transmit. TX DMA disabled have to done before this */ | ||
2609 | umac_enable_set(priv, CMD_TX_EN, false); | ||
2610 | |||
2611 | /* tx reclaim */ | ||
2612 | bcmgenet_tx_reclaim_all(dev); | ||
2613 | bcmgenet_fini_dma(priv); | ||
2614 | |||
2615 | /* Turn off the clocks */ | ||
2616 | clk_disable_unprepare(priv->clk); | ||
2617 | |||
2618 | return 0; | ||
2619 | } | ||
2620 | |||
2621 | static int bcmgenet_resume(struct device *d) | ||
2622 | { | ||
2623 | struct net_device *dev = dev_get_drvdata(d); | ||
2624 | struct bcmgenet_priv *priv = netdev_priv(dev); | ||
2625 | unsigned long dma_ctrl; | ||
2626 | int ret; | ||
2627 | u32 reg; | ||
2628 | |||
2629 | if (!netif_running(dev)) | ||
2630 | return 0; | ||
2631 | |||
2632 | /* Turn on the clock */ | ||
2633 | ret = clk_prepare_enable(priv->clk); | ||
2634 | if (ret) | ||
2635 | return ret; | ||
2636 | |||
2637 | bcmgenet_umac_reset(priv); | ||
2638 | |||
2639 | ret = init_umac(priv); | ||
2640 | if (ret) | ||
2641 | goto out_clk_disable; | ||
2642 | |||
2643 | /* disable ethernet MAC while updating its registers */ | ||
2644 | umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); | ||
2645 | |||
2646 | bcmgenet_set_hw_addr(priv, dev->dev_addr); | ||
2647 | |||
2648 | if (phy_is_internal(priv->phydev)) { | ||
2649 | reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); | ||
2650 | reg |= EXT_ENERGY_DET_MASK; | ||
2651 | bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); | ||
2652 | } | ||
2653 | |||
2654 | /* Disable RX/TX DMA and flush TX queues */ | ||
2655 | dma_ctrl = bcmgenet_dma_disable(priv); | ||
2656 | |||
2657 | /* Reinitialize TDMA and RDMA and SW housekeeping */ | ||
2658 | ret = bcmgenet_init_dma(priv); | ||
2659 | if (ret) { | ||
2660 | netdev_err(dev, "failed to initialize DMA\n"); | ||
2661 | goto out_clk_disable; | ||
2662 | } | ||
2663 | |||
2664 | /* Always enable ring 16 - descriptor ring */ | ||
2665 | bcmgenet_enable_dma(priv, dma_ctrl); | ||
2666 | |||
2667 | netif_device_attach(dev); | ||
2668 | |||
2669 | bcmgenet_netif_start(dev); | ||
2670 | |||
2671 | return 0; | ||
2672 | |||
2673 | out_clk_disable: | ||
2674 | clk_disable_unprepare(priv->clk); | ||
2675 | return ret; | ||
2676 | } | ||
2677 | #endif /* CONFIG_PM_SLEEP */ | ||
2678 | |||
2679 | static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); | ||
2680 | |||
2587 | static struct platform_driver bcmgenet_driver = { | 2681 | static struct platform_driver bcmgenet_driver = { |
2588 | .probe = bcmgenet_probe, | 2682 | .probe = bcmgenet_probe, |
2589 | .remove = bcmgenet_remove, | 2683 | .remove = bcmgenet_remove, |
@@ -2591,6 +2685,7 @@ static struct platform_driver bcmgenet_driver = { | |||
2591 | .name = "bcmgenet", | 2685 | .name = "bcmgenet", |
2592 | .owner = THIS_MODULE, | 2686 | .owner = THIS_MODULE, |
2593 | .of_match_table = bcmgenet_match, | 2687 | .of_match_table = bcmgenet_match, |
2688 | .pm = &bcmgenet_pm_ops, | ||
2594 | }, | 2689 | }, |
2595 | }; | 2690 | }; |
2596 | module_platform_driver(bcmgenet_driver); | 2691 | module_platform_driver(bcmgenet_driver); |