0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "bcmgenet_wol: " fmt
0009
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/sched.h>
0013 #include <linux/types.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/string.h>
0016 #include <linux/init.h>
0017 #include <linux/errno.h>
0018 #include <linux/delay.h>
0019 #include <linux/pm.h>
0020 #include <linux/clk.h>
0021 #include <linux/platform_device.h>
0022 #include <net/arp.h>
0023
0024 #include <linux/mii.h>
0025 #include <linux/ethtool.h>
0026 #include <linux/netdevice.h>
0027 #include <linux/inetdevice.h>
0028 #include <linux/etherdevice.h>
0029 #include <linux/skbuff.h>
0030 #include <linux/in.h>
0031 #include <linux/ip.h>
0032 #include <linux/ipv6.h>
0033 #include <linux/phy.h>
0034
0035 #include "bcmgenet.h"
0036
0037
0038
0039
0040 void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
0041 {
0042 struct bcmgenet_priv *priv = netdev_priv(dev);
0043 struct device *kdev = &priv->pdev->dev;
0044
0045 if (!device_can_wakeup(kdev)) {
0046 wol->supported = 0;
0047 wol->wolopts = 0;
0048 return;
0049 }
0050
0051 wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER;
0052 wol->wolopts = priv->wolopts;
0053 memset(wol->sopass, 0, sizeof(wol->sopass));
0054
0055 if (wol->wolopts & WAKE_MAGICSECURE)
0056 memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
0057 }
0058
0059
0060
0061
0062 int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
0063 {
0064 struct bcmgenet_priv *priv = netdev_priv(dev);
0065 struct device *kdev = &priv->pdev->dev;
0066
0067 if (!device_can_wakeup(kdev))
0068 return -ENOTSUPP;
0069
0070 if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER))
0071 return -EINVAL;
0072
0073 if (wol->wolopts & WAKE_MAGICSECURE)
0074 memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
0075
0076
0077 if (wol->wolopts) {
0078 device_set_wakeup_enable(kdev, 1);
0079
0080 if (priv->wol_irq_disabled)
0081 enable_irq_wake(priv->wol_irq);
0082 priv->wol_irq_disabled = false;
0083 } else {
0084 device_set_wakeup_enable(kdev, 0);
0085
0086 if (!priv->wol_irq_disabled)
0087 disable_irq_wake(priv->wol_irq);
0088 priv->wol_irq_disabled = true;
0089 }
0090
0091 priv->wolopts = wol->wolopts;
0092
0093 return 0;
0094 }
0095
0096 static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
0097 {
0098 struct net_device *dev = priv->dev;
0099 int retries = 0;
0100
0101 while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
0102 & RBUF_STATUS_WOL)) {
0103 retries++;
0104 if (retries > 5) {
0105 netdev_crit(dev, "polling wol mode timeout\n");
0106 return -ETIMEDOUT;
0107 }
0108 mdelay(1);
0109 }
0110
0111 return retries;
0112 }
0113
0114 static void bcmgenet_set_mpd_password(struct bcmgenet_priv *priv)
0115 {
0116 bcmgenet_umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
0117 UMAC_MPD_PW_MS);
0118 bcmgenet_umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
0119 UMAC_MPD_PW_LS);
0120 }
0121
0122 int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
0123 enum bcmgenet_power_mode mode)
0124 {
0125 struct net_device *dev = priv->dev;
0126 struct bcmgenet_rxnfc_rule *rule;
0127 u32 reg, hfb_ctrl_reg, hfb_enable = 0;
0128 int retries = 0;
0129
0130 if (mode != GENET_POWER_WOL_MAGIC) {
0131 netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
0132 return -EINVAL;
0133 }
0134
0135
0136 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
0137 if (reg & CMD_SW_RESET)
0138 reg &= ~CMD_SW_RESET;
0139
0140
0141 reg &= ~CMD_RX_EN;
0142 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
0143 mdelay(10);
0144
0145 if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
0146 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
0147 reg |= MPD_EN;
0148 if (priv->wolopts & WAKE_MAGICSECURE) {
0149 bcmgenet_set_mpd_password(priv);
0150 reg |= MPD_PW_EN;
0151 }
0152 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
0153 }
0154
0155 hfb_ctrl_reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
0156 if (priv->wolopts & WAKE_FILTER) {
0157 list_for_each_entry(rule, &priv->rxnfc_list, list)
0158 if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE)
0159 hfb_enable |= (1 << rule->fs.location);
0160 reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN;
0161 bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
0162 }
0163
0164
0165 retries = bcmgenet_poll_wol_status(priv);
0166 if (retries < 0) {
0167 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
0168 reg &= ~(MPD_EN | MPD_PW_EN);
0169 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
0170 bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
0171 return retries;
0172 }
0173
0174 netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
0175 retries);
0176
0177 clk_prepare_enable(priv->clk_wol);
0178 priv->wol_active = 1;
0179
0180 if (hfb_enable) {
0181 bcmgenet_hfb_reg_writel(priv, hfb_enable,
0182 HFB_FLT_ENABLE_V3PLUS + 4);
0183 hfb_ctrl_reg = RBUF_HFB_EN | RBUF_ACPI_EN;
0184 bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
0185 }
0186
0187
0188 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
0189 priv->crc_fwd_en = 1;
0190 reg |= CMD_CRC_FWD;
0191
0192
0193 reg |= CMD_RX_EN;
0194 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
0195
0196 reg = UMAC_IRQ_MPD_R;
0197 if (hfb_enable)
0198 reg |= UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM;
0199
0200 bcmgenet_intrl2_0_writel(priv, reg, INTRL2_CPU_MASK_CLEAR);
0201
0202 return 0;
0203 }
0204
0205 void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
0206 enum bcmgenet_power_mode mode)
0207 {
0208 u32 reg;
0209
0210 if (mode != GENET_POWER_WOL_MAGIC) {
0211 netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode);
0212 return;
0213 }
0214
0215 if (!priv->wol_active)
0216 return;
0217
0218 priv->wol_active = 0;
0219 clk_disable_unprepare(priv->clk_wol);
0220 priv->crc_fwd_en = 0;
0221
0222
0223 if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
0224 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
0225 if (!(reg & MPD_EN))
0226 return;
0227 reg &= ~(MPD_EN | MPD_PW_EN);
0228 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
0229 }
0230
0231
0232 if (priv->wolopts & WAKE_FILTER) {
0233 reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
0234 if (!(reg & RBUF_ACPI_EN))
0235 return;
0236 reg &= ~(RBUF_HFB_EN | RBUF_ACPI_EN);
0237 bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
0238 }
0239
0240
0241 reg = bcmgenet_umac_readl(priv, UMAC_CMD);
0242 reg &= ~CMD_CRC_FWD;
0243 bcmgenet_umac_writel(priv, reg, UMAC_CMD);
0244 }