Skip to content

Commit

Permalink
net: bcmgenet: add WAKE_FILTER support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Doug Berger authored and David S. Miller committed Apr 29, 2020
1 parent 3e37095 commit f50932c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
5 changes: 3 additions & 2 deletions drivers/net/ethernet/broadcom/genet/bcmgenet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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;
Expand Down
43 changes: 34 additions & 9 deletions drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -135,20 +136,32 @@ 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);
if (retries < 0) {
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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit f50932c

Please sign in to comment.