e1000e: Export S0ix flags to ethtool
authorMario Limonciello <mario.limonciello@dell.com>
Mon, 14 Dec 2020 19:29:35 +0000 (13:29 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Jan 2021 19:18:12 +0000 (20:18 +0100)
[ Upstream commit 3c98cbf22a96c1b12f48c1b2a4680dfe5cb280f9 ]

This flag can be used by an end user to disable S0ix flows on a
buggy system or by an OEM for development purposes.

If you need this flag to be persisted across reboots, it's suggested
to use a udev rule to call adjust it until the kernel could have your
configuration in a disallow list.

Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Tested-by: Yijun Shen <Yijun.shen@dell.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/netdev.c

index ba7a0f8f693763e74ddd2582d07716e50c2f8f28..5b2143f4b1f85fada39e3509508d7ed31be46abb 100644 (file)
@@ -436,6 +436,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
 #define FLAG2_DFLT_CRC_STRIPPING          BIT(12)
 #define FLAG2_CHECK_RX_HWTSTAMP           BIT(13)
 #define FLAG2_CHECK_SYSTIM_OVERFLOW       BIT(14)
+#define FLAG2_ENABLE_S0IX_FLOWS           BIT(15)
 
 #define E1000_RX_DESC_PS(R, i)     \
        (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
index 03215b0aee4bd349cab3793d1e38282c78e9cece..06442e6bef7310e41852bdb727d1b2c3c583a050 100644 (file)
@@ -23,6 +23,13 @@ struct e1000_stats {
        int stat_offset;
 };
 
+static const char e1000e_priv_flags_strings[][ETH_GSTRING_LEN] = {
+#define E1000E_PRIV_FLAGS_S0IX_ENABLED BIT(0)
+       "s0ix-enabled",
+};
+
+#define E1000E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(e1000e_priv_flags_strings)
+
 #define E1000_STAT(str, m) { \
                .stat_string = str, \
                .type = E1000_STATS, \
@@ -1776,6 +1783,8 @@ static int e1000e_get_sset_count(struct net_device __always_unused *netdev,
                return E1000_TEST_LEN;
        case ETH_SS_STATS:
                return E1000_STATS_LEN;
+       case ETH_SS_PRIV_FLAGS:
+               return E1000E_PRIV_FLAGS_STR_LEN;
        default:
                return -EOPNOTSUPP;
        }
@@ -2097,6 +2106,10 @@ static void e1000_get_strings(struct net_device __always_unused *netdev,
                        p += ETH_GSTRING_LEN;
                }
                break;
+       case ETH_SS_PRIV_FLAGS:
+               memcpy(data, e1000e_priv_flags_strings,
+                      E1000E_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN);
+               break;
        }
 }
 
@@ -2305,6 +2318,37 @@ static int e1000e_get_ts_info(struct net_device *netdev,
        return 0;
 }
 
+static u32 e1000e_get_priv_flags(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       u32 priv_flags = 0;
+
+       if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
+               priv_flags |= E1000E_PRIV_FLAGS_S0IX_ENABLED;
+
+       return priv_flags;
+}
+
+static int e1000e_set_priv_flags(struct net_device *netdev, u32 priv_flags)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       unsigned int flags2 = adapter->flags2;
+
+       flags2 &= ~FLAG2_ENABLE_S0IX_FLOWS;
+       if (priv_flags & E1000E_PRIV_FLAGS_S0IX_ENABLED) {
+               struct e1000_hw *hw = &adapter->hw;
+
+               if (hw->mac.type < e1000_pch_cnp)
+                       return -EINVAL;
+               flags2 |= FLAG2_ENABLE_S0IX_FLOWS;
+       }
+
+       if (flags2 != adapter->flags2)
+               adapter->flags2 = flags2;
+
+       return 0;
+}
+
 static const struct ethtool_ops e1000_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS,
        .get_drvinfo            = e1000_get_drvinfo,
@@ -2336,6 +2380,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
        .set_eee                = e1000e_set_eee,
        .get_link_ksettings     = e1000_get_link_ksettings,
        .set_link_ksettings     = e1000_set_link_ksettings,
+       .get_priv_flags         = e1000e_get_priv_flags,
+       .set_priv_flags         = e1000e_set_priv_flags,
 };
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)
index b9800ba2006ca3a831072aebf9efa88251086273..e9b82c209c2df60534a2eef83fe5d8e230846554 100644 (file)
@@ -6923,7 +6923,6 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct e1000_hw *hw = &adapter->hw;
        int rc;
 
        e1000e_flush_lpic(pdev);
@@ -6935,7 +6934,7 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev)
                e1000e_pm_thaw(dev);
        } else {
                /* Introduce S0ix implementation */
-               if (hw->mac.type >= e1000_pch_cnp)
+               if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
                        e1000e_s0ix_entry_flow(adapter);
        }
 
@@ -6947,11 +6946,10 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct e1000_hw *hw = &adapter->hw;
        int rc;
 
        /* Introduce S0ix implementation */
-       if (hw->mac.type >= e1000_pch_cnp)
+       if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
                e1000e_s0ix_exit_flow(adapter);
 
        rc = __e1000_resume(pdev);
@@ -7615,6 +7613,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!(adapter->flags & FLAG_HAS_AMT))
                e1000e_get_hw_control(adapter);
 
+       if (hw->mac.type >= e1000_pch_cnp)
+               adapter->flags2 |= FLAG2_ENABLE_S0IX_FLOWS;
+
        strlcpy(netdev->name, "eth%d", sizeof(netdev->name));
        err = register_netdev(netdev);
        if (err)