igb: Enable reading of wake up packet

Currently, in igb_resume(), igb driver ignores the Wake Up Status (WUS)
and Wake Up Packet Memory (WUPM) registers. This patch enables the igb
driver to read the WUPM if the controller was woken by a wake up packet
that is not more than 128 bytes long (maximum WUPM size), then pass it
up the kernel network stack.

Signed-off-by: Kim Tatt Chuah <kim.tatt.chuah@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Kim Tatt Chuah 2017-03-27 08:44:35 +08:00 committed by Jeff Kirsher
parent 4827cc3779
commit b90fa87635
2 changed files with 56 additions and 1 deletions

View File

@ -39,6 +39,27 @@
#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ #define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ #define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
/* Wake Up Status */
#define E1000_WUS_EX 0x00000004 /* Directed Exact */
#define E1000_WUS_ARPD 0x00000020 /* Directed ARP Request */
#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 */
#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 */
#define E1000_WUS_NSD 0x00000400 /* Directed IPv6 Neighbor Solicitation */
/* Packet types that are enabled for wake packet delivery */
#define WAKE_PKT_WUS ( \
E1000_WUS_EX | \
E1000_WUS_ARPD | \
E1000_WUS_IPV4 | \
E1000_WUS_IPV6 | \
E1000_WUS_NSD)
/* Wake Up Packet Length */
#define E1000_WUPL_MASK 0x00000FFF
/* Wake Up Packet Memory stores the first 128 bytes of the wake up packet */
#define E1000_WUPM_BYTES 128
/* Extended Device Control */ /* Extended Device Control */
#define E1000_CTRL_EXT_SDP2_DATA 0x00000040 /* Value of SW Defineable Pin 2 */ #define E1000_CTRL_EXT_SDP2_DATA 0x00000040 /* Value of SW Defineable Pin 2 */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Defineable Pin 3 */ #define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Defineable Pin 3 */

View File

@ -7985,6 +7985,36 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake,
return 0; return 0;
} }
static void igb_deliver_wake_packet(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
struct sk_buff *skb;
u32 wupl;
wupl = rd32(E1000_WUPL) & E1000_WUPL_MASK;
/* WUPM stores only the first 128 bytes of the wake packet.
* Read the packet only if we have the whole thing.
*/
if ((wupl == 0) || (wupl > E1000_WUPM_BYTES))
return;
skb = netdev_alloc_skb_ip_align(netdev, E1000_WUPM_BYTES);
if (!skb)
return;
skb_put(skb, wupl);
/* Ensure reads are 32-bit aligned */
wupl = roundup(wupl, 4);
memcpy_fromio(skb->data, hw->hw_addr + E1000_WUPM_REG(0), wupl);
skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb);
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int igb_suspend(struct device *dev) static int igb_suspend(struct device *dev)
@ -8014,7 +8044,7 @@ static int igb_resume(struct device *dev)
struct net_device *netdev = pci_get_drvdata(pdev); struct net_device *netdev = pci_get_drvdata(pdev);
struct igb_adapter *adapter = netdev_priv(netdev); struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
u32 err; u32 err, val;
pci_set_power_state(pdev, PCI_D0); pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev); pci_restore_state(pdev);
@ -8045,6 +8075,10 @@ static int igb_resume(struct device *dev)
*/ */
igb_get_hw_control(adapter); igb_get_hw_control(adapter);
val = rd32(E1000_WUS);
if (val & WAKE_PKT_WUS)
igb_deliver_wake_packet(netdev);
wr32(E1000_WUS, ~0); wr32(E1000_WUS, ~0);
rtnl_lock(); rtnl_lock();