diff mbox series

[iwl-next,v9,3/7] ixgbe: Add link management support for E610 device

Message ID 20241003141650.16524-4-piotr.kwapulinski@intel.com
State Under Review
Delegated to: Anthony Nguyen
Headers show
Series ixgbe: Add support for Intel(R) E610 device | expand

Commit Message

Piotr Kwapulinski Oct. 3, 2024, 2:16 p.m. UTC
Add low level link management support for E610 device. Link management
operations are handled via the Admin Command Interface. Add the following
link management operations:
- get link capabilities
- set up link
- get media type
- get link status, link status events
- link power management

Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Jan Glaza <jan.glaza@intel.com>
Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 1091 +++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   32 +
 .../ethernet/intel/ixgbe/ixgbe_type_e610.h    |    1 +
 3 files changed, 1124 insertions(+)

Comments

Simon Horman Oct. 17, 2024, 9:46 a.m. UTC | #1
On Thu, Oct 03, 2024 at 04:16:46PM +0200, Piotr Kwapulinski wrote:
> Add low level link management support for E610 device. Link management
> operations are handled via the Admin Command Interface. Add the following
> link management operations:
> - get link capabilities
> - set up link
> - get media type
> - get link status, link status events
> - link power management
> 
> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Reviewed-by: Jan Glaza <jan.glaza@intel.com>
> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>

