i40e: add wake-on-lan support
authorShannon Nelson <shannon.nelson@intel.com>
Thu, 28 Nov 2013 06:39:22 +0000 (06:39 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 4 Jan 2014 03:22:25 +0000 (19:22 -0800)
Wake on LAN is disabled by default and will remain that way for most
platforms, but there is an NVM setting that allows vendors to enable it
for a port if they think they've provided the right power environment
for the device.  This patch adds code to check the NVM setting and enable
Magic Packet use if WoL is enabled for the port.

Since only Magic Packet is supported, there's not a lot of HW configuration
needed.

Change-Id: I44e904a7b15695e34683009f487064cd86ea59b0
Signed-off-by: Shannon Nelson <shannon.nelson@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: Kavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_type.h

index 40706c15cdc37d7f51bfcf033207280738422fde..31dd2651155325e6d7a6389a8e274edf86206ea4 100644 (file)
@@ -205,6 +205,7 @@ struct i40e_pf {
        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;
index d6681f6bf2913d586e09e51f44e06a18741ec107..255a138a212a16fa8701159f08f74ec31ebbf256 100644 (file)
@@ -844,8 +844,45 @@ static void i40e_diag_test(struct net_device *netdev,
 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)
@@ -1568,6 +1605,7 @@ static const struct ethtool_ops i40e_ethtool_ops = {
        .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,
index 22a2c0efff60d5de697e949be3d9fcac2e933a4f..45b21987645a767113bc9503e98461ba08b6320a 100644 (file)
@@ -7537,6 +7537,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        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);
@@ -7858,6 +7862,7 @@ static void i40e_pci_error_resume(struct pci_dev *pdev)
 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);
@@ -7865,8 +7870,11 @@ static void i40e_shutdown(struct pci_dev *pdev)
        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);
        }
 }
@@ -7879,6 +7887,7 @@ static void i40e_shutdown(struct pci_dev *pdev)
 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);
@@ -7886,7 +7895,10 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t 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;
index 72a6028d24e0dfe6243b271e9d814c1219fc495b..8bf1cac2d9005efb8c37116a26939c2599e12fe1 100644 (file)
@@ -1022,6 +1022,7 @@ struct i40e_hw_port_stats {
 #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