diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index a01d991ee2e0..665a9813e251 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -2013,6 +2013,45 @@ int ixgbe_identify_phy_e610(struct ixgbe_hw *hw) 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 @@ -4026,6 +4065,7 @@ static const struct ixgbe_mac_operations mac_ops_e610 = { .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, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h index 11916b979d28..2cb76a3d30ae 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h @@ -55,6 +55,7 @@ int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw); int ixgbe_identify_phy_e610(struct ixgbe_hw *hw); int ixgbe_identify_module_e610(struct ixgbe_hw *hw); int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw); +int ixgbe_setup_eee_e610(struct ixgbe_hw *hw, bool enable_eee); int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on); int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw); int ixgbe_init_eeprom_params_e610(struct ixgbe_hw *hw); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 186345933f3f..6990fe53f049 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "ixgbe.h" @@ -3540,7 +3541,7 @@ static const struct { { 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 }, }; @@ -3557,6 +3558,17 @@ static const struct { { 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) { @@ -3598,6 +3610,133 @@ static int ixgbe_validate_keee(struct net_device *netdev, 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) { @@ -3824,8 +3963,8 @@ static const struct ethtool_ops ixgbe_ethtool_ops_e610 = { .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, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 2646ee6f295f..9e1fb7383975 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6758,6 +6758,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /** * 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) @@ -6774,6 +6775,20 @@ 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; @@ -8082,6 +8097,7 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) 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; @@ -8122,6 +8138,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) 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"; @@ -8145,10 +8163,11 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) 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); @@ -12003,6 +12022,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 61f2ef67defd..01d0aa70b2b7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3524,6 +3524,7 @@ struct ixgbe_mac_operations { int (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); void (*set_rate_select_speed)(struct ixgbe_hw *, ixgbe_link_speed); + int (*setup_eee)(struct ixgbe_hw *hw, bool enable_eee); /* Packet Buffer Manipulation */ void (*set_rxpba)(struct ixgbe_hw *, int, u32, int);