Reviewed-by: Simon Horman <horms@kernel.org>
Kalesh Anakkur Purayil Oct. 17, 2024, 1:26 p.m. UTC | #2
On Thu, Oct 3, 2024 at 7:49 PM Piotr Kwapulinski
<piotr.kwapulinski@intel.com> wrote:
>
> Add low level link management support for E610 device. Link management
> operations are handled via the Admin Command Interface. Add the following
> link management operations:
> - get link capabilities
> - set up link
> - get media type
> - get link status, link status events
> - link power management
>
> Co-developed-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Signed-off-by: Stefan Wegrzyn <stefan.wegrzyn@intel.com>
> Co-developed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Signed-off-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
> Reviewed-by: Jan Glaza <jan.glaza@intel.com>
> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
> ---
>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 1091 +++++++++++++++++
>  drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h |   32 +
>  .../ethernet/intel/ixgbe/ixgbe_type_e610.h    |    1 +
>  3 files changed, 1124 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> index 3bc88df..c0c740f 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
> @@ -1033,3 +1033,1094 @@ void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>         cfg->module_compliance_enforcement =
>                 caps->module_compliance_enforcement;
>  }
> +
> +/**
> + * ixgbe_aci_set_phy_cfg - set PHY configuration
> + * @hw: pointer to the HW struct
> + * @cfg: structure with PHY configuration data to be set
> + *
> + * Set the various PHY configuration parameters supported on the Port
> + * using ACI command (0x0601).
> + * One or more of the Set PHY config parameters may be ignored in an MFP
> + * mode as the PF may not have the privilege to set some of the PHY Config
> + * parameters.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
> +                         struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
> +{
> +       struct ixgbe_aci_desc desc;
> +       int err;
> +
> +       if (!cfg)
> +               return -EINVAL;
> +
> +       /* Ensure that only valid bits of cfg->caps can be turned on. */
> +       cfg->caps &= IXGBE_ACI_PHY_ENA_VALID_MASK;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_phy_cfg);
> +       desc.params.set_phy.lport_num = hw->bus.func;
> +       desc.flags |= IXGBE_ACI_FLAG_RD;
> +
> +       err = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
> +
[Kalesh] There is no need of an empty line here
> +       if (!err)
> +               hw->phy.curr_user_phy_cfg = *cfg;
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_aci_set_link_restart_an - set up link and restart AN
> + * @hw: pointer to the HW struct
> + * @ena_link: if true: enable link, if false: disable link
> + *
> + * Function sets up the link and restarts the Auto-Negotiation over the link.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link)
> +{
> +       struct ixgbe_aci_cmd_restart_an *cmd;
> +       struct ixgbe_aci_desc desc;
> +
> +       cmd = &desc.params.restart_an;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_restart_an);
> +
> +       cmd->cmd_flags = IXGBE_ACI_RESTART_AN_LINK_RESTART;
> +       cmd->lport_num = hw->bus.func;
> +       if (ena_link)
> +               cmd->cmd_flags |= IXGBE_ACI_RESTART_AN_LINK_ENABLE;
> +       else
> +               cmd->cmd_flags &= ~IXGBE_ACI_RESTART_AN_LINK_ENABLE;
> +
> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
> +}
> +
> +/**
> + * ixgbe_is_media_cage_present - check if media cage is present
> + * @hw: pointer to the HW struct
> + *
> + * Identify presence of media cage using the ACI command (0x06E0).
> + *
> + * Return: true if media cage is present, else false. If no cage, then
> + * media type is backplane or BASE-T.
> + */
> +static bool ixgbe_is_media_cage_present(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_link_topo *cmd;
> +       struct ixgbe_aci_desc desc;
> +
> +       cmd = &desc.params.get_link_topo;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
> +
> +       cmd->addr.topo_params.node_type_ctx =
> +               FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_CTX_M,
> +                          IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT);
> +
> +       /* Set node type. */
> +       cmd->addr.topo_params.node_type_ctx |=
> +               FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_TYPE_M,
> +                          IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE);
> +
> +       /* Node type cage can be used to determine if cage is present. If AQC
> +        * returns error (ENOENT), then no cage present. If no cage present then
> +        * connection type is backplane or BASE-T.
> +        */
> +       return ixgbe_aci_get_netlist_node(hw, cmd, NULL, NULL);
> +}
> +
> +/**
> + * ixgbe_get_media_type_from_phy_type - Gets media type based on phy type
> + * @hw: pointer to the HW struct
> + *
> + * Try to identify the media type based on the phy type.
> + * If more than one media type, the ixgbe_media_type_unknown is returned.
> + * First, phy_type_low is checked, then phy_type_high.
> + * If none are identified, the ixgbe_media_type_unknown is returned
> + *
> + * Return: type of a media based on phy type in form of enum.
> + */
> +static enum ixgbe_media_type
> +ixgbe_get_media_type_from_phy_type(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_link_status *hw_link_info;
> +
> +       if (!hw)
> +               return ixgbe_media_type_unknown;
> +
> +       hw_link_info = &hw->link.link_info;
> +       if (hw_link_info->phy_type_low && hw_link_info->phy_type_high)
> +               /* If more than one media type is selected, report unknown */
> +               return ixgbe_media_type_unknown;
> +
> +       if (hw_link_info->phy_type_low) {
> +               /* 1G SGMII is a special case where some DA cable PHYs
> +                * may show this as an option when it really shouldn't
> +                * be since SGMII is meant to be between a MAC and a PHY
> +                * in a backplane. Try to detect this case and handle it
> +                */
> +               if (hw_link_info->phy_type_low == IXGBE_PHY_TYPE_LOW_1G_SGMII &&
> +                   (hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
> +                   IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE ||
> +                   hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
> +                   IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE))
> +                       return ixgbe_media_type_da;
> +
> +               switch (hw_link_info->phy_type_low) {
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_SX:
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_LX:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_SR:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_LR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_SR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_LR:
> +                       return ixgbe_media_type_fiber;
> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
> +               case IXGBE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
> +                       return ixgbe_media_type_fiber;
> +               case IXGBE_PHY_TYPE_LOW_100BASE_TX:
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_T:
> +               case IXGBE_PHY_TYPE_LOW_2500BASE_T:
> +               case IXGBE_PHY_TYPE_LOW_5GBASE_T:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_T:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_T:
> +                       return ixgbe_media_type_copper;
> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_DA:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR_S:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_CR1:
> +                       return ixgbe_media_type_da;
> +               case IXGBE_PHY_TYPE_LOW_25G_AUI_C2C:
> +                       if (ixgbe_is_media_cage_present(hw))
> +                               return ixgbe_media_type_aui;
> +                       fallthrough;
> +               case IXGBE_PHY_TYPE_LOW_1000BASE_KX:
> +               case IXGBE_PHY_TYPE_LOW_2500BASE_KX:
> +               case IXGBE_PHY_TYPE_LOW_2500BASE_X:
> +               case IXGBE_PHY_TYPE_LOW_5GBASE_KR:
> +               case IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1:
> +               case IXGBE_PHY_TYPE_LOW_10G_SFI_C2C:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR1:
> +               case IXGBE_PHY_TYPE_LOW_25GBASE_KR_S:
> +                       return ixgbe_media_type_backplane;
> +               }
> +       } else {
> +               switch (hw_link_info->phy_type_high) {
> +               case IXGBE_PHY_TYPE_HIGH_10BASE_T:
> +                       return ixgbe_media_type_copper;
> +               }
> +       }
> +       return ixgbe_media_type_unknown;
> +}
> +
> +/**
> + * ixgbe_update_link_info - update status of the HW network link
> + * @hw: pointer to the HW struct
> + *
> + * Update the status of the HW network link.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_update_link_info(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_link_status *li;
> +       int err;
> +
> +       if (!hw)
> +               return -EINVAL;
> +
> +       li = &hw->link.link_info;
> +
> +       err = ixgbe_aci_get_link_info(hw, true, NULL);
> +       if (err)
> +               return err;
> +
> +       if (li->link_info & IXGBE_ACI_MEDIA_AVAILABLE) {
[Kalesh] If you change the check as below, that would help code indentation:
if (!(li->link_info & IXGBE_ACI_MEDIA_AVAILABLE))
      return 0;
> +               struct ixgbe_aci_cmd_get_phy_caps_data __free(kfree) *pcaps;
> +
> +               pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
> +               if (!pcaps)
> +                       return -ENOMEM;
> +
> +               err = ixgbe_aci_get_phy_caps(hw, false,
> +                                            IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
> +                                            pcaps);
> +
> +               if (!err)
> +                       memcpy(li->module_type, &pcaps->module_type,
> +                              sizeof(li->module_type));
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_get_link_status - get status of the HW network link
> + * @hw: pointer to the HW struct
> + * @link_up: pointer to bool (true/false = linkup/linkdown)
> + *
> + * Variable link_up is true if link is up, false if link is down.
> + * The variable link_up is invalid if status is non zero. As a
> + * result of this call, link status reporting becomes enabled
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up)
> +{
> +       if (!hw || !link_up)
> +               return -EINVAL;
> +
> +       if (hw->link.get_link_info) {
> +               int err = ixgbe_update_link_info(hw);
> +
> +               if (err)
> +                       return err;
> +       }
> +
> +       *link_up = hw->link.link_info.link_info & IXGBE_ACI_LINK_UP;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_aci_get_link_info - get the link status
> + * @hw: pointer to the HW struct
> + * @ena_lse: enable/disable LinkStatusEvent reporting
> + * @link: pointer to link status structure - optional
> + *
> + * Get the current Link Status using ACI command (0x607).
> + * The current link can be optionally provided to update
> + * the status.
> + *
> + * Return: the link status of the adapter.
> + */
> +int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
> +                           struct ixgbe_link_status *link)
> +{
> +       struct ixgbe_aci_cmd_get_link_status_data link_data = { 0 };
> +       struct ixgbe_aci_cmd_get_link_status *resp;
> +       struct ixgbe_link_status *li_old, *li;
> +       struct ixgbe_fc_info *hw_fc_info;
> +       struct ixgbe_aci_desc desc;
> +       bool tx_pause, rx_pause;
> +       u8 cmd_flags;
> +       int err;
> +
> +       if (!hw)
> +               return -EINVAL;
> +
> +       li_old = &hw->link.link_info_old;
> +       li = &hw->link.link_info;
> +       hw_fc_info = &hw->fc;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_status);
> +       cmd_flags = (ena_lse) ? IXGBE_ACI_LSE_ENA : IXGBE_ACI_LSE_DIS;
> +       resp = &desc.params.get_link_status;
> +       resp->cmd_flags = cmd_flags;
> +       resp->lport_num = hw->bus.func;
> +
> +       err = ixgbe_aci_send_cmd(hw, &desc, &link_data, sizeof(link_data));
> +
[Kalesh] there is no need of empty line here
> +       if (err)
> +               return err;
> +
> +       /* Save off old link status information. */
> +       *li_old = *li;
> +
> +       /* Update current link status information. */
> +       li->link_speed = link_data.link_speed;
> +       li->phy_type_low = link_data.phy_type_low;
> +       li->phy_type_high = link_data.phy_type_high;
> +       li->link_info = link_data.link_info;
> +       li->link_cfg_err = link_data.link_cfg_err;
> +       li->an_info = link_data.an_info;
> +       li->ext_info = link_data.ext_info;
> +       li->max_frame_size = link_data.max_frame_size;
> +       li->fec_info = link_data.cfg & IXGBE_ACI_FEC_MASK;
> +       li->topo_media_conflict = link_data.topo_media_conflict;
> +       li->pacing = link_data.cfg & (IXGBE_ACI_CFG_PACING_M |
> +                                     IXGBE_ACI_CFG_PACING_TYPE_M);
> +
> +       /* Update fc info. */
> +       tx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_TX);
> +       rx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_RX);
> +       if (tx_pause && rx_pause)
> +               hw_fc_info->current_mode = ixgbe_fc_full;
> +       else if (tx_pause)
> +               hw_fc_info->current_mode = ixgbe_fc_tx_pause;
> +       else if (rx_pause)
> +               hw_fc_info->current_mode = ixgbe_fc_rx_pause;
> +       else
> +               hw_fc_info->current_mode = ixgbe_fc_none;
> +
> +       li->lse_ena = !!(resp->cmd_flags & IXGBE_ACI_LSE_IS_ENABLED);
> +
> +       /* Save link status information. */
> +       if (link)
> +               *link = *li;
> +
> +       /* Flag cleared so calling functions don't call AQ again. */
> +       hw->link.get_link_info = false;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_aci_set_event_mask - set event mask
> + * @hw: pointer to the HW struct
> + * @port_num: port number of the physical function
> + * @mask: event mask to be set
> + *
> + * Set the event mask using ACI command (0x0613).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask)
> +{
> +       struct ixgbe_aci_cmd_set_event_mask *cmd;
> +       struct ixgbe_aci_desc desc;
> +
> +       cmd = &desc.params.set_event_mask;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_event_mask);
> +
> +       cmd->lport_num = port_num;
> +
> +       cmd->event_mask = mask;
> +       return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
> +}
> +
> +/**
> + * ixgbe_configure_lse - enable/disable link status events
> + * @hw: pointer to the HW struct
> + * @activate: true for enable lse, false otherwise
> + * @mask: event mask to be set; a set bit means deactivation of the
> + * corresponding event
> + *
> + * Set the event mask and then enable or disable link status events
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask)
> +{
> +       int err;
> +
> +       err = ixgbe_aci_set_event_mask(hw, (u8)hw->bus.func, mask);
> +       if (err)
> +               return err;
> +
> +       /* Enabling link status events generation by fw */
> +       err = ixgbe_aci_get_link_info(hw, activate, NULL);
[Kalesh] You can simplify this as:
return ixgbe_aci_get_link_info(hw, activate, NULL);
> +       if (err)
> +               return err;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_get_media_type_e610 - Gets media type
> + * @hw: pointer to the HW struct
> + *
> + * In order to get the media type, the function gets PHY
> + * capabilities and later on use them to identify the PHY type
> + * checking phy_type_high and phy_type_low.
> + *
> + * Return: the type of media in form of ixgbe_media_type enum
> + * or ixgbe_media_type_unknown in case of an error.
> + */
> +enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
> +       int rc;
> +
> +       rc = ixgbe_update_link_info(hw);
> +       if (rc)
> +               return ixgbe_media_type_unknown;
> +
> +       /* If there is no link but PHY (dongle) is available SW should use
> +        * Get PHY Caps admin command instead of Get Link Status, find most
> +        * significant bit that is set in PHY types reported by the command
> +        * and use it to discover media type.
> +        */
> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP) &&
> +           (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE)) {
> +               int highest_bit;
> +
> +               /* Get PHY Capabilities */
> +               rc = ixgbe_aci_get_phy_caps(hw, false,
> +                                           IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
> +                                           &pcaps);
> +               if (rc)
> +                       return ixgbe_media_type_unknown;
> +
> +               highest_bit = fls64(pcaps.phy_type_high);
> +               if (highest_bit) {
> +                       hw->link.link_info.phy_type_high =
> +                               BIT_ULL(highest_bit - 1);
> +                       hw->link.link_info.phy_type_low = 0;
> +               } else {
> +                       highest_bit = fls64(pcaps.phy_type_low);
> +                       if (highest_bit)
> +                               hw->link.link_info.phy_type_low =
> +                                       BIT_ULL(highest_bit - 1);
> +               }
> +       }
> +
> +       /* Based on link status or search above try to discover media type. */
> +       hw->phy.media_type = ixgbe_get_media_type_from_phy_type(hw);
> +
> +       return hw->phy.media_type;
> +}
> +
> +/**
> + * ixgbe_setup_link_e610 - Set up link
> + * @hw: pointer to hardware structure
> + * @speed: new link speed
> + * @autoneg_wait: true when waiting for completion is needed
> + *
> + * Set up the link with the specified speed.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
> +                         bool autoneg_wait)
> +{
> +       /* Simply request FW to perform proper PHY setup */
> +       return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
> +}
> +
> +/**
> + * ixgbe_check_link_e610 - Determine link and speed status
> + * @hw: pointer to hardware structure
> + * @speed: pointer to link speed
> + * @link_up: true when link is up
> + * @link_up_wait_to_complete: bool used to wait for link up or not
> + *
> + * Determine if the link is up and the current link speed
> + * using ACI command (0x0607).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
> +                         bool *link_up, bool link_up_wait_to_complete)
> +{
> +       int err;
> +       u32 i;
> +
> +       if (!speed || !link_up)
> +               return -EINVAL;
> +
> +       /* Set get_link_info flag to ensure that fresh
> +        * link information will be obtained from FW
> +        * by sending Get Link Status admin command.
> +        */
> +       hw->link.get_link_info = true;
> +
> +       /* Update link information in adapter context. */
> +       err = ixgbe_get_link_status(hw, link_up);
> +       if (err)
> +               return err;
> +
> +       /* Wait for link up if it was requested. */
> +       if (link_up_wait_to_complete && !(*link_up)) {
> +               for (i = 0; i < hw->mac.max_link_up_time; i++) {
> +                       msleep(100);
> +                       hw->link.get_link_info = true;
> +                       err = ixgbe_get_link_status(hw, link_up);
> +                       if (err)
> +                               return err;
> +                       if (*link_up)
> +                               break;
> +               }
> +       }
> +
> +       /* Use link information in adapter context updated by the call
> +        * to ixgbe_get_link_status() to determine current link speed.
> +        * Link speed information is valid only when link up was
> +        * reported by FW.
> +        */
> +       if (*link_up) {
> +               switch (hw->link.link_info.link_speed) {
> +               case IXGBE_ACI_LINK_SPEED_10MB:
> +                       *speed = IXGBE_LINK_SPEED_10_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_100MB:
> +                       *speed = IXGBE_LINK_SPEED_100_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_1000MB:
> +                       *speed = IXGBE_LINK_SPEED_1GB_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_2500MB:
> +                       *speed = IXGBE_LINK_SPEED_2_5GB_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_5GB:
> +                       *speed = IXGBE_LINK_SPEED_5GB_FULL;
> +                       break;
> +               case IXGBE_ACI_LINK_SPEED_10GB:
> +                       *speed = IXGBE_LINK_SPEED_10GB_FULL;
> +                       break;
> +               default:
> +                       *speed = IXGBE_LINK_SPEED_UNKNOWN;
> +                       break;
> +               }
> +       } else {
> +               *speed = IXGBE_LINK_SPEED_UNKNOWN;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_get_link_capabilities_e610 - Determine link capabilities
> + * @hw: pointer to hardware structure
> + * @speed: pointer to link speed
> + * @autoneg: true when autoneg or autotry is enabled
> + *
> + * Determine speed and AN parameters of a link.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
> +                                    ixgbe_link_speed *speed,
> +                                    bool *autoneg)
> +{
> +       if (!speed || !autoneg)
> +               return -EINVAL;
> +
> +       *autoneg = true;
> +       *speed = hw->phy.speeds_supported;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_cfg_phy_fc - Configure PHY Flow Control (FC) data based on FC mode
> + * @hw: pointer to hardware structure
> + * @cfg: PHY configuration data to set FC mode
> + * @req_mode: FC mode to configure
> + *
> + * Configures PHY Flow Control according to the provided configuration.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
> +                    struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
> +                    enum ixgbe_fc_mode req_mode)
> +{
> +       u8 pause_mask = 0x0;
> +
> +       if (!cfg)
> +               return -EINVAL;
> +
> +       switch (req_mode) {
> +       case ixgbe_fc_full:
> +               pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
> +               pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
> +               break;
> +       case ixgbe_fc_rx_pause:
> +               pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
> +               break;
> +       case ixgbe_fc_tx_pause:
> +               pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
> +               break;
> +       default:
> +               break;
> +       }
> +
> +       /* Clear the old pause settings. */
> +       cfg->caps &= ~(IXGBE_ACI_PHY_EN_TX_LINK_PAUSE |
> +               IXGBE_ACI_PHY_EN_RX_LINK_PAUSE);
> +
> +       /* Set the new capabilities. */
> +       cfg->caps |= pause_mask;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_setup_fc_e610 - Set up flow control
> + * @hw: pointer to hardware structure
> + *
> + * Set up flow control. This has to be done during init time.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_setup_fc_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps = { 0 };
> +       struct ixgbe_aci_cmd_set_phy_cfg_data cfg = { 0 };
> +       int err;
> +
> +       /* Get the current PHY config */
> +       err = ixgbe_aci_get_phy_caps(hw, false,
> +                                    IXGBE_ACI_REPORT_ACTIVE_CFG, &pcaps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_copy_phy_caps_to_cfg(&pcaps, &cfg);
> +
> +       /* Configure the set PHY data */
> +       err = ixgbe_cfg_phy_fc(hw, &cfg, hw->fc.requested_mode);
> +       if (err)
> +               return err;
> +
> +       /* If the capabilities have changed, then set the new config */
> +       if (cfg.caps != pcaps.caps) {
> +               cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
> +
> +               err = ixgbe_aci_set_phy_cfg(hw, &cfg);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_fc_autoneg_e610 - Configure flow control
> + * @hw: pointer to hardware structure
> + *
> + * Configure Flow Control.
> + */
> +void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw)
> +{
> +       int err;
> +
> +       /* Get current link err.
> +        * Current FC mode will be stored in the hw context.
> +        */
> +       err = ixgbe_aci_get_link_info(hw, false, NULL);
> +       if (err)
> +               goto no_autoneg;
> +
> +       /* Check if the link is up */
> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP))
> +               goto no_autoneg;
> +
> +       /* Check if auto-negotiation has completed */
> +       if (!(hw->link.link_info.an_info & IXGBE_ACI_AN_COMPLETED))
> +               goto no_autoneg;
> +
> +       hw->fc.fc_was_autonegged = true;
> +       return;
> +
> +no_autoneg:
> +       hw->fc.fc_was_autonegged = false;
> +       hw->fc.current_mode = hw->fc.requested_mode;
> +}
> +
> +/**
> + * ixgbe_disable_rx_e610 - Disable RX unit
> + * @hw: pointer to hardware structure
> + *
> + * Disable RX DMA unit on E610 with use of ACI command (0x000C).
> + *
> + * Return: the exit code of the operation.
> + */
> +void ixgbe_disable_rx_e610(struct ixgbe_hw *hw)
> +{
> +       u32 rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
> +       u32 pfdtxgswc;
> +       int err;
> +
> +       if (!(rxctrl & IXGBE_RXCTRL_RXEN))
> +               return;
> +
> +       pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
> +       if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
> +               pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
> +               IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
> +               hw->mac.set_lben = true;
> +       } else {
> +               hw->mac.set_lben = false;
> +       }
> +
> +       err = ixgbe_aci_disable_rxen(hw);
> +
> +       /* If we fail - disable RX using register write */
> +       if (err) {
> +               rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
> +               if (rxctrl & IXGBE_RXCTRL_RXEN) {
> +                       rxctrl &= ~IXGBE_RXCTRL_RXEN;
> +                       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
> +               }
> +       }
> +}
> +
> +/**
> + * ixgbe_init_phy_ops_e610 - PHY specific init
> + * @hw: pointer to hardware structure
> + *
> + * Initialize any function pointers that were not able to be
> + * set during init_shared_code because the PHY type was not known.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_mac_info *mac = &hw->mac;
> +       struct ixgbe_phy_info *phy = &hw->phy;
> +       int ret_val;
> +
> +       if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
> +               phy->ops.set_phy_power = ixgbe_set_phy_power_e610;
> +       else
> +               phy->ops.set_phy_power = NULL;
> +
> +       /* Identify the PHY */
> +       ret_val = phy->ops.identify(hw);
[Kalesh] You can change it to:
return phy->ops.identify(hw);
> +       if (ret_val)
> +               return ret_val;
> +
> +       return ret_val;
> +}
> +
> +/**
> + * ixgbe_identify_phy_e610 - Identify PHY
> + * @hw: pointer to hardware structure
> + *
> + * Determine PHY type, supported speeds and PHY ID.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_identify_phy_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
> +       int err;
> +
> +       /* Set PHY type */
> +       hw->phy.type = ixgbe_phy_fw;
> +
> +       err = ixgbe_aci_get_phy_caps(hw, false,
> +                                    IXGBE_ACI_REPORT_TOPO_CAP_MEDIA, &pcaps);
> +       if (err)
> +               return err;
> +
> +       if (!(pcaps.module_compliance_enforcement &
> +             IXGBE_ACI_MOD_ENFORCE_STRICT_MODE)) {
> +               /* Handle lenient mode */
> +               err = ixgbe_aci_get_phy_caps(hw, false,
> +                                            IXGBE_ACI_REPORT_TOPO_CAP_NO_MEDIA,
> +                                            &pcaps);
> +               if (err)
> +                       return err;
> +       }
> +
> +       /* Determine supported speeds */
> +       hw->phy.speeds_supported = IXGBE_LINK_SPEED_UNKNOWN;
> +
> +       if (pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10BASE_T ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10M_SGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10_FULL;
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100BASE_TX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100M_SGMII ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_100M_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_T  ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_SX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_LX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_KX ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1G_SGMII    ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_1G_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_T       ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_DA      ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_SR      ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_LR      ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1  ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_C2C     ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10G_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
> +
> +       /* 2.5 and 5 Gbps link speeds must be excluded from the
> +        * auto-negotiation set used during driver initialization due to
> +        * compatibility issues with certain switches. Those issues do not
> +        * exist in case of E610 2.5G SKU device (0x57b1).
> +        */
> +       if (!hw->phy.autoneg_advertised &&
> +           hw->device_id != IXGBE_DEV_ID_E610_2_5G_T)
> +               hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
> +
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_T   ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_X   ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_KX  ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_SGMII ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
> +
> +       if (!hw->phy.autoneg_advertised &&
> +           hw->device_id == IXGBE_DEV_ID_E610_2_5G_T)
> +               hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
> +
> +       if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_T  ||
> +           pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_KR ||
> +           pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_5G_USXGMII)
> +               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
> +
> +       /* Set PHY ID */
> +       memcpy(&hw->phy.id, pcaps.phy_id_oui, sizeof(u32));
> +
> +       hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_10_FULL |
> +                                      IXGBE_LINK_SPEED_100_FULL |
> +                                      IXGBE_LINK_SPEED_1GB_FULL;
> +       hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_identify_module_e610 - Identify SFP module type
> + * @hw: pointer to hardware structure
> + *
> + * Identify the SFP module type.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_identify_module_e610(struct ixgbe_hw *hw)
> +{
> +       bool media_available;
> +       u8 module_type;
> +       int err;
> +
> +       err = ixgbe_update_link_info(hw);
> +       if (err)
> +               return err;
> +
> +       media_available =
> +               (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE);
> +
> +       if (media_available) {
> +               hw->phy.sfp_type = ixgbe_sfp_type_unknown;
> +
> +               /* Get module type from hw context updated by
> +                * ixgbe_update_link_info()
> +                */
> +               module_type = hw->link.link_info.module_type[IXGBE_ACI_MOD_TYPE_IDENT];
> +
> +               if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE) ||
> +                   (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE)) {
> +                       hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
> +               } else if (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_SR) {
> +                       hw->phy.sfp_type = ixgbe_sfp_type_sr;
> +               } else if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LR) ||
> +                          (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LRM)) {
> +                       hw->phy.sfp_type = ixgbe_sfp_type_lr;
> +               }
> +       } else {
> +               hw->phy.sfp_type = ixgbe_sfp_type_not_present;
> +               return -ENOENT;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_setup_phy_link_e610 - Sets up firmware-controlled PHYs
> + * @hw: pointer to hardware structure
> + *
> + * Set the parameters for the firmware-controlled PHYs.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
> +       struct ixgbe_aci_cmd_set_phy_cfg_data pcfg;
> +       u8 rmode = IXGBE_ACI_REPORT_TOPO_CAP_MEDIA;
> +       u64 sup_phy_type_low, sup_phy_type_high;
> +       int err;
> +
> +       err = ixgbe_aci_get_link_info(hw, false, NULL);
> +       if (err)
> +               return err;
> +
> +       /* If media is not available get default config. */
> +       if (!(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE))
> +               rmode = IXGBE_ACI_REPORT_DFLT_CFG;
> +
> +       err = ixgbe_aci_get_phy_caps(hw, false, rmode, &pcaps);
> +       if (err)
> +               return err;
> +
> +       sup_phy_type_low = pcaps.phy_type_low;
> +       sup_phy_type_high = pcaps.phy_type_high;
> +
> +       /* Get Active configuration to avoid unintended changes. */
> +       err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
> +                                    &pcaps);
> +       if (err)
> +               return err;
> +
> +       ixgbe_copy_phy_caps_to_cfg(&pcaps, &pcfg);
> +
> +       /* Set default PHY types for a given speed */
> +       pcfg.phy_type_low = 0;
> +       pcfg.phy_type_high = 0;
> +
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL) {
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10BASE_T;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10M_SGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100BASE_TX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100M_SGMII;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_100M_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_SX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_LX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_KX;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1G_SGMII;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_1G_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_X;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_KX;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_SGMII;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_KR;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_5G_USXGMII;
> +       }
> +       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) {
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_T;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_DA;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_SR;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_LR;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC;
> +               pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_C2C;
> +               pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10G_USXGMII;
> +       }
> +
> +       /* Mask the set values to avoid requesting unsupported link types */
> +       pcfg.phy_type_low &= sup_phy_type_low;
> +       pcfg.phy_type_high &= sup_phy_type_high;
> +
> +       if (pcfg.phy_type_high != pcaps.phy_type_high ||
> +           pcfg.phy_type_low != pcaps.phy_type_low ||
> +           pcfg.caps != pcaps.caps) {
> +               pcfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
> +               pcfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
> +
> +               err = ixgbe_aci_set_phy_cfg(hw, &pcfg);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * ixgbe_set_phy_power_e610 - Control power for copper PHY
> + * @hw: pointer to hardware structure
> + * @on: true for on, false for off
> + *
> + * Set the power on/off of the PHY
> + * by getting its capabilities and setting the appropriate
> + * configuration parameters.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
> +       struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 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);
> +
> +       if (on)
> +               phy_cfg.caps &= ~IXGBE_ACI_PHY_ENA_LOW_POWER;
> +       else
> +               phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LOW_POWER;
> +
> +       /* PHY is already in requested power mode. */
> +       if (phy_caps.caps == phy_cfg.caps)
> +               return 0;
> +
> +       phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
> +       phy_cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
> +
> +       err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
[Kalesh] Change it as:
return  ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_enter_lplu_e610 - Transition to low power states
> + * @hw: pointer to hardware structure
> + *
> + * Configures Low Power Link Up on transition to low power states
> + * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
> + * X557 PHY immediately prior to entering LPLU.
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw)
> +{
> +       struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
> +       struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 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.low_power_ctrl_an |= IXGBE_ACI_PHY_EN_D3COLD_LOW_POWER_AUTONEG;
> +
> +       err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
[Kalesh] Same comment as above
> +
> +       return err;
> +}
> +
> +/**
> + * ixgbe_aci_get_netlist_node - get a node handle
> + * @hw: pointer to the hw struct
> + * @cmd: get_link_topo AQ structure
> + * @node_part_number: output node part number if node found
> + * @node_handle: output node handle parameter if node found
> + *
> + * Get the netlist node and assigns it to
> + * the provided handle using ACI command (0x06E0).
> + *
> + * Return: the exit code of the operation.
> + */
> +int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
> +                              struct ixgbe_aci_cmd_get_link_topo *cmd,
> +                              u8 *node_part_number, u16 *node_handle)
> +{
> +       struct ixgbe_aci_desc desc;
> +
> +       ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
> +       desc.params.get_link_topo = *cmd;
> +
> +       if (ixgbe_aci_send_cmd(hw, &desc, NULL, 0))
> +               return -EOPNOTSUPP;
> +
> +       if (node_handle)
> +               *node_handle = desc.params.get_link_topo.addr.handle;
> +       if (node_part_number)
> +               *node_part_number = desc.params.get_link_topo.node_part_num;
> +
> +       return 0;
> +}
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> index 5c5a676..4a4f969 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
> @@ -27,5 +27,37 @@ int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
>                            struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
>  void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
>                                 struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
> +int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
> +                         struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
> +int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link);
> +int ixgbe_update_link_info(struct ixgbe_hw *hw);
> +int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up);
> +int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
> +                           struct ixgbe_link_status *link);
> +int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask);
> +int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask);
> +enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw);
> +int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
> +                         bool autoneg_wait);
> +int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
> +                         bool *link_up, bool link_up_wait_to_complete);
> +int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
> +                                    ixgbe_link_speed *speed,
> +                                    bool *autoneg);
> +int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
> +                    struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
> +                    enum ixgbe_fc_mode req_mode);
> +int ixgbe_setup_fc_e610(struct ixgbe_hw *hw);
> +void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw);
> +void ixgbe_disable_rx_e610(struct ixgbe_hw *hw);
> +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_set_phy_power_e610(struct ixgbe_hw *hw, bool on);
> +int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
> +int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
> +                              struct ixgbe_aci_cmd_get_link_topo *cmd,
> +                              u8 *node_part_number, u16 *node_handle);
>
>  #endif /* _IXGBE_E610_H_ */
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
> index 6c6d990..1f97652 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
> @@ -652,6 +652,7 @@ struct ixgbe_aci_cmd_link_topo_params {
>  #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CLK_MUX  10
>  #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_GPS      11
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_S         4
> +#define IXGBE_ACI_LINK_TOPO_NODE_CTX_M         GENMASK(7, 4)
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_GLOBAL                    0
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_BOARD                     1
>  #define IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT                      2
> --
> 2.43.0
>
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
index 3bc88df..c0c740f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c
@@ -1033,3 +1033,1094 @@  void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
 	cfg->module_compliance_enforcement =
 		caps->module_compliance_enforcement;
 }
