return 0;
}
+/**
+ * ixgbe_setup_eee_e610 - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ * @enable_eee: boolean flag to enable EEE
+ *
+ * Enable/disable EEE based on @enable_eee.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_eee_e610(struct ixgbe_hw *hw, bool enable_eee)
+{
+ struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = {};
+ struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = {};
+ u16 eee_cap = 0;
+ int err;
+
+ err = ixgbe_aci_get_phy_caps(hw, false,
+ IXGBE_ACI_REPORT_ACTIVE_CFG, &phy_caps);
+ if (err)
+ return err;
+
+ ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
+ phy_cfg.caps |= (IXGBE_ACI_PHY_ENA_LINK |
+ IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT);
+
+ if (enable_eee) {
+ if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_2_5GB_FULL)
+ eee_cap |= IXGBE_ACI_PHY_EEE_EN_2_5GBASE_T;
+ if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_5GB_FULL)
+ eee_cap |= IXGBE_ACI_PHY_EEE_EN_5GBASE_T;
+ if (hw->phy.eee_speeds_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+ eee_cap |= IXGBE_ACI_PHY_EEE_EN_10GBASE_T;
+ }
+
+ phy_cfg.eee_cap = cpu_to_le16(eee_cap);
+
+ return ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
+}
+
/**
* ixgbe_identify_module_e610 - Identify SFP module type
* @hw: pointer to hardware structure
.fw_rollback_mode = ixgbe_fw_rollback_mode_e610,
.get_nvm_ver = ixgbe_get_active_nvm_ver,
.get_link_capabilities = ixgbe_get_link_capabilities_e610,
+ .setup_eee = ixgbe_setup_eee_e610,
.get_bus_info = ixgbe_get_bus_info_generic,
.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X540,
.release_swfw_sync = ixgbe_release_swfw_sync_X540,
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
+#include <linux/string_choices.h>
#include <linux/uaccess.h>
#include "ixgbe.h"
{ IXGBE_LINK_SPEED_10_FULL, ETHTOOL_LINK_MODE_10baseT_Full_BIT },
{ IXGBE_LINK_SPEED_100_FULL, ETHTOOL_LINK_MODE_100baseT_Full_BIT },
{ IXGBE_LINK_SPEED_1GB_FULL, ETHTOOL_LINK_MODE_1000baseT_Full_BIT },
- { IXGBE_LINK_SPEED_2_5GB_FULL, ETHTOOL_LINK_MODE_2500baseX_Full_BIT },
+ { IXGBE_LINK_SPEED_2_5GB_FULL, ETHTOOL_LINK_MODE_2500baseT_Full_BIT },
{ IXGBE_LINK_SPEED_5GB_FULL, ETHTOOL_LINK_MODE_5000baseT_Full_BIT },
{ IXGBE_LINK_SPEED_10GB_FULL, ETHTOOL_LINK_MODE_10000baseT_Full_BIT },
};
{ FW_PHY_ACT_UD_2_10G_KR_EEE, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
};
+static const struct {
+ u16 eee_cap_bit;
+ u32 link_mode;
+} ixgbe_eee_cap_map[] = {
+ { IXGBE_ACI_PHY_EEE_EN_100BASE_TX, ETHTOOL_LINK_MODE_100baseT_Full_BIT },
+ { IXGBE_ACI_PHY_EEE_EN_1000BASE_T, ETHTOOL_LINK_MODE_1000baseT_Full_BIT },
+ { IXGBE_ACI_PHY_EEE_EN_10GBASE_T, ETHTOOL_LINK_MODE_10000baseT_Full_BIT },
+ { IXGBE_ACI_PHY_EEE_EN_5GBASE_T, ETHTOOL_LINK_MODE_5000baseT_Full_BIT },
+ { IXGBE_ACI_PHY_EEE_EN_2_5GBASE_T, ETHTOOL_LINK_MODE_2500baseT_Full_BIT },
+};
+
static int ixgbe_validate_keee(struct net_device *netdev,
struct ethtool_keee *keee_requested)
{
return 0;
}
+/**
+ * ixgbe_is_eee_link_speed_supported_e610 - Check if EEE can be enabled
+ * @adapter: pointer to the adapter struct
+ *
+ * Check whether current link configuration is capable of enabling EEE feature.
+ *
+ * E610 specific function - for other adapters supporting EEE there might be
+ * no such limitation.
+ *
+ * Return: true if EEE can be enabled, false otherwise.
+ */
+static bool
+ixgbe_is_eee_link_speed_supported_e610(struct ixgbe_adapter *adapter)
+{
+ switch (adapter->link_speed) {
+ case IXGBE_LINK_SPEED_10GB_FULL:
+ case IXGBE_LINK_SPEED_2_5GB_FULL:
+ case IXGBE_LINK_SPEED_5GB_FULL:
+ return true;
+ case IXGBE_LINK_SPEED_100_FULL:
+ case IXGBE_LINK_SPEED_1GB_FULL:
+ e_dev_info("Energy Efficient Ethernet (EEE) feature is not supported on link speeds equal to or below 1Gbps. EEE is supported on speeds above 1Gbps.\n");
+ fallthrough;
+ default:
+ return false;
+ }
+}
+
+static int ixgbe_get_eee_e610(struct net_device *netdev,
+ struct ethtool_keee *kedata)
+{
+ struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
+ struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_link_status link;
+ u16 eee_cap;
+ int err;
+
+ linkmode_zero(kedata->lp_advertised);
+ linkmode_zero(kedata->supported);
+ linkmode_zero(kedata->advertised);
+
+ err = ixgbe_aci_get_link_info(hw, true, &link);
+ if (err)
+ return err;
+
+ err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
+ &pcaps);
+ if (err)
+ return err;
+
+ kedata->eee_active = link.eee_status & IXGBE_ACI_LINK_EEE_ACTIVE;
+ kedata->eee_enabled = link.eee_status & IXGBE_ACI_LINK_EEE_ENABLED;
+
+ /* for E610 devices EEE enablement implies TX LPI enablement */
+ kedata->tx_lpi_enabled = kedata->eee_enabled;
+
+ if (kedata->eee_enabled)
+ kedata->tx_lpi_timer = le16_to_cpu(pcaps.eee_entry_delay);
+
+ eee_cap = le16_to_cpu(pcaps.eee_cap);
+
+ for (int i = 0; i < ARRAY_SIZE(ixgbe_eee_cap_map); i++) {
+ if (eee_cap & ixgbe_eee_cap_map[i].eee_cap_bit)
+ linkmode_set_bit(ixgbe_eee_cap_map[i].link_mode,
+ kedata->lp_advertised);
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(ixgbe_ls_map); i++) {
+ if (hw->phy.eee_speeds_supported &
+ ixgbe_ls_map[i].mac_speed)
+ linkmode_set_bit(ixgbe_ls_map[i].link_mode,
+ kedata->supported);
+
+ if (hw->phy.eee_speeds_advertised &
+ ixgbe_ls_map[i].mac_speed)
+ linkmode_set_bit(ixgbe_ls_map[i].link_mode,
+ kedata->advertised);
+ }
+
+ return 0;
+}
+
+static int ixgbe_set_eee_e610(struct net_device *netdev,
+ struct ethtool_keee *kedata)
+{
+ struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+
+ err = ixgbe_validate_keee(netdev, kedata);
+
+ if (err == -EALREADY) {
+ return 0;
+ } else if (err) {
+ if (err == -EOPNOTSUPP)
+ e_dev_info("Energy Efficient Ethernet (EEE) feature is currently not supported on this device, please update the device NVM to the latest and try again\n");
+ return err;
+ }
+
+ if (!(ixgbe_is_eee_link_speed_supported_e610(adapter)) &&
+ kedata->eee_enabled)
+ return -EOPNOTSUPP;
+
+ hw->phy.eee_speeds_advertised = kedata->eee_enabled ?
+ hw->phy.eee_speeds_supported : 0;
+
+ err = hw->mac.ops.setup_eee(hw, kedata->eee_enabled);
+ if (err) {
+ e_dev_err("Setting EEE %s failed.\n",
+ str_on_off(kedata->eee_enabled));
+ return err;
+ }
+
+ if (kedata->eee_enabled)
+ adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
+ else
+ adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
+
+ if (netif_running(netdev))
+ ixgbe_reinit_locked(adapter);
+ else
+ ixgbe_reset(adapter);
+
+ return 0;
+}
+
static int
ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata)
{
.set_rxfh = ixgbe_set_rxfh,
.get_rxfh_fields = ixgbe_get_rxfh_fields,
.set_rxfh_fields = ixgbe_set_rxfh_fields,
- .get_eee = ixgbe_get_eee,
- .set_eee = ixgbe_set_eee,
+ .get_eee = ixgbe_get_eee_e610,
+ .set_eee = ixgbe_set_eee_e610,
.get_channels = ixgbe_get_channels,
.set_channels = ixgbe_set_channels,
.get_priv_flags = ixgbe_get_priv_flags,
/**
* ixgbe_set_eee_capable - helper function to determine EEE support on X550
+ * and E610
* @adapter: board private structure
*/
static void ixgbe_set_eee_capable(struct ixgbe_adapter *adapter)
break;
adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
break;
+ case IXGBE_DEV_ID_E610_BACKPLANE:
+ case IXGBE_DEV_ID_E610_SFP:
+ case IXGBE_DEV_ID_E610_10G_T:
+ case IXGBE_DEV_ID_E610_2_5G_T:
+ if (hw->dev_caps.common_cap.eee_support &&
+ hw->phy.eee_speeds_supported) {
+ adapter->flags2 |= IXGBE_FLAG2_EEE_CAPABLE;
+ /* For E610 adapters EEE should be enabled by default
+ * if the feature is supported by FW.
+ */
+ adapter->flags2 |= IXGBE_FLAG2_EEE_ENABLED;
+ break;
+ }
+ fallthrough;
default:
adapter->flags2 &= ~IXGBE_FLAG2_EEE_CAPABLE;
adapter->flags2 &= ~IXGBE_FLAG2_EEE_ENABLED;
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
u32 link_speed = adapter->link_speed;
+ struct ethtool_keee keee = {};
const char *speed_str;
bool flow_rx, flow_tx;
if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state))
ixgbe_ptp_start_cyclecounter(adapter);
+ netdev->ethtool_ops->get_eee(netdev, &keee);
+
switch (link_speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
speed_str = "10 Gbps";
speed_str = "unknown speed";
break;
}
- e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", speed_str,
+ e_info(drv, "NIC Link is Up %s, Flow Control: %s, EEE: %s\n", speed_str,
((flow_rx && flow_tx) ? "RX/TX" :
(flow_rx ? "RX" :
- (flow_tx ? "TX" : "None"))));
+ (flow_tx ? "TX" : "None"))),
+ str_on_off(keee.eee_enabled));
netif_carrier_on(netdev);
ixgbe_check_vf_rate_limit(adapter);
if (err)
goto err_netdev;
+ if (hw->mac.type == ixgbe_mac_e610 &&
+ (adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE)) {
+ bool eee_enable = adapter->flags2 & IXGBE_FLAG2_EEE_ENABLED;
+
+ hw->mac.ops.setup_eee(hw, eee_enable);
+ }
+
ixgbe_devlink_init_regions(adapter);
devl_register(adapter->devlink);
devl_unlock(adapter->devlink);