u16 rss_size_max;          /* HW defined max RSS queues */
        u16 fdir_pf_filter_count;  /* num of guaranteed filters for this PF */
        u8 atr_sample_rate;
+       bool wol_en;
 
        enum i40e_interrupt_policy int_policy;
        u16 rx_itr_default;
 
 static void i40e_get_wol(struct net_device *netdev,
                         struct ethtool_wolinfo *wol)
 {
-       wol->supported = 0;
-       wol->wolopts = 0;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u16 wol_nvm_bits;
+
+       /* NVM bit on means WoL disabled for the port */
+       i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits);
+       if ((1 << hw->port) & wol_nvm_bits) {
+               wol->supported = 0;
+               wol->wolopts = 0;
+       } else {
+               wol->supported = WAKE_MAGIC;
+               wol->wolopts = (pf->wol_en ? WAKE_MAGIC : 0);
+       }
+}
+
+static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u16 wol_nvm_bits;
+
+       /* NVM bit on means WoL disabled for the port */
+       i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits);
+       if (((1 << hw->port) & wol_nvm_bits))
+               return -EOPNOTSUPP;
+
+       /* only magic packet is supported */
+       if (wol->wolopts && (wol->wolopts != WAKE_MAGIC))
+               return -EOPNOTSUPP;
+
+       /* is this a new value? */
+       if (pf->wol_en != !!wol->wolopts) {
+               pf->wol_en = !!wol->wolopts;
+               device_set_wakeup_enable(&pf->pdev->dev, pf->wol_en);
+       }
+
+       return 0;
 }
 
 static int i40e_nway_reset(struct net_device *netdev)
        .nway_reset             = i40e_nway_reset,
        .get_link               = ethtool_op_get_link,
        .get_wol                = i40e_get_wol,
+       .set_wol                = i40e_set_wol,
        .get_eeprom_len         = i40e_get_eeprom_len,
        .get_eeprom             = i40e_get_eeprom,
        .get_ringparam          = i40e_get_ringparam,
 
        pf->flags |= I40E_FLAG_NEED_LINK_UPDATE;
        pf->link_check_timeout = jiffies;
 
+       /* WoL defaults to disabled */
+       pf->wol_en = false;
+       device_set_wakeup_enable(&pf->pdev->dev, pf->wol_en);
+
        /* set up the main switch operations */
        i40e_determine_queue_usage(pf);
        i40e_init_interrupt_scheme(pf);
 static void i40e_shutdown(struct pci_dev *pdev)
 {
        struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_hw *hw = &pf->hw;
 
        set_bit(__I40E_SUSPENDED, &pf->state);
        set_bit(__I40E_DOWN, &pf->state);
        i40e_prep_for_reset(pf);
        rtnl_unlock();
 
+       wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
+       wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
+
        if (system_state == SYSTEM_POWER_OFF) {
-               pci_wake_from_d3(pdev, false);    /* No WoL support yet */
+               pci_wake_from_d3(pdev, pf->wol_en);
                pci_set_power_state(pdev, PCI_D3hot);
        }
 }
 static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_hw *hw = &pf->hw;
 
        set_bit(__I40E_SUSPENDED, &pf->state);
        set_bit(__I40E_DOWN, &pf->state);
        i40e_prep_for_reset(pf);
        rtnl_unlock();
 
-       pci_wake_from_d3(pdev, false);    /* No WoL support yet */
+       wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
+       wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
+
+       pci_wake_from_d3(pdev, pf->wol_en);
        pci_set_power_state(pdev, PCI_D3hot);
 
        return 0;
 
 #define I40E_SR_NVM_CONTROL_WORD               0x00
 #define I40E_SR_EMP_MODULE_PTR                 0x0F
 #define I40E_SR_NVM_IMAGE_VERSION              0x18
+#define I40E_SR_NVM_WAKE_ON_LAN                        0x19
 #define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR  0x27
 #define I40E_SR_NVM_EETRACK_LO                 0x2D
 #define I40E_SR_NVM_EETRACK_HI                 0x2E