net: systemport: Fix WoL with password after deep sleep
authorFlorian Fainelli <f.fainelli@gmail.com>
Fri, 1 Feb 2019 21:23:38 +0000 (13:23 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Feb 2019 18:46:11 +0000 (19:46 +0100)
[ Upstream commit 8dfb8d2cceb76b74ad5b58cc65c75994329b4d5e ]

Broadcom STB chips support a deep sleep mode where all register
contents are lost. Because we were stashing the MagicPacket password
into some of these registers a suspend into that deep sleep then a
resumption would not lead to being able to wake-up from MagicPacket with
password again.

Fix this by keeping a software copy of the password and program it
during suspend.

Fixes: 83e82f4c706b ("net: systemport: add Wake-on-LAN support")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bcmsysport.h

index 4546255..ed3edb1 100644 (file)
@@ -519,7 +519,6 @@ static void bcm_sysport_get_wol(struct net_device *dev,
                                struct ethtool_wolinfo *wol)
 {
        struct bcm_sysport_priv *priv = netdev_priv(dev);
-       u32 reg;
 
        wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
        wol->wolopts = priv->wolopts;
@@ -527,11 +526,7 @@ static void bcm_sysport_get_wol(struct net_device *dev,
        if (!(priv->wolopts & WAKE_MAGICSECURE))
                return;
 
-       /* Return the programmed SecureOn password */
-       reg = umac_readl(priv, UMAC_PSW_MS);
-       put_unaligned_be16(reg, &wol->sopass[0]);
-       reg = umac_readl(priv, UMAC_PSW_LS);
-       put_unaligned_be32(reg, &wol->sopass[2]);
+       memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
 }
 
 static int bcm_sysport_set_wol(struct net_device *dev,
@@ -547,13 +542,8 @@ static int bcm_sysport_set_wol(struct net_device *dev,
        if (wol->wolopts & ~supported)
                return -EINVAL;
 
-       /* Program the SecureOn password */
-       if (wol->wolopts & WAKE_MAGICSECURE) {
-               umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
-                           UMAC_PSW_MS);
-               umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
-                           UMAC_PSW_LS);
-       }
+       if (wol->wolopts & WAKE_MAGICSECURE)
+               memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
 
        /* Flag the device and relevant IRQ as wakeup capable */
        if (wol->wolopts) {
@@ -2221,12 +2211,17 @@ static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv)
        unsigned int timeout = 1000;
        u32 reg;
 
-       /* Password has already been programmed */
        reg = umac_readl(priv, UMAC_MPD_CTRL);
        reg |= MPD_EN;
        reg &= ~PSW_EN;
-       if (priv->wolopts & WAKE_MAGICSECURE)
+       if (priv->wolopts & WAKE_MAGICSECURE) {
+               /* Program the SecureOn password */
+               umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
+                           UMAC_PSW_MS);
+               umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
+                           UMAC_PSW_LS);
                reg |= PSW_EN;
+       }
        umac_writel(priv, reg, UMAC_MPD_CTRL);
 
        /* Make sure RBUF entered WoL mode as result */
index 86ae751..3df4a48 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __BCM_SYSPORT_H
 #define __BCM_SYSPORT_H
 
+#include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 
 /* Receive/transmit descriptor format */
@@ -754,6 +755,7 @@ struct bcm_sysport_priv {
        unsigned int            crc_fwd:1;
        u16                     rev;
        u32                     wolopts;
+       u8                      sopass[SOPASS_MAX];
        unsigned int            wol_irq_disabled:1;
 
        /* MIB related fields */