]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ixgbe: add support for ACPI WOL for E610
authorJedrzej Jagielski <jedrzej.jagielski@intel.com>
Mon, 3 Mar 2025 12:06:28 +0000 (13:06 +0100)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Tue, 29 Apr 2025 22:13:43 +0000 (15:13 -0700)
Currently only APM (Advanced Power Management) is supported by
the ixgbe driver. It works for magic packets only, as for different
sources of wake-up E610 adapter utilizes different feature.

Add E610 specific implementation of ixgbe_set_wol() callback. When
any of broadcast/multicast/unicast wake-up is set, disable APM and
configure ACPI (Advanced Configuration and Power Interface).

Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Bharath R <bharath.r@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c

index 83d9ee3941e583c1a7823729d283ffd7d96add92..abc8c279192a93cebe56ca613de4d9769728e8a5 100644 (file)
@@ -2365,6 +2365,50 @@ static int ixgbe_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        return 0;
 }
 
+static int ixgbe_set_wol_acpi(struct net_device *netdev,
+                             struct ethtool_wolinfo *wol)
+{
+       struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 grc;
+
+       if (ixgbe_wol_exclusion(adapter, wol))
+               return wol->wolopts ? -EOPNOTSUPP : 0;
+
+       /* disable APM wakeup */
+       grc = IXGBE_READ_REG(hw, IXGBE_GRC_X550EM_a);
+       grc &= ~IXGBE_GRC_APME;
+       IXGBE_WRITE_REG(hw, IXGBE_GRC_X550EM_a, grc);
+
+       /* erase existing filters */
+       IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
+       adapter->wol = 0;
+
+       if (wol->wolopts & WAKE_UCAST)
+               adapter->wol |= IXGBE_WUFC_EX;
+       if (wol->wolopts & WAKE_MCAST)
+               adapter->wol |= IXGBE_WUFC_MC;
+       if (wol->wolopts & WAKE_BCAST)
+               adapter->wol |= IXGBE_WUFC_BC;
+
+       IXGBE_WRITE_REG(hw, IXGBE_WUC, IXGBE_WUC_PME_EN);
+       IXGBE_WRITE_REG(hw, IXGBE_WUFC, adapter->wol);
+
+       hw->wol_enabled = adapter->wol;
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
+       return 0;
+}
+
+static int ixgbe_set_wol_e610(struct net_device *netdev,
+                             struct ethtool_wolinfo *wol)
+{
+       if (wol->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
+               return ixgbe_set_wol_acpi(netdev, wol);
+       else
+               return ixgbe_set_wol(netdev, wol);
+}
+
 static int ixgbe_nway_reset(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
@@ -3656,7 +3700,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops_e610 = {
        .get_regs_len           = ixgbe_get_regs_len,
        .get_regs               = ixgbe_get_regs,
        .get_wol                = ixgbe_get_wol,
-       .set_wol                = ixgbe_set_wol,
+       .set_wol                = ixgbe_set_wol_e610,
        .nway_reset             = ixgbe_nway_reset,
        .get_link               = ethtool_op_get_link,
        .get_eeprom_len         = ixgbe_get_eeprom_len,