aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFugang Duan <b38611@freescale.com>2014-05-13 02:22:14 -0400
committerFugang Duan <b38611@freescale.com>2014-05-15 03:55:06 -0400
commit349166536e7aa124f8d559044147f2550a5cb87a (patch)
treed9ec2fdc00ea3f10ce32b84ab04511fd83af58f7
parent4bcf608a8a5b74f595faab5b6cb4f4e84e711471 (diff)
ENGR00313508-02 net: fec: add sleep mode support
When imx6sx is in stop mode, enet sleep mode is entered, the magic pattern can wake up imx6sx system. Use ethtool to enable/disable wol magic pattern wake up. Signed-off-by: Fugang Duan <B38611@freescale.com>
-rw-r--r--drivers/net/ethernet/freescale/fec.h2
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c109
2 files changed, 102 insertions, 9 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 7190f171d02e..878d64efc178 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -307,6 +307,7 @@ struct bufdesc_ex {
307#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ 307#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
308#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ 308#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
309#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ 309#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
310#define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */
310#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2) 311#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
311#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2) 312#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
312#define FEC_ENET_TS_AVAIL ((uint)0x00010000) 313#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
@@ -591,6 +592,7 @@ struct fec_enet_private {
591 u64 prtc; 592 u64 prtc;
592 int bufdesc_ex; 593 int bufdesc_ex;
593 int pause_flag; 594 int pause_flag;
595 int wol_flag;
594 596
595 struct napi_struct napi; 597 struct napi_struct napi;
596 int csum_flags; 598 int csum_flags;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 3447f7c2248d..165310209fe6 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -196,6 +196,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
196#define FEC_MMFR_RA(v) ((v & 0x1f) << 18) 196#define FEC_MMFR_RA(v) ((v & 0x1f) << 18)
197#define FEC_MMFR_TA (2 << 16) 197#define FEC_MMFR_TA (2 << 16)
198#define FEC_MMFR_DATA(v) (v & 0xffff) 198#define FEC_MMFR_DATA(v) (v & 0xffff)
199/* FEC ECR bits definition */
200#define FEC_ECR_MAGICEN (1 << 2)
201#define FEC_ECR_SLEEP (1 << 3)
199 202
200#define FEC_MII_TIMEOUT 30000 /* us */ 203#define FEC_MII_TIMEOUT 30000 /* us */
201 204
@@ -204,6 +207,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
204 207
205#define FEC_PAUSE_FLAG_AUTONEG 0x1 208#define FEC_PAUSE_FLAG_AUTONEG 0x1
206#define FEC_PAUSE_FLAG_ENABLE 0x2 209#define FEC_PAUSE_FLAG_ENABLE 0x2
210#define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0)
211#define FEC_WOL_FLAG_ENABLE (0x1 << 1)
212#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2)
207 213
208static int mii_cnt; 214static int mii_cnt;
209 215
@@ -765,9 +771,11 @@ static void
765fec_stop(struct net_device *ndev) 771fec_stop(struct net_device *ndev)
766{ 772{
767 struct fec_enet_private *fep = netdev_priv(ndev); 773 struct fec_enet_private *fep = netdev_priv(ndev);
774 struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
768 const struct platform_device_id *id_entry = 775 const struct platform_device_id *id_entry =
769 platform_get_device_id(fep->pdev); 776 platform_get_device_id(fep->pdev);
770 u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); 777 u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
778 u32 val;
771 779
772 /* We cannot expect a graceful transmit stop without link !!! */ 780 /* We cannot expect a graceful transmit stop without link !!! */
773 if (fep->link) { 781 if (fep->link) {
@@ -782,14 +790,27 @@ fec_stop(struct net_device *ndev)
782 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC 790 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
783 * instead of reset MAC itself. 791 * instead of reset MAC itself.
784 */ 792 */
785 if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) 793 if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
786 writel(0, fep->hwp + FEC_ECNTRL); 794 if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB)
787 else { 795 writel(0, fep->hwp + FEC_ECNTRL);
788 writel(1, fep->hwp + FEC_ECNTRL); 796 else {
789 udelay(10); 797 writel(1, fep->hwp + FEC_ECNTRL);
798 udelay(10);
799 }
800
801 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
802 } else {
803 writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP,
804 fep->hwp + FEC_IMASK);
805 val = readl(fep->hwp + FEC_ECNTRL);
806 val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
807 writel(val, fep->hwp + FEC_ECNTRL);
808
809 if (pdata && pdata->sleep_mode_enable)
810 pdata->sleep_mode_enable(true);
790 } 811 }
812
791 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 813 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
792 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
793 814
794 if (fep->bufdesc_ex && (fep->hwts_tx_en_ioctl || 815 if (fep->bufdesc_ex && (fep->hwts_tx_en_ioctl ||
795 fep->hwts_rx_en_ioctl || fep->hwts_tx_en || 816 fep->hwts_rx_en_ioctl || fep->hwts_tx_en ||
@@ -797,7 +818,8 @@ fec_stop(struct net_device *ndev)
797 fec_ptp_stop(ndev); 818 fec_ptp_stop(ndev);
798 819
799 /* We have to keep ENET enabled to have MII interrupt stay working */ 820 /* We have to keep ENET enabled to have MII interrupt stay working */
800 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 821 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC &&
822 !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
801 writel(2, fep->hwp + FEC_ECNTRL); 823 writel(2, fep->hwp + FEC_ECNTRL);
802 writel(rmii_mode, fep->hwp + FEC_R_CNTRL); 824 writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
803 } 825 }
@@ -1974,6 +1996,47 @@ static void fec_enet_itr_coal_init(struct net_device *ndev)
1974 fec_enet_set_coalesce(ndev, &ec); 1996 fec_enet_set_coalesce(ndev, &ec);
1975} 1997}
1976 1998
1999#ifdef CONFIG_PM
2000static void
2001fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
2002{
2003 struct fec_enet_private *fep = netdev_priv(ndev);
2004
2005 if (fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET) {
2006 wol->supported = WAKE_MAGIC;
2007 wol->wolopts = fep->wol_flag & FEC_WOL_FLAG_ENABLE ? WAKE_MAGIC : 0;
2008 } else {
2009 wol->supported = wol->wolopts = 0;
2010 }
2011}
2012
2013static int
2014fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
2015{
2016 struct fec_enet_private *fep = netdev_priv(ndev);
2017
2018 if (!(fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET) &&
2019 wol->wolopts != 0)
2020 return -EINVAL;
2021
2022 if (wol->wolopts & ~WAKE_MAGIC)
2023 return -EINVAL;
2024
2025 device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
2026 if (device_may_wakeup(&ndev->dev)) {
2027 fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
2028 if (fep->irq[0] > 0)
2029 enable_irq_wake(fep->irq[0]);
2030 } else {
2031 fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
2032 if (fep->irq[0] > 0)
2033 disable_irq_wake(fep->irq[0]);
2034 }
2035
2036 return 0;
2037}
2038#endif
2039
1977static const struct ethtool_ops fec_enet_ethtool_ops = { 2040static const struct ethtool_ops fec_enet_ethtool_ops = {
1978#if !defined(CONFIG_M5272) 2041#if !defined(CONFIG_M5272)
1979 .get_pauseparam = fec_enet_get_pauseparam, 2042 .get_pauseparam = fec_enet_get_pauseparam,
@@ -1992,6 +2055,10 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
1992 .get_strings = fec_enet_get_strings, 2055 .get_strings = fec_enet_get_strings,
1993 .get_sset_count = fec_enet_get_sset_count, 2056 .get_sset_count = fec_enet_get_sset_count,
1994#endif 2057#endif
2058#ifdef CONFIG_PM
2059 .get_wol = fec_enet_get_wol,
2060 .set_wol = fec_enet_set_wol,
2061#endif
1995}; 2062};
1996 2063
1997static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) 2064static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -2171,6 +2238,9 @@ fec_enet_open(struct net_device *ndev)
2171 PM_QOS_CPU_DMA_LATENCY, 2238 PM_QOS_CPU_DMA_LATENCY,
2172 PM_QOS_DEFAULT_VALUE); 2239 PM_QOS_DEFAULT_VALUE);
2173 2240
2241 device_set_wakeup_enable(&ndev->dev,
2242 fep->wol_flag & FEC_WOL_FLAG_ENABLE);
2243
2174 return 0; 2244 return 0;
2175} 2245}
2176 2246
@@ -2539,6 +2609,9 @@ static void fec_of_init(struct platform_device *pdev)
2539 if (!np) 2609 if (!np)
2540 return; 2610 return;
2541 2611
2612 if (of_get_property(np, "fsl,magic-packet", NULL))
2613 fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
2614
2542 of_property_read_u32(np, "phy-reset-duration", 2615 of_property_read_u32(np, "phy-reset-duration",
2543 &fep->reset_duration); 2616 &fep->reset_duration);
2544 /* A sane reset duration should not be longer than 1s */ 2617 /* A sane reset duration should not be longer than 1s */
@@ -2751,6 +2824,7 @@ fec_probe(struct platform_device *pdev)
2751 } 2824 }
2752 goto failed_irq; 2825 goto failed_irq;
2753 } 2826 }
2827 fep->irq[i] = irq;
2754 } 2828 }
2755 2829
2756 init_completion(&fep->mdio_done); 2830 init_completion(&fep->mdio_done);
@@ -2760,6 +2834,9 @@ fec_probe(struct platform_device *pdev)
2760 2834
2761 /* Carrier starts down, phylib will bring it up */ 2835 /* Carrier starts down, phylib will bring it up */
2762 netif_carrier_off(ndev); 2836 netif_carrier_off(ndev);
2837 device_init_wakeup(&ndev->dev,
2838 fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET);
2839
2763 fec_enet_clk_enable(ndev, false); 2840 fec_enet_clk_enable(ndev, false);
2764 2841
2765 /* Select sleep pin state */ 2842 /* Select sleep pin state */
@@ -2835,9 +2912,12 @@ fec_suspend(struct device *dev)
2835 struct fec_enet_private *fep = netdev_priv(ndev); 2912 struct fec_enet_private *fep = netdev_priv(ndev);
2836 2913
2837 if (netif_running(ndev)) { 2914 if (netif_running(ndev)) {
2915 if (fep->wol_flag & FEC_WOL_FLAG_ENABLE)
2916 fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON;
2838 fec_stop(ndev); 2917 fec_stop(ndev);
2839 netif_device_detach(ndev); 2918 netif_device_detach(ndev);
2840 fec_enet_clk_enable(ndev, false); 2919 if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
2920 fec_enet_clk_enable(ndev, false);
2841 pinctrl_pm_select_sleep_state(&fep->pdev->dev); 2921 pinctrl_pm_select_sleep_state(&fep->pdev->dev);
2842 } 2922 }
2843 2923
@@ -2859,7 +2939,9 @@ fec_resume(struct device *dev)
2859{ 2939{
2860 struct net_device *ndev = dev_get_drvdata(dev); 2940 struct net_device *ndev = dev_get_drvdata(dev);
2861 struct fec_enet_private *fep = netdev_priv(ndev); 2941 struct fec_enet_private *fep = netdev_priv(ndev);
2942 struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
2862 int ret; 2943 int ret;
2944 int val;
2863 2945
2864 if (fep->reg_phy) { 2946 if (fep->reg_phy) {
2865 ret = regulator_enable(fep->reg_phy); 2947 ret = regulator_enable(fep->reg_phy);
@@ -2869,7 +2951,16 @@ fec_resume(struct device *dev)
2869 2951
2870 if (netif_running(ndev)) { 2952 if (netif_running(ndev)) {
2871 pinctrl_pm_select_default_state(&fep->pdev->dev); 2953 pinctrl_pm_select_default_state(&fep->pdev->dev);
2872 fec_enet_clk_enable(ndev, true); 2954 if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
2955 if (pdata && pdata->sleep_mode_enable)
2956 pdata->sleep_mode_enable(false);
2957 val = readl(fep->hwp + FEC_ECNTRL);
2958 val &= (~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP));
2959 writel(val, fep->hwp + FEC_ECNTRL);
2960 fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON;
2961 } else {
2962 fec_enet_clk_enable(ndev, true);
2963 }
2873 if (!fep->clk_enet_out && !fep->reg_phy) 2964 if (!fep->clk_enet_out && !fep->reg_phy)
2874 fec_restart(ndev, fep->full_duplex); 2965 fec_restart(ndev, fep->full_duplex);
2875 netif_device_attach(ndev); 2966 netif_device_attach(ndev);