diff options
author | David S. Miller <davem@davemloft.net> | 2014-07-21 16:04:37 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-21 16:04:37 -0700 |
commit | bb1fed7110c287024dce6bee8152aad903104d96 (patch) | |
tree | 8062476c2325870473869bb27217f7f22093bc51 | |
parent | 575a19354c80fde236382755592256d30d2a27fb (diff) | |
parent | 06ba8375ec42daae19124eaa106295dbe159731f (diff) | |
download | op-kernel-dev-bb1fed7110c287024dce6bee8152aad903104d96.zip op-kernel-dev-bb1fed7110c287024dce6bee8152aad903104d96.tar.gz |
Merge branch 'bcmgenet-next'
Florian Fainelli says:
====================
net: bcmgenet: PM and Wake-on-LAN
This patchset brings S2/S3 Power Management support to the GENET driver
as well as Wake-on-LAN using Magic Packets with or without SecureOn
passwords.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 270 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 206 |
4 files changed, 430 insertions, 60 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile index 31f55a9..9b6885e 100644 --- a/drivers/net/ethernet/broadcom/genet/Makefile +++ b/drivers/net/ethernet/broadcom/genet/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_BCMGENET) += genet.o -genet-objs := bcmgenet.o bcmmii.o +genet-objs := bcmgenet.o bcmmii.o bcmgenet_wol.o diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 16281ad..0173a6d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -730,6 +730,8 @@ static struct ethtool_ops bcmgenet_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = bcmgenet_get_msglevel, .set_msglevel = bcmgenet_set_msglevel, + .get_wol = bcmgenet_get_wol, + .set_wol = bcmgenet_set_wol, }; /* Power down the unimac, based on mode. */ @@ -743,6 +745,10 @@ static void bcmgenet_power_down(struct bcmgenet_priv *priv, phy_detach(priv->phydev); break; + case GENET_POWER_WOL_MAGIC: + bcmgenet_wol_power_down_cfg(priv, mode); + break; + case GENET_POWER_PASSIVE: /* Power down LED */ bcmgenet_mii_reset(priv->dev); @@ -777,6 +783,9 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, /* enable APD */ reg |= EXT_PWR_DN_EN_LD; break; + case GENET_POWER_WOL_MAGIC: + bcmgenet_wol_power_up_cfg(priv, mode); + return; default: break; } @@ -1437,6 +1446,25 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) } } +static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, + bool enable) +{ + u32 reg; + + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + if (enable) + reg |= mask; + else + reg &= ~mask; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + /* UniMAC stops on a packet boundary, wait for a full-size packet + * to be processed + */ + if (enable == 0) + usleep_range(1000, 2000); +} + static int reset_umac(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; @@ -1469,6 +1497,17 @@ static int reset_umac(struct bcmgenet_priv *priv) return 0; } +static void bcmgenet_intr_disable(struct bcmgenet_priv *priv) +{ + /* Mask all interrupts.*/ + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); + bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); + bcmgenet_intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); +} + static int init_umac(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; @@ -1497,10 +1536,7 @@ static int init_umac(struct bcmgenet_priv *priv) if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); - /* Mask all interrupts.*/ - bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); - bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); - bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intr_disable(priv); cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE; @@ -1802,6 +1838,13 @@ static void bcmgenet_irq_task(struct work_struct *work) netif_dbg(priv, intr, priv->dev, "%s\n", __func__); + if (priv->irq0_stat & UMAC_IRQ_MPD_R) { + priv->irq0_stat &= ~UMAC_IRQ_MPD_R; + netif_dbg(priv, wol, priv->dev, + "magic packet detected, waking up\n"); + bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC); + } + /* Link UP/DOWN event */ if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) { @@ -1891,6 +1934,15 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) +{ + struct bcmgenet_priv *priv = dev_id; + + pm_wakeup_event(&priv->pdev->dev, 0); + + return IRQ_HANDLED; +} + static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) { u32 reg; @@ -1915,14 +1967,8 @@ static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, static int bcmgenet_wol_resume(struct bcmgenet_priv *priv) { - int ret; - /* From WOL-enabled suspend, switch to regular clock */ - clk_disable(priv->clk_wol); - /* init umac registers to synchronize s/w with h/w */ - ret = init_umac(priv); - if (ret) - return ret; + clk_disable_unprepare(priv->clk_wol); phy_init_hw(priv->phydev); /* Speed settings must be restored */ @@ -1967,6 +2013,23 @@ static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl) bcmgenet_tdma_writel(priv, reg, DMA_CTRL); } +static void bcmgenet_netif_start(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + /* Start the network engine */ + napi_enable(&priv->napi); + + umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); + + if (phy_is_internal(priv->phydev)) + bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + + netif_tx_start_all_queues(dev); + + phy_start(priv->phydev); +} + static int bcmgenet_open(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -1988,18 +2051,14 @@ static int bcmgenet_open(struct net_device *dev) goto err_clk_disable; /* disable ethernet MAC while updating its registers */ + umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); + + /* Make sure we reflect the value of CRC_CMD_FWD */ reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg &= ~(CMD_TX_EN | CMD_RX_EN); - bcmgenet_umac_writel(priv, reg, UMAC_CMD); + priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); bcmgenet_set_hw_addr(priv, dev->dev_addr); - if (priv->wol_enabled) { - ret = bcmgenet_wol_resume(priv); - if (ret) - return ret; - } - if (phy_is_internal(priv->phydev)) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_ENERGY_DET_MASK; @@ -2033,24 +2092,7 @@ static int bcmgenet_open(struct net_device *dev) goto err_irq0; } - /* Start the network engine */ - napi_enable(&priv->napi); - - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg |= (CMD_TX_EN | CMD_RX_EN); - bcmgenet_umac_writel(priv, reg, UMAC_CMD); - - /* Make sure we reflect the value of CRC_CMD_FWD */ - priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); - - device_set_wakeup_capable(&dev->dev, 1); - - if (phy_is_internal(priv->phydev)) - bcmgenet_power_up(priv, GENET_POWER_PASSIVE); - - netif_tx_start_all_queues(dev); - - phy_start(priv->phydev); + bcmgenet_netif_start(dev); return 0; @@ -2117,33 +2159,40 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) return ret; } +static void bcmgenet_netif_stop(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + netif_tx_stop_all_queues(dev); + napi_disable(&priv->napi); + phy_stop(priv->phydev); + + bcmgenet_intr_disable(priv); + + /* Wait for pending work items to complete. Since interrupts are + * disabled no new work will be scheduled. + */ + cancel_work_sync(&priv->bcmgenet_irq_work); +} + static int bcmgenet_close(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); int ret; - u32 reg; netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); - phy_stop(priv->phydev); + bcmgenet_netif_stop(dev); /* Disable MAC receive */ - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg &= ~CMD_RX_EN; - bcmgenet_umac_writel(priv, reg, UMAC_CMD); - - netif_tx_stop_all_queues(dev); + umac_enable_set(priv, CMD_RX_EN, false); ret = bcmgenet_dma_teardown(priv); if (ret) return ret; /* Disable MAC transmit. TX DMA disabled have to done before this */ - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg &= ~CMD_TX_EN; - bcmgenet_umac_writel(priv, reg, UMAC_CMD); - - napi_disable(&priv->napi); + umac_enable_set(priv, CMD_TX_EN, false); /* tx reclaim */ bcmgenet_tx_reclaim_all(dev); @@ -2152,18 +2201,9 @@ static int bcmgenet_close(struct net_device *dev) free_irq(priv->irq0, priv); free_irq(priv->irq1, priv); - /* Wait for pending work items to complete - we are stopping - * the clock now. Since interrupts are disabled, no new work - * will be scheduled. - */ - cancel_work_sync(&priv->bcmgenet_irq_work); - if (phy_is_internal(priv->phydev)) bcmgenet_power_down(priv, GENET_POWER_PASSIVE); - if (priv->wol_enabled) - clk_enable(priv->clk_wol); - if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); @@ -2450,6 +2490,7 @@ static int bcmgenet_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->irq0 = platform_get_irq(pdev, 0); priv->irq1 = platform_get_irq(pdev, 1); + priv->wol_irq = platform_get_irq(pdev, 2); if (!priv->irq0 || !priv->irq1) { dev_err(&pdev->dev, "can't find IRQs\n"); err = -EINVAL; @@ -2484,6 +2525,13 @@ static int bcmgenet_probe(struct platform_device *pdev) dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + /* Request the WOL interrupt and advertise suspend if available */ + priv->wol_irq_disabled = true; + err = devm_request_irq(&pdev->dev, priv->wol_irq, bcmgenet_wol_isr, 0, + dev->name, priv); + if (!err) + device_set_wakeup_capable(&pdev->dev, 1); + /* Set the needed headroom to account for any possible * features enabling/disabling at runtime */ @@ -2561,6 +2609,111 @@ static int bcmgenet_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int bcmgenet_suspend(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcmgenet_priv *priv = netdev_priv(dev); + int ret; + + if (!netif_running(dev)) + return 0; + + bcmgenet_netif_stop(dev); + + netif_device_detach(dev); + + /* Disable MAC receive */ + umac_enable_set(priv, CMD_RX_EN, false); + + ret = bcmgenet_dma_teardown(priv); + if (ret) + return ret; + + /* Disable MAC transmit. TX DMA disabled have to done before this */ + umac_enable_set(priv, CMD_TX_EN, false); + + /* tx reclaim */ + bcmgenet_tx_reclaim_all(dev); + bcmgenet_fini_dma(priv); + + /* Prepare the device for Wake-on-LAN and switch to the slow clock */ + if (device_may_wakeup(d) && priv->wolopts) { + bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); + clk_prepare_enable(priv->clk_wol); + } + + /* Turn off the clocks */ + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int bcmgenet_resume(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned long dma_ctrl; + int ret; + u32 reg; + + if (!netif_running(dev)) + return 0; + + /* Turn on the clock */ + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + bcmgenet_umac_reset(priv); + + ret = init_umac(priv); + if (ret) + goto out_clk_disable; + + if (priv->wolopts) + ret = bcmgenet_wol_resume(priv); + + if (ret) + goto out_clk_disable; + + /* disable ethernet MAC while updating its registers */ + umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); + + bcmgenet_set_hw_addr(priv, dev->dev_addr); + + if (phy_is_internal(priv->phydev)) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + reg |= EXT_ENERGY_DET_MASK; + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + } + + /* Disable RX/TX DMA and flush TX queues */ + dma_ctrl = bcmgenet_dma_disable(priv); + + /* Reinitialize TDMA and RDMA and SW housekeeping */ + ret = bcmgenet_init_dma(priv); + if (ret) { + netdev_err(dev, "failed to initialize DMA\n"); + goto out_clk_disable; + } + + /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + + netif_device_attach(dev); + + bcmgenet_netif_start(dev); + + return 0; + +out_clk_disable: + clk_disable_unprepare(priv->clk); + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); static struct platform_driver bcmgenet_driver = { .probe = bcmgenet_probe, @@ -2569,6 +2722,7 @@ static struct platform_driver bcmgenet_driver = { .name = "bcmgenet", .owner = THIS_MODULE, .of_match_table = bcmgenet_match, + .pm = &bcmgenet_pm_ops, }, }; module_platform_driver(bcmgenet_driver); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index e23c993..c61cd98 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -456,6 +456,7 @@ struct enet_cb { enum bcmgenet_power_mode { GENET_POWER_CABLE_SENSE = 0, GENET_POWER_PASSIVE, + GENET_POWER_WOL_MAGIC, }; struct bcmgenet_priv; @@ -569,6 +570,8 @@ struct bcmgenet_priv { int irq1; unsigned int irq0_stat; unsigned int irq1_stat; + int wol_irq; + bool wol_irq_disabled; /* HW descriptors/checksum variables */ bool desc_64b_en; @@ -583,7 +586,6 @@ struct bcmgenet_priv { struct platform_device *pdev; /* WOL */ - unsigned long wol_enabled; struct clk *clk_wol; u32 wolopts; @@ -625,4 +627,12 @@ int bcmgenet_mii_config(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_mii_reset(struct net_device *dev); +/* Wake-on-LAN routines */ +void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol); +int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol); +int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode); +void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode); + #endif /* __BCMGENET_H__ */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c new file mode 100644 index 0000000..b82b7e4 --- /dev/null +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -0,0 +1,206 @@ +/* + * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support + * + * Copyright (c) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "bcmgenet_wol: " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/clk.h> +#include <linux/version.h> +#include <linux/platform_device.h> +#include <net/arp.h> + +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/netdevice.h> +#include <linux/inetdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/phy.h> + +#include "bcmgenet.h" + +/* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet + * Detection is supported through ethtool + */ +void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + u32 reg; + + wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE; + wol->wolopts = priv->wolopts; + memset(wol->sopass, 0, sizeof(wol->sopass)); + + if (wol->wolopts & WAKE_MAGICSECURE) { + reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS); + put_unaligned_be16(reg, &wol->sopass[0]); + reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS); + put_unaligned_be32(reg, &wol->sopass[2]); + } +} + +/* ethtool function - set WOL (Wake on LAN) settings. + * Only for magic packet detection mode. + */ +int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + u32 reg; + + if (!device_can_wakeup(kdev)) + return -ENOTSUPP; + + if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE)) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGICSECURE) { + bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]), + UMAC_MPD_PW_MS); + bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]), + UMAC_MPD_PW_LS); + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg |= MPD_PW_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + } + + /* Flag the device and relevant IRQ as wakeup capable */ + if (wol->wolopts) { + device_set_wakeup_enable(kdev, 1); + enable_irq_wake(priv->wol_irq); + priv->wol_irq_disabled = false; + } else { + device_set_wakeup_enable(kdev, 0); + /* Avoid unbalanced disable_irq_wake calls */ + if (!priv->wol_irq_disabled) + disable_irq_wake(priv->wol_irq); + priv->wol_irq_disabled = true; + } + + priv->wolopts = wol->wolopts; + + return 0; +} + +static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv) +{ + struct net_device *dev = priv->dev; + int retries = 0; + + while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS) + & RBUF_STATUS_WOL)) { + retries++; + if (retries > 5) { + netdev_crit(dev, "polling wol mode timeout\n"); + return -ETIMEDOUT; + } + mdelay(1); + } + + return retries; +} + +int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode) +{ + struct net_device *dev = priv->dev; + u32 cpu_mask_clear; + int retries = 0; + u32 reg; + + if (mode != GENET_POWER_WOL_MAGIC) { + netif_err(priv, wol, dev, "unsupported mode: %d\n", mode); + return -EINVAL; + } + + /* disable RX */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~CMD_RX_EN; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + mdelay(10); + + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg |= MPD_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + + /* Do not leave UniMAC in MPD mode only */ + retries = bcmgenet_poll_wol_status(priv); + if (retries < 0) { + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg &= ~MPD_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + return retries; + } + + netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n", + retries); + + /* Enable CRC forward */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + priv->crc_fwd_en = 1; + reg |= CMD_CRC_FWD; + + /* Receiver must be enabled for WOL MP detection */ + reg |= CMD_RX_EN; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + if (priv->hw_params->flags & GENET_HAS_EXT) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + reg &= ~EXT_ENERGY_DET_MASK; + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + } + + /* Enable the MPD interrupt */ + cpu_mask_clear = UMAC_IRQ_MPD_R; + + bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR); + + return 0; +} + +void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode) +{ + u32 cpu_mask_set; + u32 reg; + + if (mode != GENET_POWER_WOL_MAGIC) { + netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode); + return; + } + + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg &= ~MPD_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + + /* Disable CRC Forward */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~CMD_CRC_FWD; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + priv->crc_fwd_en = 0; + + /* Stop monitoring magic packet IRQ */ + cpu_mask_set = UMAC_IRQ_MPD_R; + + /* Stop monitoring magic packet IRQ */ + bcmgenet_intrl2_0_writel(priv, cpu_mask_set, INTRL2_CPU_MASK_SET); +} |