be2net: Enable Wake-On-LAN from shutdown for Skyhawk
authorSriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Mon, 6 Jun 2016 11:22:09 +0000 (07:22 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 7 Jun 2016 23:18:19 +0000 (16:18 -0700)
Skyhawk does support wake-up from ACPI shutdown state - S5, provided the
platform supports it (like Auxiliary power source etc). The changes listed
below are done to fix this.

1) There's no need to defer the HW configuration of WOL to be_suspend().
Remove this in be_suspend() and move it to be_set_wol() ethtool function
so it is configured directly in the context of ethtool. This automatically
takes care of the shutdown case.

2) The driver incorrectly uses WOL_CAP field in the FW response to
get_acpi_wol_cap() command, to determine if WOL is enabled. Instead the
driver must rely on the macaddr field in the response to infer WOL state.

3) In be_get_config() during init, if we find that WOL is enabled in FW,
call pci_enable_wake() to enable pmcsr.pme_en bit. This is needed to
support persistent WOL configuration provided by the FW in some platforms.

4) Remove code in be_set_wol() that writes to PCICFG_PM_CONTROL_OFFSET
to set pme_en bit; pci_enable_wake() sets that.

Fixes: 028991e49 ("Enabling Wake-on-LAN is not supported in S5 state")
Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Signed-off-by: Sathya Perla <sathya.perla@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_main.c

index bef92c4027ccc80ded04d1bc91741ba9afc60a05..ddc8611c8432ccbda6c7c11bf47f219bdab4671a 100644 (file)
@@ -4023,7 +4023,10 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
                resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *)cmd.va;
 
                adapter->wol_cap = resp->wol_settings;
-               if (adapter->wol_cap & BE_WOL_CAP)
+
+               /* Non-zero macaddr indicates WOL is enabled */
+               if (adapter->wol_cap & BE_WOL_CAP &&
+                   !is_zero_ether_addr(resp->magic_mac))
                        adapter->wol_en = true;
        }
 err:
index b63ae37aa0c2e1c9ed8b23c2759dcb25d9a74499..855a1702c5a999920fb8c14f81f68b3fe682919b 100644 (file)
@@ -1556,7 +1556,9 @@ struct be_cmd_resp_acpi_wol_magic_config_v1 {
        u8 rsvd0[2];
        u8 wol_settings;
        u8 rsvd1[5];
-       u32 rsvd2[295];
+       u32 rsvd2[288];
+       u8 magic_mac[6];
+       u8 rsvd3[22];
 } __packed;
 
 #define BE_GET_WOL_CAP                 2
index 2ff691636dac3b8f518f8c054ce5c90dc8b00ffe..c569cd703c802a54ba984279e1f7931bd6195af8 100644 (file)
@@ -793,6 +793,11 @@ static void be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 static int be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       struct device *dev = &adapter->pdev->dev;
+       struct be_dma_mem cmd;
+       u8 mac[ETH_ALEN];
+       bool enable;
+       int status;
 
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EOPNOTSUPP;
@@ -802,12 +807,32 @@ static int be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
                return -EOPNOTSUPP;
        }
 
-       if (wol->wolopts & WAKE_MAGIC)
-               adapter->wol_en = true;
-       else
-               adapter->wol_en = false;
+       cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config);
+       cmd.va = dma_zalloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL);
+       if (!cmd.va)
+               return -ENOMEM;
 
-       return 0;
+       eth_zero_addr(mac);
+
+       enable = wol->wolopts & WAKE_MAGIC;
+       if (enable)
+               ether_addr_copy(mac, adapter->netdev->dev_addr);
+
+       status = be_cmd_enable_magic_wol(adapter, mac, &cmd);
+       if (status) {
+               dev_err(dev, "Could not set Wake-on-lan mac address\n");
+               status = be_cmd_status(status);
+               goto err;
+       }
+
+       pci_enable_wake(adapter->pdev, PCI_D3hot, enable);
+       pci_enable_wake(adapter->pdev, PCI_D3cold, enable);
+
+       adapter->wol_en = enable ? true : false;
+
+err:
+       dma_free_coherent(dev, cmd.size, cmd.va, cmd.dma);
+       return status;
 }
 
 static int be_test_ddr_dma(struct be_adapter *adapter)
index 860104711ce7be74df90b08ede5916d5aa56c4bd..32823a7feb572b78cce25749d5ec51f5bd613e40 100644 (file)
@@ -3636,40 +3636,6 @@ err:
        return -EIO;
 }
 
-static int be_setup_wol(struct be_adapter *adapter, bool enable)
-{
-       struct device *dev = &adapter->pdev->dev;
-       struct be_dma_mem cmd;
-       u8 mac[ETH_ALEN];
-       int status;
-
-       eth_zero_addr(mac);
-
-       cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config);
-       cmd.va = dma_zalloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL);
-       if (!cmd.va)
-               return -ENOMEM;
-
-       if (enable) {
-               status = pci_write_config_dword(adapter->pdev,
-                                               PCICFG_PM_CONTROL_OFFSET,
-                                               PCICFG_PM_CONTROL_MASK);
-               if (status) {
-                       dev_err(dev, "Could not enable Wake-on-lan\n");
-                       goto err;
-               }
-       } else {
-               ether_addr_copy(mac, adapter->netdev->dev_addr);
-       }
-
-       status = be_cmd_enable_magic_wol(adapter, mac, &cmd);
-       pci_enable_wake(adapter->pdev, PCI_D3hot, enable);
-       pci_enable_wake(adapter->pdev, PCI_D3cold, enable);
-err:
-       dma_free_coherent(dev, cmd.size, cmd.va, cmd.dma);
-       return status;
-}
-
 static void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
 {
        u32 addr;
@@ -4294,6 +4260,8 @@ static int be_get_config(struct be_adapter *adapter)
        }
 
        be_cmd_get_acpi_wol_cap(adapter);
+       pci_enable_wake(adapter->pdev, PCI_D3hot, adapter->wol_en);
+       pci_enable_wake(adapter->pdev, PCI_D3cold, adapter->wol_en);
 
        be_cmd_query_port_name(adapter);
 
@@ -5463,9 +5431,6 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct be_adapter *adapter = pci_get_drvdata(pdev);
 
-       if (adapter->wol_en)
-               be_setup_wol(adapter, true);
-
        be_intr_set(adapter, false);
        be_cancel_err_detection(adapter);
 
@@ -5494,9 +5459,6 @@ static int be_pci_resume(struct pci_dev *pdev)
 
        be_schedule_err_detection(adapter, ERR_DETECTION_DELAY);
 
-       if (adapter->wol_en)
-               be_setup_wol(adapter, false);
-
        return 0;
 }