root/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcmgenet_get_wol
  2. bcmgenet_set_wol
  3. bcmgenet_poll_wol_status
  4. bcmgenet_wol_power_down_cfg
  5. bcmgenet_wol_power_up_cfg

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support
   4  *
   5  * Copyright (c) 2014-2017 Broadcom
   6  */
   7 
   8 #define pr_fmt(fmt)                             "bcmgenet_wol: " fmt
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/sched.h>
  13 #include <linux/types.h>
  14 #include <linux/interrupt.h>
  15 #include <linux/string.h>
  16 #include <linux/init.h>
  17 #include <linux/errno.h>
  18 #include <linux/delay.h>
  19 #include <linux/pm.h>
  20 #include <linux/clk.h>
  21 #include <linux/version.h>
  22 #include <linux/platform_device.h>
  23 #include <net/arp.h>
  24 
  25 #include <linux/mii.h>
  26 #include <linux/ethtool.h>
  27 #include <linux/netdevice.h>
  28 #include <linux/inetdevice.h>
  29 #include <linux/etherdevice.h>
  30 #include <linux/skbuff.h>
  31 #include <linux/in.h>
  32 #include <linux/ip.h>
  33 #include <linux/ipv6.h>
  34 #include <linux/phy.h>
  35 
  36 #include "bcmgenet.h"
  37 
  38 /* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet
  39  * Detection is supported through ethtool
  40  */
  41 void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  42 {
  43         struct bcmgenet_priv *priv = netdev_priv(dev);
  44         u32 reg;
  45 
  46         wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
  47         wol->wolopts = priv->wolopts;
  48         memset(wol->sopass, 0, sizeof(wol->sopass));
  49 
  50         if (wol->wolopts & WAKE_MAGICSECURE) {
  51                 reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS);
  52                 put_unaligned_be16(reg, &wol->sopass[0]);
  53                 reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS);
  54                 put_unaligned_be32(reg, &wol->sopass[2]);
  55         }
  56 }
  57 
  58 /* ethtool function - set WOL (Wake on LAN) settings.
  59  * Only for magic packet detection mode.
  60  */
  61 int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  62 {
  63         struct bcmgenet_priv *priv = netdev_priv(dev);
  64         struct device *kdev = &priv->pdev->dev;
  65         u32 reg;
  66 
  67         if (!device_can_wakeup(kdev))
  68                 return -ENOTSUPP;
  69 
  70         if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
  71                 return -EINVAL;
  72 
  73         reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
  74         if (wol->wolopts & WAKE_MAGICSECURE) {
  75                 bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
  76                                      UMAC_MPD_PW_MS);
  77                 bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
  78                                      UMAC_MPD_PW_LS);
  79                 reg |= MPD_PW_EN;
  80         } else {
  81                 reg &= ~MPD_PW_EN;
  82         }
  83         bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
  84 
  85         /* Flag the device and relevant IRQ as wakeup capable */
  86         if (wol->wolopts) {
  87                 device_set_wakeup_enable(kdev, 1);
  88                 /* Avoid unbalanced enable_irq_wake calls */
  89                 if (priv->wol_irq_disabled)
  90                         enable_irq_wake(priv->wol_irq);
  91                 priv->wol_irq_disabled = false;
  92         } else {
  93                 device_set_wakeup_enable(kdev, 0);
  94                 /* Avoid unbalanced disable_irq_wake calls */
  95                 if (!priv->wol_irq_disabled)
  96                         disable_irq_wake(priv->wol_irq);
  97                 priv->wol_irq_disabled = true;
  98         }
  99 
 100         priv->wolopts = wol->wolopts;
 101 
 102         return 0;
 103 }
 104 
 105 static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
 106 {
 107         struct net_device *dev = priv->dev;
 108         int retries = 0;
 109 
 110         while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
 111                 & RBUF_STATUS_WOL)) {
 112                 retries++;
 113                 if (retries > 5) {
 114                         netdev_crit(dev, "polling wol mode timeout\n");
 115                         return -ETIMEDOUT;
 116                 }
 117                 mdelay(1);
 118         }
 119 
 120         return retries;
 121 }
 122 
 123 int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
 124                                 enum bcmgenet_power_mode mode)
 125 {
 126         struct net_device *dev = priv->dev;
 127         int retries = 0;
 128         u32 reg;
 129 
 130         if (mode != GENET_POWER_WOL_MAGIC) {
 131                 netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
 132                 return -EINVAL;
 133         }
 134 
 135         /* disable RX */
 136         reg = bcmgenet_umac_readl(priv, UMAC_CMD);
 137         reg &= ~CMD_RX_EN;
 138         bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 139         mdelay(10);
 140 
 141         reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
 142         reg |= MPD_EN;
 143         bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 144 
 145         /* Do not leave UniMAC in MPD mode only */
 146         retries = bcmgenet_poll_wol_status(priv);
 147         if (retries < 0) {
 148                 reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
 149                 reg &= ~MPD_EN;
 150                 bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 151                 return retries;
 152         }
 153 
 154         netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n",
 155                   retries);
 156 
 157         /* Enable CRC forward */
 158         reg = bcmgenet_umac_readl(priv, UMAC_CMD);
 159         priv->crc_fwd_en = 1;
 160         reg |= CMD_CRC_FWD;
 161 
 162         /* Receiver must be enabled for WOL MP detection */
 163         reg |= CMD_RX_EN;
 164         bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 165 
 166         if (priv->hw_params->flags & GENET_HAS_EXT) {
 167                 reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
 168                 reg &= ~EXT_ENERGY_DET_MASK;
 169                 bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
 170         }
 171 
 172         return 0;
 173 }
 174 
 175 void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
 176                                enum bcmgenet_power_mode mode)
 177 {
 178         u32 reg;
 179 
 180         if (mode != GENET_POWER_WOL_MAGIC) {
 181                 netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode);
 182                 return;
 183         }
 184 
 185         reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
 186         if (!(reg & MPD_EN))
 187                 return; /* already powered up so skip the rest */
 188         reg &= ~MPD_EN;
 189         bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 190 
 191         /* Disable CRC Forward */
 192         reg = bcmgenet_umac_readl(priv, UMAC_CMD);
 193         reg &= ~CMD_CRC_FWD;
 194         bcmgenet_umac_writel(priv, reg, UMAC_CMD);
 195         priv->crc_fwd_en = 0;
 196 }

/* [<][>][^][v][top][bottom][index][help] */