OSDN Git Service

net: bcmgenet: add WAKE_FILTER support
authorDoug Berger <opendmb@gmail.com>
Wed, 29 Apr 2020 20:02:06 +0000 (13:02 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 29 Apr 2020 23:55:22 +0000 (16:55 -0700)
This commit enables support for the WAKE_FILTER method of Wake on
LAN for the GENET driver. The method can be enabled by adding 'f'
to the interface 'wol' setting specified by ethtool.

Rx network flow rules can be specified using ethtool. Rules that
define a flow-type with the RX_CLS_FLOW_WAKE action (i.e. -2) can
wake the system from the 'standby' power state when the WAKE_FILTER
WoL method is enabled.

Signed-off-by: Doug Berger <opendmb@gmail.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c

index 5ef1ea7..ad614d7 100644 (file)
@@ -724,7 +724,7 @@ static int bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv,
                break;
        }
 
-       if (!fs->ring_cookie) {
+       if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) {
                /* Ring 0 flows can be handled by the default Descriptor Ring
                 * We'll map them to ring 0, but don't enable the filter
                 */
@@ -1499,7 +1499,8 @@ static int bcmgenet_insert_flow(struct net_device *dev,
                return -EINVAL;
        }
 
-       if (cmd->fs.ring_cookie > priv->hw_params->rx_queues) {
+       if (cmd->fs.ring_cookie > priv->hw_params->rx_queues &&
+           cmd->fs.ring_cookie != RX_CLS_FLOW_WAKE) {
                netdev_err(dev, "rxnfc: Unsupported action (%llu)\n",
                           cmd->fs.ring_cookie);
                return -EINVAL;
index da45a46..4b9d65f 100644 (file)
@@ -42,7 +42,7 @@ void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
 
-       wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
+       wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER;
        wol->wolopts = priv->wolopts;
        memset(wol->sopass, 0, sizeof(wol->sopass));
 
@@ -61,7 +61,7 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (!device_can_wakeup(kdev))
                return -ENOTSUPP;
 
-       if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE))
+       if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER))
                return -EINVAL;
 
        if (wol->wolopts & WAKE_MAGICSECURE)
@@ -117,8 +117,9 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
                                enum bcmgenet_power_mode mode)
 {
        struct net_device *dev = priv->dev;
+       struct bcmgenet_rxnfc_rule *rule;
+       u32 reg, hfb_ctrl_reg, hfb_enable = 0;
        int retries = 0;
-       u32 reg;
 
        if (mode != GENET_POWER_WOL_MAGIC) {
                netif_err(priv, wol, dev, "unsupported mode: %d\n", mode);
@@ -135,13 +136,24 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
        bcmgenet_umac_writel(priv, reg, UMAC_CMD);
        mdelay(10);
 
-       reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
-       reg |= MPD_EN;
-       if (priv->wolopts & WAKE_MAGICSECURE) {
-               bcmgenet_set_mpd_password(priv);
-               reg |= MPD_PW_EN;
+       if (priv->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
+               reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+               reg |= MPD_EN;
+               if (priv->wolopts & WAKE_MAGICSECURE) {
+                       bcmgenet_set_mpd_password(priv);
+                       reg |= MPD_PW_EN;
+               }
+               bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+       }
+
+       hfb_ctrl_reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+       if (priv->wolopts & WAKE_FILTER) {
+               list_for_each_entry(rule, &priv->rxnfc_list, list)
+                       if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE)
+                               hfb_enable |= (1 << rule->fs.location);
+               reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN;
+               bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
        }
-       bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
        /* Do not leave UniMAC in MPD mode only */
        retries = bcmgenet_poll_wol_status(priv);
@@ -149,6 +161,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
                reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
                reg &= ~(MPD_EN | MPD_PW_EN);
                bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+               bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
                return retries;
        }
 
@@ -158,6 +171,13 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
        clk_prepare_enable(priv->clk_wol);
        priv->wol_active = 1;
 
+       if (hfb_enable) {
+               bcmgenet_hfb_reg_writel(priv, hfb_enable,
+                                       HFB_FLT_ENABLE_V3PLUS + 4);
+               hfb_ctrl_reg = RBUF_HFB_EN | RBUF_ACPI_EN;
+               bcmgenet_hfb_reg_writel(priv, hfb_ctrl_reg, HFB_CTRL);
+       }
+
        /* Enable CRC forward */
        reg = bcmgenet_umac_readl(priv, UMAC_CMD);
        priv->crc_fwd_en = 1;
@@ -197,6 +217,11 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
        reg &= ~(MPD_EN | MPD_PW_EN);
        bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
 
+       /* Disable WAKE_FILTER Detection */
+       reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL);
+       reg &= ~(RBUF_HFB_EN | RBUF_ACPI_EN);
+       bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL);
+
        /* Disable CRC Forward */
        reg = bcmgenet_umac_readl(priv, UMAC_CMD);
        reg &= ~CMD_CRC_FWD;