+
+/**
+ * ixgbe_aci_set_phy_cfg - set PHY configuration
+ * @hw: pointer to the HW struct
+ * @cfg: structure with PHY configuration data to be set
+ *
+ * Set the various PHY configuration parameters supported on the Port
+ * using ACI command (0x0601).
+ * One or more of the Set PHY config parameters may be ignored in an MFP
+ * mode as the PF may not have the privilege to set some of the PHY Config
+ * parameters.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
+			  struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
+{
+	struct ixgbe_aci_desc desc;
+	int err;
+
+	if (!cfg)
+		return -EINVAL;
+
+	/* Ensure that only valid bits of cfg->caps can be turned on. */
+	cfg->caps &= IXGBE_ACI_PHY_ENA_VALID_MASK;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_phy_cfg);
+	desc.params.set_phy.lport_num = hw->bus.func;
+	desc.flags |= IXGBE_ACI_FLAG_RD;
+
+	err = ixgbe_aci_send_cmd(hw, &desc, cfg, sizeof(*cfg));
+
+	if (!err)
+		hw->phy.curr_user_phy_cfg = *cfg;
+
+	return err;
+}
+
+/**
+ * ixgbe_aci_set_link_restart_an - set up link and restart AN
+ * @hw: pointer to the HW struct
+ * @ena_link: if true: enable link, if false: disable link
+ *
+ * Function sets up the link and restarts the Auto-Negotiation over the link.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link)
+{
+	struct ixgbe_aci_cmd_restart_an *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.restart_an;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_restart_an);
+
+	cmd->cmd_flags = IXGBE_ACI_RESTART_AN_LINK_RESTART;
+	cmd->lport_num = hw->bus.func;
+	if (ena_link)
+		cmd->cmd_flags |= IXGBE_ACI_RESTART_AN_LINK_ENABLE;
+	else
+		cmd->cmd_flags &= ~IXGBE_ACI_RESTART_AN_LINK_ENABLE;
+
+	return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+}
+
+/**
+ * ixgbe_is_media_cage_present - check if media cage is present
+ * @hw: pointer to the HW struct
+ *
+ * Identify presence of media cage using the ACI command (0x06E0).
+ *
+ * Return: true if media cage is present, else false. If no cage, then
+ * media type is backplane or BASE-T.
+ */
+static bool ixgbe_is_media_cage_present(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_link_topo *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.get_link_topo;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
+
+	cmd->addr.topo_params.node_type_ctx =
+		FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_CTX_M,
+			   IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT);
+
+	/* Set node type. */
+	cmd->addr.topo_params.node_type_ctx |=
+		FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_TYPE_M,
+			   IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE);
+
+	/* Node type cage can be used to determine if cage is present. If AQC
+	 * returns error (ENOENT), then no cage present. If no cage present then
+	 * connection type is backplane or BASE-T.
+	 */
+	return ixgbe_aci_get_netlist_node(hw, cmd, NULL, NULL);
+}
+
+/**
+ * ixgbe_get_media_type_from_phy_type - Gets media type based on phy type
+ * @hw: pointer to the HW struct
+ *
+ * Try to identify the media type based on the phy type.
+ * If more than one media type, the ixgbe_media_type_unknown is returned.
+ * First, phy_type_low is checked, then phy_type_high.
+ * If none are identified, the ixgbe_media_type_unknown is returned
+ *
+ * Return: type of a media based on phy type in form of enum.
+ */
+static enum ixgbe_media_type
+ixgbe_get_media_type_from_phy_type(struct ixgbe_hw *hw)
+{
+	struct ixgbe_link_status *hw_link_info;
+
+	if (!hw)
+		return ixgbe_media_type_unknown;
+
+	hw_link_info = &hw->link.link_info;
+	if (hw_link_info->phy_type_low && hw_link_info->phy_type_high)
+		/* If more than one media type is selected, report unknown */
+		return ixgbe_media_type_unknown;
+
+	if (hw_link_info->phy_type_low) {
+		/* 1G SGMII is a special case where some DA cable PHYs
+		 * may show this as an option when it really shouldn't
+		 * be since SGMII is meant to be between a MAC and a PHY
+		 * in a backplane. Try to detect this case and handle it
+		 */
+		if (hw_link_info->phy_type_low == IXGBE_PHY_TYPE_LOW_1G_SGMII &&
+		    (hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
+		    IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE ||
+		    hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
+		    IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE))
+			return ixgbe_media_type_da;
+
+		switch (hw_link_info->phy_type_low) {
+		case IXGBE_PHY_TYPE_LOW_1000BASE_SX:
+		case IXGBE_PHY_TYPE_LOW_1000BASE_LX:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_SR:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_LR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_SR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_LR:
+			return ixgbe_media_type_fiber;
+		case IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
+		case IXGBE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
+			return ixgbe_media_type_fiber;
+		case IXGBE_PHY_TYPE_LOW_100BASE_TX:
+		case IXGBE_PHY_TYPE_LOW_1000BASE_T:
+		case IXGBE_PHY_TYPE_LOW_2500BASE_T:
+		case IXGBE_PHY_TYPE_LOW_5GBASE_T:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_T:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_T:
+			return ixgbe_media_type_copper;
+		case IXGBE_PHY_TYPE_LOW_10G_SFI_DA:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_CR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_CR_S:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_CR1:
+			return ixgbe_media_type_da;
+		case IXGBE_PHY_TYPE_LOW_25G_AUI_C2C:
+			if (ixgbe_is_media_cage_present(hw))
+				return ixgbe_media_type_aui;
+			fallthrough;
+		case IXGBE_PHY_TYPE_LOW_1000BASE_KX:
+		case IXGBE_PHY_TYPE_LOW_2500BASE_KX:
+		case IXGBE_PHY_TYPE_LOW_2500BASE_X:
+		case IXGBE_PHY_TYPE_LOW_5GBASE_KR:
+		case IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1:
+		case IXGBE_PHY_TYPE_LOW_10G_SFI_C2C:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_KR:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_KR1:
+		case IXGBE_PHY_TYPE_LOW_25GBASE_KR_S:
+			return ixgbe_media_type_backplane;
+		}
+	} else {
+		switch (hw_link_info->phy_type_high) {
+		case IXGBE_PHY_TYPE_HIGH_10BASE_T:
+			return ixgbe_media_type_copper;
+		}
+	}
+	return ixgbe_media_type_unknown;
+}
+
+/**
+ * ixgbe_update_link_info - update status of the HW network link
+ * @hw: pointer to the HW struct
+ *
+ * Update the status of the HW network link.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_update_link_info(struct ixgbe_hw *hw)
+{
+	struct ixgbe_link_status *li;
+	int err;
+
+	if (!hw)
+		return -EINVAL;
+
+	li = &hw->link.link_info;
+
+	err = ixgbe_aci_get_link_info(hw, true, NULL);
+	if (err)
+		return err;
+
+	if (li->link_info & IXGBE_ACI_MEDIA_AVAILABLE) {
+		struct ixgbe_aci_cmd_get_phy_caps_data __free(kfree) *pcaps;
+
+		pcaps =	kzalloc(sizeof(*pcaps), GFP_KERNEL);
+		if (!pcaps)
+			return -ENOMEM;
+
+		err = ixgbe_aci_get_phy_caps(hw, false,
+					     IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
+					     pcaps);
+
+		if (!err)
+			memcpy(li->module_type, &pcaps->module_type,
+			       sizeof(li->module_type));
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_get_link_status - get status of the HW network link
+ * @hw: pointer to the HW struct
+ * @link_up: pointer to bool (true/false = linkup/linkdown)
+ *
+ * Variable link_up is true if link is up, false if link is down.
+ * The variable link_up is invalid if status is non zero. As a
+ * result of this call, link status reporting becomes enabled
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up)
+{
+	if (!hw || !link_up)
+		return -EINVAL;
+
+	if (hw->link.get_link_info) {
+		int err = ixgbe_update_link_info(hw);
+
+		if (err)
+			return err;
+	}
+
+	*link_up = hw->link.link_info.link_info & IXGBE_ACI_LINK_UP;
+
+	return 0;
+}
+
+/**
+ * ixgbe_aci_get_link_info - get the link status
+ * @hw: pointer to the HW struct
+ * @ena_lse: enable/disable LinkStatusEvent reporting
+ * @link: pointer to link status structure - optional
+ *
+ * Get the current Link Status using ACI command (0x607).
+ * The current link can be optionally provided to update
+ * the status.
+ *
+ * Return: the link status of the adapter.
+ */
+int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
+			    struct ixgbe_link_status *link)
+{
+	struct ixgbe_aci_cmd_get_link_status_data link_data = { 0 };
+	struct ixgbe_aci_cmd_get_link_status *resp;
+	struct ixgbe_link_status *li_old, *li;
+	struct ixgbe_fc_info *hw_fc_info;
+	struct ixgbe_aci_desc desc;
+	bool tx_pause, rx_pause;
+	u8 cmd_flags;
+	int err;
+
+	if (!hw)
+		return -EINVAL;
+
+	li_old = &hw->link.link_info_old;
+	li = &hw->link.link_info;
+	hw_fc_info = &hw->fc;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_status);
+	cmd_flags = (ena_lse) ? IXGBE_ACI_LSE_ENA : IXGBE_ACI_LSE_DIS;
+	resp = &desc.params.get_link_status;
+	resp->cmd_flags = cmd_flags;
+	resp->lport_num = hw->bus.func;
+
+	err = ixgbe_aci_send_cmd(hw, &desc, &link_data, sizeof(link_data));
+
+	if (err)
+		return err;
+
+	/* Save off old link status information. */
+	*li_old = *li;
+
+	/* Update current link status information. */
+	li->link_speed = link_data.link_speed;
+	li->phy_type_low = link_data.phy_type_low;
+	li->phy_type_high = link_data.phy_type_high;
+	li->link_info = link_data.link_info;
+	li->link_cfg_err = link_data.link_cfg_err;
+	li->an_info = link_data.an_info;
+	li->ext_info = link_data.ext_info;
+	li->max_frame_size = link_data.max_frame_size;
+	li->fec_info = link_data.cfg & IXGBE_ACI_FEC_MASK;
+	li->topo_media_conflict = link_data.topo_media_conflict;
+	li->pacing = link_data.cfg & (IXGBE_ACI_CFG_PACING_M |
+				      IXGBE_ACI_CFG_PACING_TYPE_M);
+
+	/* Update fc info. */
+	tx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_TX);
+	rx_pause = !!(link_data.an_info & IXGBE_ACI_LINK_PAUSE_RX);
+	if (tx_pause && rx_pause)
+		hw_fc_info->current_mode = ixgbe_fc_full;
+	else if (tx_pause)
+		hw_fc_info->current_mode = ixgbe_fc_tx_pause;
+	else if (rx_pause)
+		hw_fc_info->current_mode = ixgbe_fc_rx_pause;
+	else
+		hw_fc_info->current_mode = ixgbe_fc_none;
+
+	li->lse_ena = !!(resp->cmd_flags & IXGBE_ACI_LSE_IS_ENABLED);
+
+	/* Save link status information. */
+	if (link)
+		*link = *li;
+
+	/* Flag cleared so calling functions don't call AQ again. */
+	hw->link.get_link_info = false;
+
+	return 0;
+}
+
+/**
+ * ixgbe_aci_set_event_mask - set event mask
+ * @hw: pointer to the HW struct
+ * @port_num: port number of the physical function
+ * @mask: event mask to be set
+ *
+ * Set the event mask using ACI command (0x0613).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask)
+{
+	struct ixgbe_aci_cmd_set_event_mask *cmd;
+	struct ixgbe_aci_desc desc;
+
+	cmd = &desc.params.set_event_mask;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_set_event_mask);
+
+	cmd->lport_num = port_num;
+
+	cmd->event_mask = mask;
+	return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
+}
+
+/**
+ * ixgbe_configure_lse - enable/disable link status events
+ * @hw: pointer to the HW struct
+ * @activate: true for enable lse, false otherwise
+ * @mask: event mask to be set; a set bit means deactivation of the
+ * corresponding event
+ *
+ * Set the event mask and then enable or disable link status events
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask)
+{
+	int err;
+
+	err = ixgbe_aci_set_event_mask(hw, (u8)hw->bus.func, mask);
+	if (err)
+		return err;
+
+	/* Enabling link status events generation by fw */
+	err = ixgbe_aci_get_link_info(hw, activate, NULL);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/**
+ * ixgbe_get_media_type_e610 - Gets media type
+ * @hw: pointer to the HW struct
+ *
+ * In order to get the media type, the function gets PHY
+ * capabilities and later on use them to identify the PHY type
+ * checking phy_type_high and phy_type_low.
+ *
+ * Return: the type of media in form of ixgbe_media_type enum
+ * or ixgbe_media_type_unknown in case of an error.
+ */
+enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+	int rc;
+
+	rc = ixgbe_update_link_info(hw);
+	if (rc)
+		return ixgbe_media_type_unknown;
+
+	/* If there is no link but PHY (dongle) is available SW should use
+	 * Get PHY Caps admin command instead of Get Link Status, find most
+	 * significant bit that is set in PHY types reported by the command
+	 * and use it to discover media type.
+	 */
+	if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP) &&
+	    (hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE)) {
+		int highest_bit;
+
+		/* Get PHY Capabilities */
+		rc = ixgbe_aci_get_phy_caps(hw, false,
+					    IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
+					    &pcaps);
+		if (rc)
+			return ixgbe_media_type_unknown;
+
+		highest_bit = fls64(pcaps.phy_type_high);
+		if (highest_bit) {
+			hw->link.link_info.phy_type_high =
+				BIT_ULL(highest_bit - 1);
+			hw->link.link_info.phy_type_low = 0;
+		} else {
+			highest_bit = fls64(pcaps.phy_type_low);
+			if (highest_bit)
+				hw->link.link_info.phy_type_low =
+					BIT_ULL(highest_bit - 1);
+		}
+	}
+
+	/* Based on link status or search above try to discover media type. */
+	hw->phy.media_type = ixgbe_get_media_type_from_phy_type(hw);
+
+	return hw->phy.media_type;
+}
+
+/**
+ * ixgbe_setup_link_e610 - Set up link
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg_wait: true when waiting for completion is needed
+ *
+ * Set up the link with the specified speed.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+			  bool autoneg_wait)
+{
+	/* Simply request FW to perform proper PHY setup */
+	return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
+}
+
+/**
+ * ixgbe_check_link_e610 - Determine link and speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true when link is up
+ * @link_up_wait_to_complete: bool used to wait for link up or not
+ *
+ * Determine if the link is up and the current link speed
+ * using ACI command (0x0607).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+			  bool *link_up, bool link_up_wait_to_complete)
+{
+	int err;
+	u32 i;
+
+	if (!speed || !link_up)
+		return -EINVAL;
+
+	/* Set get_link_info flag to ensure that fresh
+	 * link information will be obtained from FW
+	 * by sending Get Link Status admin command.
+	 */
+	hw->link.get_link_info = true;
+
+	/* Update link information in adapter context. */
+	err = ixgbe_get_link_status(hw, link_up);
+	if (err)
+		return err;
+
+	/* Wait for link up if it was requested. */
+	if (link_up_wait_to_complete && !(*link_up)) {
+		for (i = 0; i < hw->mac.max_link_up_time; i++) {
+			msleep(100);
+			hw->link.get_link_info = true;
+			err = ixgbe_get_link_status(hw, link_up);
+			if (err)
+				return err;
+			if (*link_up)
+				break;
+		}
+	}
+
+	/* Use link information in adapter context updated by the call
+	 * to ixgbe_get_link_status() to determine current link speed.
+	 * Link speed information is valid only when link up was
+	 * reported by FW.
+	 */
+	if (*link_up) {
+		switch (hw->link.link_info.link_speed) {
+		case IXGBE_ACI_LINK_SPEED_10MB:
+			*speed = IXGBE_LINK_SPEED_10_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_100MB:
+			*speed = IXGBE_LINK_SPEED_100_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_1000MB:
+			*speed = IXGBE_LINK_SPEED_1GB_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_2500MB:
+			*speed = IXGBE_LINK_SPEED_2_5GB_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_5GB:
+			*speed = IXGBE_LINK_SPEED_5GB_FULL;
+			break;
+		case IXGBE_ACI_LINK_SPEED_10GB:
+			*speed = IXGBE_LINK_SPEED_10GB_FULL;
+			break;
+		default:
+			*speed = IXGBE_LINK_SPEED_UNKNOWN;
+			break;
+		}
+	} else {
+		*speed = IXGBE_LINK_SPEED_UNKNOWN;
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_get_link_capabilities_e610 - Determine link capabilities
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: true when autoneg or autotry is enabled
+ *
+ * Determine speed and AN parameters of a link.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
+				     ixgbe_link_speed *speed,
+				     bool *autoneg)
+{
+	if (!speed || !autoneg)
+		return -EINVAL;
+
+	*autoneg = true;
+	*speed = hw->phy.speeds_supported;
+
+	return 0;
+}
+
+/**
+ * ixgbe_cfg_phy_fc - Configure PHY Flow Control (FC) data based on FC mode
+ * @hw: pointer to hardware structure
+ * @cfg: PHY configuration data to set FC mode
+ * @req_mode: FC mode to configure
+ *
+ * Configures PHY Flow Control according to the provided configuration.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
+		     struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
+		     enum ixgbe_fc_mode req_mode)
+{
+	u8 pause_mask = 0x0;
+
+	if (!cfg)
+		return -EINVAL;
+
+	switch (req_mode) {
+	case ixgbe_fc_full:
+		pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
+		pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
+		break;
+	case ixgbe_fc_rx_pause:
+		pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE;
+		break;
+	case ixgbe_fc_tx_pause:
+		pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
+		break;
+	default:
+		break;
+	}
+
+	/* Clear the old pause settings. */
+	cfg->caps &= ~(IXGBE_ACI_PHY_EN_TX_LINK_PAUSE |
+		IXGBE_ACI_PHY_EN_RX_LINK_PAUSE);
+
+	/* Set the new capabilities. */
+	cfg->caps |= pause_mask;
+
+	return 0;
+}
+
+/**
+ * ixgbe_setup_fc_e610 - Set up flow control
+ * @hw: pointer to hardware structure
+ *
+ * Set up flow control. This has to be done during init time.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_fc_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps = { 0 };
+	struct ixgbe_aci_cmd_set_phy_cfg_data cfg = { 0 };
+	int err;
+
+	/* Get the current PHY config */
+	err = ixgbe_aci_get_phy_caps(hw, false,
+				     IXGBE_ACI_REPORT_ACTIVE_CFG, &pcaps);
+	if (err)
+		return err;
+
+	ixgbe_copy_phy_caps_to_cfg(&pcaps, &cfg);
+
+	/* Configure the set PHY data */
+	err = ixgbe_cfg_phy_fc(hw, &cfg, hw->fc.requested_mode);
+	if (err)
+		return err;
+
+	/* If the capabilities have changed, then set the new config */
+	if (cfg.caps != pcaps.caps) {
+		cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
+
+		err = ixgbe_aci_set_phy_cfg(hw, &cfg);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_fc_autoneg_e610 - Configure flow control
+ * @hw: pointer to hardware structure
+ *
+ * Configure Flow Control.
+ */
+void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw)
+{
+	int err;
+
+	/* Get current link err.
+	 * Current FC mode will be stored in the hw context.
+	 */
+	err = ixgbe_aci_get_link_info(hw, false, NULL);
+	if (err)
+		goto no_autoneg;
+
+	/* Check if the link is up */
+	if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP))
+		goto no_autoneg;
+
+	/* Check if auto-negotiation has completed */
+	if (!(hw->link.link_info.an_info & IXGBE_ACI_AN_COMPLETED))
+		goto no_autoneg;
+
+	hw->fc.fc_was_autonegged = true;
+	return;
+
+no_autoneg:
+	hw->fc.fc_was_autonegged = false;
+	hw->fc.current_mode = hw->fc.requested_mode;
+}
+
+/**
+ * ixgbe_disable_rx_e610 - Disable RX unit
+ * @hw: pointer to hardware structure
+ *
+ * Disable RX DMA unit on E610 with use of ACI command (0x000C).
+ *
+ * Return: the exit code of the operation.
+ */
+void ixgbe_disable_rx_e610(struct ixgbe_hw *hw)
+{
+	u32 rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	u32 pfdtxgswc;
+	int err;
+
+	if (!(rxctrl & IXGBE_RXCTRL_RXEN))
+		return;
+
+	pfdtxgswc = IXGBE_READ_REG(hw, IXGBE_PFDTXGSWC);
+	if (pfdtxgswc & IXGBE_PFDTXGSWC_VT_LBEN) {
+		pfdtxgswc &= ~IXGBE_PFDTXGSWC_VT_LBEN;
+		IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, pfdtxgswc);
+		hw->mac.set_lben = true;
+	} else {
+		hw->mac.set_lben = false;
+	}
+
+	err = ixgbe_aci_disable_rxen(hw);
+
+	/* If we fail - disable RX using register write */
+	if (err) {
+		rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+		if (rxctrl & IXGBE_RXCTRL_RXEN) {
+			rxctrl &= ~IXGBE_RXCTRL_RXEN;
+			IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
+		}
+	}
+}
+
+/**
+ * ixgbe_init_phy_ops_e610 - PHY specific init
+ * @hw: pointer to hardware structure
+ *
+ * Initialize any function pointers that were not able to be
+ * set during init_shared_code because the PHY type was not known.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_mac_info *mac = &hw->mac;
+	struct ixgbe_phy_info *phy = &hw->phy;
+	int ret_val;
+
+	if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper)
+		phy->ops.set_phy_power = ixgbe_set_phy_power_e610;
+	else
+		phy->ops.set_phy_power = NULL;
+
+	/* Identify the PHY */
+	ret_val = phy->ops.identify(hw);
+	if (ret_val)
+		return ret_val;
+
+	return ret_val;
+}
+
+/**
+ * ixgbe_identify_phy_e610 - Identify PHY
+ * @hw: pointer to hardware structure
+ *
+ * Determine PHY type, supported speeds and PHY ID.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_identify_phy_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+	int err;
+
+	/* Set PHY type */
+	hw->phy.type = ixgbe_phy_fw;
+
+	err = ixgbe_aci_get_phy_caps(hw, false,
+				     IXGBE_ACI_REPORT_TOPO_CAP_MEDIA, &pcaps);
+	if (err)
+		return err;
+
+	if (!(pcaps.module_compliance_enforcement &
+	      IXGBE_ACI_MOD_ENFORCE_STRICT_MODE)) {
+		/* Handle lenient mode */
+		err = ixgbe_aci_get_phy_caps(hw, false,
+					     IXGBE_ACI_REPORT_TOPO_CAP_NO_MEDIA,
+					     &pcaps);
+		if (err)
+			return err;
+	}
+
+	/* Determine supported speeds */
+	hw->phy.speeds_supported = IXGBE_LINK_SPEED_UNKNOWN;
+
+	if (pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10BASE_T ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10M_SGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10_FULL;
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100BASE_TX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_100M_SGMII ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_100M_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_T  ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_SX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_LX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1000BASE_KX ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_1G_SGMII    ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_1G_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_T       ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_DA      ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_SR      ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_LR      ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1  ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_10G_SFI_C2C     ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_10G_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
+
+	/* 2.5 and 5 Gbps link speeds must be excluded from the
+	 * auto-negotiation set used during driver initialization due to
+	 * compatibility issues with certain switches. Those issues do not
+	 * exist in case of E610 2.5G SKU device (0x57b1).
+	 */
+	if (!hw->phy.autoneg_advertised &&
+	    hw->device_id != IXGBE_DEV_ID_E610_2_5G_T)
+		hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
+
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_T   ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_X   ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_2500BASE_KX  ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_SGMII ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_2500M_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
+
+	if (!hw->phy.autoneg_advertised &&
+	    hw->device_id == IXGBE_DEV_ID_E610_2_5G_T)
+		hw->phy.autoneg_advertised = hw->phy.speeds_supported;//PK
+
+	if (pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_T  ||
+	    pcaps.phy_type_low  & IXGBE_PHY_TYPE_LOW_5GBASE_KR ||
+	    pcaps.phy_type_high & IXGBE_PHY_TYPE_HIGH_5G_USXGMII)
+		hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
+
+	/* Set PHY ID */
+	memcpy(&hw->phy.id, pcaps.phy_id_oui, sizeof(u32));
+
+	hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_10_FULL |
+				       IXGBE_LINK_SPEED_100_FULL |
+				       IXGBE_LINK_SPEED_1GB_FULL;
+	hw->phy.eee_speeds_advertised = hw->phy.eee_speeds_supported;
+
+	return 0;
+}
+
+/**
+ * ixgbe_identify_module_e610 - Identify SFP module type
+ * @hw: pointer to hardware structure
+ *
+ * Identify the SFP module type.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_identify_module_e610(struct ixgbe_hw *hw)
+{
+	bool media_available;
+	u8 module_type;
+	int err;
+
+	err = ixgbe_update_link_info(hw);
+	if (err)
+		return err;
+
+	media_available =
+		(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE);
+
+	if (media_available) {
+		hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+
+		/* Get module type from hw context updated by
+		 * ixgbe_update_link_info()
+		 */
+		module_type = hw->link.link_info.module_type[IXGBE_ACI_MOD_TYPE_IDENT];
+
+		if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE) ||
+		    (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE)) {
+			hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
+		} else if (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_SR) {
+			hw->phy.sfp_type = ixgbe_sfp_type_sr;
+		} else if ((module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LR) ||
+			   (module_type & IXGBE_ACI_MOD_TYPE_BYTE1_10G_BASE_LRM)) {
+			hw->phy.sfp_type = ixgbe_sfp_type_lr;
+		}
+	} else {
+		hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_setup_phy_link_e610 - Sets up firmware-controlled PHYs
+ * @hw: pointer to hardware structure
+ *
+ * Set the parameters for the firmware-controlled PHYs.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data pcaps;
+	struct ixgbe_aci_cmd_set_phy_cfg_data pcfg;
+	u8 rmode = IXGBE_ACI_REPORT_TOPO_CAP_MEDIA;
+	u64 sup_phy_type_low, sup_phy_type_high;
+	int err;
+
+	err = ixgbe_aci_get_link_info(hw, false, NULL);
+	if (err)
+		return err;
+
+	/* If media is not available get default config. */
+	if (!(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE))
+		rmode = IXGBE_ACI_REPORT_DFLT_CFG;
+
+	err = ixgbe_aci_get_phy_caps(hw, false, rmode, &pcaps);
+	if (err)
+		return err;
+
+	sup_phy_type_low = pcaps.phy_type_low;
+	sup_phy_type_high = pcaps.phy_type_high;
+
+	/* Get Active configuration to avoid unintended changes. */
+	err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
+				     &pcaps);
+	if (err)
+		return err;
+
+	ixgbe_copy_phy_caps_to_cfg(&pcaps, &pcfg);
+
+	/* Set default PHY types for a given speed */
+	pcfg.phy_type_low = 0;
+	pcfg.phy_type_high = 0;
+
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL) {
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10BASE_T;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10M_SGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100BASE_TX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_100M_SGMII;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_100M_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_SX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_LX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1000BASE_KX;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_1G_SGMII;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_1G_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_X;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_2500BASE_KX;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_SGMII;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_2500M_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_5GBASE_KR;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_5G_USXGMII;
+	}
+	if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) {
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_T;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_DA;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_SR;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_LR;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC;
+		pcfg.phy_type_low  |= IXGBE_PHY_TYPE_LOW_10G_SFI_C2C;
+		pcfg.phy_type_high |= IXGBE_PHY_TYPE_HIGH_10G_USXGMII;
+	}
+
+	/* Mask the set values to avoid requesting unsupported link types */
+	pcfg.phy_type_low &= sup_phy_type_low;
+	pcfg.phy_type_high &= sup_phy_type_high;
+
+	if (pcfg.phy_type_high != pcaps.phy_type_high ||
+	    pcfg.phy_type_low != pcaps.phy_type_low ||
+	    pcfg.caps != pcaps.caps) {
+		pcfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
+		pcfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
+
+		err = ixgbe_aci_set_phy_cfg(hw, &pcfg);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_set_phy_power_e610 - Control power for copper PHY
+ * @hw: pointer to hardware structure
+ * @on: true for on, false for off
+ *
+ * Set the power on/off of the PHY
+ * by getting its capabilities and setting the appropriate
+ * configuration parameters.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
+	struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 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);
+
+	if (on)
+		phy_cfg.caps &= ~IXGBE_ACI_PHY_ENA_LOW_POWER;
+	else
+		phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LOW_POWER;
+
+	/* PHY is already in requested power mode. */
+	if (phy_caps.caps == phy_cfg.caps)
+		return 0;
+
+	phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LINK;
+	phy_cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
+
+	err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
+
+	return err;
+}
+
+/**
+ * ixgbe_enter_lplu_e610 - Transition to low power states
+ * @hw: pointer to hardware structure
+ *
+ * Configures Low Power Link Up on transition to low power states
+ * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the
+ * X557 PHY immediately prior to entering LPLU.
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw)
+{
+	struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = { 0 };
+	struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = { 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.low_power_ctrl_an |= IXGBE_ACI_PHY_EN_D3COLD_LOW_POWER_AUTONEG;
+
+	err = ixgbe_aci_set_phy_cfg(hw, &phy_cfg);
+
+	return err;
+}
+
+/**
+ * ixgbe_aci_get_netlist_node - get a node handle
+ * @hw: pointer to the hw struct
+ * @cmd: get_link_topo AQ structure
+ * @node_part_number: output node part number if node found
+ * @node_handle: output node handle parameter if node found
+ *
+ * Get the netlist node and assigns it to
+ * the provided handle using ACI command (0x06E0).
+ *
+ * Return: the exit code of the operation.
+ */
+int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
+			       struct ixgbe_aci_cmd_get_link_topo *cmd,
+			       u8 *node_part_number, u16 *node_handle)
+{
+	struct ixgbe_aci_desc desc;
+
+	ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo);
+	desc.params.get_link_topo = *cmd;
+
+	if (ixgbe_aci_send_cmd(hw, &desc, NULL, 0))
+		return -EOPNOTSUPP;
+
+	if (node_handle)
+		*node_handle = desc.params.get_link_topo.addr.handle;
+	if (node_part_number)
+		*node_part_number = desc.params.get_link_topo.node_part_num;
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
index 5c5a676..4a4f969 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h
@@ -27,5 +27,37 @@  int ixgbe_aci_get_phy_caps(struct ixgbe_hw *hw, bool qual_mods, u8 report_mode,
 			   struct ixgbe_aci_cmd_get_phy_caps_data *pcaps);
 void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps,
 				struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
