Message ID | 20241003141650.16524-4-piotr.kwapulinski@intel.com (mailing list archive) |
---|---|
State | Awaiting Upstream |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | ixgbe: Add support for Intel(R) E610 device | expand |
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>
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 > >
>-----Original Message----- >From: Kalesh Anakkur Purayil <kalesh-anakkur.purayil@broadcom.com> >Sent: Thursday, October 17, 2024 3:27 PM >To: Kwapulinski, Piotr <piotr.kwapulinski@intel.com> >Cc: intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org; Wegrzyn, Stefan <stefan.wegrzyn@intel.com>; Jagielski, Jedrzej <jedrzej.jagielski@intel.com>; Glaza, Jan <jan.glaza@intel.com> >Subject: Re: [PATCH iwl-next v9 3/7] ixgbe: Add link management support for E610 device > >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 Will do >> + 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: Will do. >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 Will do. >> + 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); Will do. >> + 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); Will do. >> + 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); Will do. >> + >> + 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 Will do. >> + >> + 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 >> >> > > >-- >Regards, >Kalesh A P Thank you All for review. Piotr
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