+int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw,
+			  struct ixgbe_aci_cmd_set_phy_cfg_data *cfg);
+int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link);
+int ixgbe_update_link_info(struct ixgbe_hw *hw);
+int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up);
+int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse,
+			    struct ixgbe_link_status *link);
+int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask);
+int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask);
+enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw);
+int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+			  bool autoneg_wait);
+int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+			  bool *link_up, bool link_up_wait_to_complete);
+int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
+				     ixgbe_link_speed *speed,
+				     bool *autoneg);
+int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw,
+		     struct ixgbe_aci_cmd_set_phy_cfg_data *cfg,
+		     enum ixgbe_fc_mode req_mode);
+int ixgbe_setup_fc_e610(struct ixgbe_hw *hw);
+void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw);
+void ixgbe_disable_rx_e610(struct ixgbe_hw *hw);
+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_set_phy_power_e610(struct ixgbe_hw *hw, bool on);
+int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
+int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
+			       struct ixgbe_aci_cmd_get_link_topo *cmd,
+			       u8 *node_part_number, u16 *node_handle);
 
 #endif /* _IXGBE_E610_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
index 6c6d990..1f97652 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type_e610.h
@@ -652,6 +652,7 @@  struct ixgbe_aci_cmd_link_topo_params {
 #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_CLK_MUX	10
 #define IXGBE_ACI_LINK_TOPO_NODE_TYPE_GPS	11
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_S		4
+#define IXGBE_ACI_LINK_TOPO_NODE_CTX_M		GENMASK(7, 4)
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_GLOBAL			0
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_BOARD			1
 #define IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT			2