Message ID | 20241003141650.16524-3-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:45PM +0200, Piotr Kwapulinski wrote: > Add low level support for E610 device capabilities detection. The > capabilities are discovered via the Admin Command Interface. Discover the > following capabilities: > - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset > - device caps: vsi, fdir, 1588 > - phy caps > > 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 Sokolowski <jan.sokolowski@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:48 PM Piotr Kwapulinski <piotr.kwapulinski@intel.com> wrote: > > Add low level support for E610 device capabilities detection. The > capabilities are discovered via the Admin Command Interface. Discover the > following capabilities: > - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset > - device caps: vsi, fdir, 1588 > - phy caps > > 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 Sokolowski <jan.sokolowski@intel.com> > Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com> Hi Piotr, Some minor cosmetic comments in line. > --- > drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 540 ++++++++++++++++++ > drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 12 + > drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 + > 3 files changed, 560 insertions(+) > > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c > index 28bd7da..3bc88df 100644 > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c > @@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res) > total_delay++; > } > } > + > +/** > + * ixgbe_parse_e610_caps - Parse common device/function capabilities > + * @hw: pointer to the HW struct > + * @caps: pointer to common capabilities structure > + * @elem: the capability element to parse > + * @prefix: message prefix for tracing capabilities > + * > + * Given a capability element, extract relevant details into the common > + * capability structure. > + * > + * Return: true if the capability matches one of the common capability ids, > + * false otherwise. > + */ > +static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_caps *caps, > + struct ixgbe_aci_cmd_list_caps_elem *elem, > + const char *prefix) > +{ > + u32 logical_id = elem->logical_id; > + u32 phys_id = elem->phys_id; > + u32 number = elem->number; > + u16 cap = elem->cap; > + > + switch (cap) { > + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: > + caps->valid_functions = number; > + break; > + case IXGBE_ACI_CAPS_SRIOV: > + caps->sr_iov_1_1 = (number == 1); > + break; > + case IXGBE_ACI_CAPS_VMDQ: > + caps->vmdq = (number == 1); > + break; > + case IXGBE_ACI_CAPS_DCB: > + caps->dcb = (number == 1); > + caps->active_tc_bitmap = logical_id; > + caps->maxtc = phys_id; > + break; > + case IXGBE_ACI_CAPS_RSS: > + caps->rss_table_size = number; > + caps->rss_table_entry_width = logical_id; > + break; > + case IXGBE_ACI_CAPS_RXQS: > + caps->num_rxq = number; > + caps->rxq_first_id = phys_id; > + break; > + case IXGBE_ACI_CAPS_TXQS: > + caps->num_txq = number; > + caps->txq_first_id = phys_id; > + break; > + case IXGBE_ACI_CAPS_MSIX: > + caps->num_msix_vectors = number; > + caps->msix_vector_first_id = phys_id; > + break; > + case IXGBE_ACI_CAPS_NVM_VER: > + break; > + case IXGBE_ACI_CAPS_MAX_MTU: > + caps->max_mtu = number; > + break; > + case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE: > + caps->pcie_reset_avoidance = (number > 0); > + break; > + case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT: > + caps->reset_restrict_support = (number == 1); > + break; > + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0: > + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1: > + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2: > + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3: > + { > + u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0; > + > + caps->ext_topo_dev_img_ver_high[index] = number; > + caps->ext_topo_dev_img_ver_low[index] = logical_id; > + caps->ext_topo_dev_img_part_num[index] = > + FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id); > + caps->ext_topo_dev_img_load_en[index] = > + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0; > + caps->ext_topo_dev_img_prog_en[index] = > + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0; > + break; > + } > + default: > + /* Not one of the recognized common capabilities */ > + return false; > + } > + > + return true; > +} > + > +/** > + * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps > + * @hw: pointer to the HW struct > + * @dev_p: pointer to device capabilities structure > + * @cap: capability element to parse > + * > + * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities. > + */ > +static void > +ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw, > + struct ixgbe_hw_dev_caps *dev_p, > + struct ixgbe_aci_cmd_list_caps_elem *cap) > +{ > + u32 number = cap->number; [Kalesh] Do you really need a local variable here? Same comment applies to functions below as well. > + > + dev_p->num_funcs = hweight32(number); > +} > + > +/** > + * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps > + * @hw: pointer to the HW struct > + * @dev_p: pointer to device capabilities structure > + * @cap: capability element to parse > + * > + * Parse IXGBE_ACI_CAPS_VF for device capabilities. > + */ > +static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_dev_caps *dev_p, > + struct ixgbe_aci_cmd_list_caps_elem *cap) > +{ > + u32 number = cap->number; > + > + dev_p->num_vfs_exposed = number; > +} > + > +/** > + * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps > + * @hw: pointer to the HW struct > + * @dev_p: pointer to device capabilities structure > + * @cap: capability element to parse > + * > + * Parse IXGBE_ACI_CAPS_VSI for device capabilities. > + */ > +static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_dev_caps *dev_p, > + struct ixgbe_aci_cmd_list_caps_elem *cap) > +{ > + u32 number = cap->number; > + > + dev_p->num_vsi_allocd_to_host = number; > +} > + > +/** > + * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps > + * @hw: pointer to the HW struct > + * @dev_p: pointer to device capabilities structure > + * @cap: capability element to parse > + * > + * Parse IXGBE_ACI_CAPS_FD for device capabilities. > + */ > +static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_dev_caps *dev_p, > + struct ixgbe_aci_cmd_list_caps_elem *cap) > +{ > + u32 number = cap->number; > + > + dev_p->num_flow_director_fltr = number; > +} > + > +/** > + * ixgbe_parse_dev_caps - Parse device capabilities > + * @hw: pointer to the HW struct > + * @dev_p: pointer to device capabilities structure > + * @buf: buffer containing the device capability records > + * @cap_count: the number of capabilities > + * > + * Helper device to parse device (0x000B) capabilities list. For > + * capabilities shared between device and function, this relies on > + * ixgbe_parse_e610_caps. > + * > + * Loop through the list of provided capabilities and extract the relevant > + * data into the device capabilities structured. > + */ > +static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_dev_caps *dev_p, > + void *buf, u32 cap_count) > +{ > + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; > + u32 i; > + > + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; > + > + memset(dev_p, 0, sizeof(*dev_p)); > + > + for (i = 0; i < cap_count; i++) { > + u16 cap = cap_resp[i].cap; > + > + ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i], > + "dev caps"); > + > + switch (cap) { > + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: > + ixgbe_parse_valid_functions_cap(hw, dev_p, > + &cap_resp[i]); > + break; > + case IXGBE_ACI_CAPS_VF: > + ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]); > + break; > + case IXGBE_ACI_CAPS_VSI: > + ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]); > + break; > + case IXGBE_ACI_CAPS_FD: > + ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]); > + break; > + default: > + /* Don't list common capabilities as unknown */ > + break; > + } > + } > +} > + > +/** > + * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps > + * @hw: pointer to the HW struct > + * @func_p: pointer to function capabilities structure > + * @cap: pointer to the capability element to parse > + * > + * Extract function capabilities for IXGBE_ACI_CAPS_VF. > + */ > +static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_func_caps *func_p, > + struct ixgbe_aci_cmd_list_caps_elem *cap) > +{ > + u32 logical_id = cap->logical_id; > + u32 number = cap->number; > + > + func_p->num_allocd_vfs = number; > + func_p->vf_base_id = logical_id; > +} > + > +/** > + * ixgbe_get_num_per_func - determine number of resources per PF > + * @hw: pointer to the HW structure > + * @max: value to be evenly split between each PF > + * > + * Determine the number of valid functions by going through the bitmap returned > + * from parsing capabilities and use this to calculate the number of resources > + * per PF based on the max value passed in. > + * > + * Return: the number of resources per PF or 0, if no PH are available. > + */ > +static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max) > +{ > +#define IXGBE_CAPS_VALID_FUNCS_M GENMASK(7, 0) > + u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions & > + IXGBE_CAPS_VALID_FUNCS_M); > + > + return funcs ? (max / funcs) : 0; > +} > + > +/** > + * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps > + * @hw: pointer to the HW struct > + * @func_p: pointer to function capabilities structure > + * @cap: pointer to the capability element to parse > + * > + * Extract function capabilities for IXGBE_ACI_CAPS_VSI. > + */ > +static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_func_caps *func_p, > + struct ixgbe_aci_cmd_list_caps_elem *cap) > +{ > + func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI); > +} > + > +/** > + * ixgbe_parse_func_caps - Parse function capabilities > + * @hw: pointer to the HW struct > + * @func_p: pointer to function capabilities structure > + * @buf: buffer containing the function capability records > + * @cap_count: the number of capabilities > + * > + * Helper function to parse function (0x000A) capabilities list. For > + * capabilities shared between device and function, this relies on > + * ixgbe_parse_e610_caps. > + * > + * Loop through the list of provided capabilities and extract the relevant > + * data into the function capabilities structured. > + */ > +static void ixgbe_parse_func_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_func_caps *func_p, > + void *buf, u32 cap_count) > +{ > + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; > + u32 i; > + > + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; > + > + memset(func_p, 0, sizeof(*func_p)); > + > + for (i = 0; i < cap_count; i++) { > + u16 cap = cap_resp[i].cap; > + > + ixgbe_parse_e610_caps(hw, &func_p->common_cap, > + &cap_resp[i], "func caps"); > + > + switch (cap) { > + case IXGBE_ACI_CAPS_VF: > + ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]); > + break; > + case IXGBE_ACI_CAPS_VSI: > + ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]); > + break; > + default: > + /* Don't list common capabilities as unknown */ > + break; > + } > + } > +} > + > +/** > + * ixgbe_aci_list_caps - query function/device capabilities > + * @hw: pointer to the HW struct > + * @buf: a buffer to hold the capabilities > + * @buf_size: size of the buffer > + * @cap_count: if not NULL, set to the number of capabilities reported > + * @opc: capabilities type to discover, device or function > + * > + * Get the function (0x000A) or device (0x000B) capabilities description from > + * firmware and store it in the buffer. > + * > + * If the cap_count pointer is not NULL, then it is set to the number of > + * capabilities firmware will report. Note that if the buffer size is too > + * small, it is possible the command will return -ENOMEM. The > + * cap_count will still be updated in this case. It is recommended that the > + * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible > + * buffer that firmware could return) to avoid this. > + * > + * Return: the exit code of the operation. > + * Exit code of -ENOMEM means the buffer size is too small. > + */ > +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size, > + u32 *cap_count, enum ixgbe_aci_opc opc) > +{ > + struct ixgbe_aci_cmd_list_caps *cmd; > + struct ixgbe_aci_desc desc; > + int err; > + > + cmd = &desc.params.get_cap; > + > + if (opc != ixgbe_aci_opc_list_func_caps && > + opc != ixgbe_aci_opc_list_dev_caps) > + return -EINVAL; > + > + ixgbe_fill_dflt_direct_cmd_desc(&desc, opc); > + err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size); > + > + if (cap_count) [Kalesh] Do you need a check for !err as well here? > + *cap_count = cmd->count; > + > + return err; > +} > + > +/** > + * ixgbe_discover_dev_caps - Read and extract device capabilities > + * @hw: pointer to the hardware structure > + * @dev_caps: pointer to device capabilities structure > + * > + * Read the device capabilities and extract them into the dev_caps structure > + * for later use. > + * > + * Return: the exit code of the operation. > + */ > +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_dev_caps *dev_caps) > +{ > + u8 *cbuf __free(kfree); > + u32 cap_count; > + int err; > + > + cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); > + if (!cbuf) > + return -ENOMEM; > + /* Although the driver doesn't know the number of capabilities the > + * device will return, we can simply send a 4KB buffer, the maximum > + * possible size that firmware can return. > + */ > + cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / > + sizeof(struct ixgbe_aci_cmd_list_caps_elem); > + > + err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE, > + &cap_count, > + ixgbe_aci_opc_list_dev_caps); > + if (err) > + return err; > + > + ixgbe_parse_dev_caps(hw, dev_caps, cbuf, cap_count); > + > + return 0; > +} > + > +/** > + * ixgbe_discover_func_caps - Read and extract function capabilities > + * @hw: pointer to the hardware structure > + * @func_caps: pointer to function capabilities structure > + * > + * Read the function capabilities and extract them into the func_caps structure > + * for later use. > + * > + * Return: the exit code of the operation. > + */ > +int ixgbe_discover_func_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_func_caps *func_caps) > +{ > + u8 *cbuf __free(kfree); > + u32 cap_count; > + int err; > + > + cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); > + if (!cbuf) > + return -ENOMEM; > + > + /* Although the driver doesn't know the number of capabilities the > + * device will return, we can simply send a 4KB buffer, the maximum > + * possible size that firmware can return. > + */ > + cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / > + sizeof(struct ixgbe_aci_cmd_list_caps_elem); > + > + err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE, > + &cap_count, > + ixgbe_aci_opc_list_func_caps); > + if (err) > + return err; > + > + ixgbe_parse_func_caps(hw, func_caps, cbuf, cap_count); > + > + return 0; > +} > + > +/** > + * ixgbe_get_caps - get info about the HW > + * @hw: pointer to the hardware structure > + * > + * Retrieve both device and function capabilities. > + * > + * Return: the exit code of the operation. > + */ > +int ixgbe_get_caps(struct ixgbe_hw *hw) > +{ > + int err; > + > + err = ixgbe_discover_dev_caps(hw, &hw->dev_caps); > + if (err) > + return err; > + > + return ixgbe_discover_func_caps(hw, &hw->func_caps); > +} > + > +/** > + * ixgbe_aci_disable_rxen - disable RX > + * @hw: pointer to the HW struct > + * > + * Request a safe disable of Receive Enable using ACI command (0x000C). > + * > + * Return: the exit code of the operation. > + */ > +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw) > +{ > + struct ixgbe_aci_cmd_disable_rxen *cmd; > + struct ixgbe_aci_desc desc; > + > + cmd = &desc.params.disable_rxen; > + > + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_disable_rxen); > + > + cmd->lport_num = hw->bus.func; > + > + return ixgbe_aci_send_cmd(hw, &desc, NULL, 0); > +} > + > +/** > + * ixgbe_aci_get_phy_caps - returns PHY capabilities > + * @hw: pointer to the HW struct > + * @qual_mods: report qualified modules > + * @report_mode: report mode capabilities > + * @pcaps: structure for PHY capabilities to be filled > + * > + * Returns the various PHY capabilities supported on the Port > + * using ACI command (0x0600). > + * > + * Return: the exit code of the operation. > + */ > +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) > +{ > + struct ixgbe_aci_cmd_get_phy_caps *cmd; > + u16 pcaps_size = sizeof(*pcaps); > + struct ixgbe_aci_desc desc; > + int err; > + > + cmd = &desc.params.get_phy; > + > + if (!pcaps || (report_mode & ~IXGBE_ACI_REPORT_MODE_M)) > + return -EINVAL; > + > + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_phy_caps); > + > + if (qual_mods) > + cmd->param0 |= IXGBE_ACI_GET_PHY_RQM; > + > + cmd->param0 |= report_mode; > + err = ixgbe_aci_send_cmd(hw, &desc, pcaps, pcaps_size); > + > + if (!err && report_mode == IXGBE_ACI_REPORT_TOPO_CAP_MEDIA) { > + hw->phy.phy_type_low = pcaps->phy_type_low; > + hw->phy.phy_type_high = pcaps->phy_type_high; > + memcpy(hw->link.link_info.module_type, &pcaps->module_type, > + sizeof(hw->link.link_info.module_type)); > + } > + > + return err; > +} > + > +/** > + * ixgbe_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data > + * @caps: PHY ability structure to copy data from > + * @cfg: PHY configuration structure to copy data to > + * > + * Helper function to copy data from PHY capabilities data structure > + * to PHY configuration data structure > + */ > +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) > +{ > + if (!caps || !cfg) > + return; > + > + memset(cfg, 0, sizeof(*cfg)); > + cfg->phy_type_low = caps->phy_type_low; > + cfg->phy_type_high = caps->phy_type_high; > + cfg->caps = caps->caps; > + cfg->low_power_ctrl_an = caps->low_power_ctrl_an; > + cfg->eee_cap = caps->eee_cap; > + cfg->eeer_value = caps->eeer_value; > + cfg->link_fec_opt = caps->link_fec_options; > + cfg->module_compliance_enforcement = > + caps->module_compliance_enforcement; > +} > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h > index 18b831b..5c5a676 100644 > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h > @@ -15,5 +15,17 @@ void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode); > int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res, > enum ixgbe_aci_res_access_type access, u32 timeout); > void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res); > +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size, > + u32 *cap_count, enum ixgbe_aci_opc opc); > +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_dev_caps *dev_caps); > +int ixgbe_discover_func_caps(struct ixgbe_hw *hw, > + struct ixgbe_hw_func_caps *func_caps); > +int ixgbe_get_caps(struct ixgbe_hw *hw); > +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw); > +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); > > #endif /* _IXGBE_E610_H_ */ > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c > index 8b8404d..0302a21 100644 > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c > @@ -43,6 +43,7 @@ > #include "ixgbe.h" > #include "ixgbe_common.h" > #include "ixgbe_dcb_82599.h" > +#include "ixgbe_e610.h" > #include "ixgbe_phy.h" > #include "ixgbe_sriov.h" > #include "ixgbe_model.h" > @@ -10932,6 +10933,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) > if (err) > goto err_sw_init; > > + if (adapter->hw.mac.type == ixgbe_mac_e610) { > + err = ixgbe_get_caps(&adapter->hw); > + if (err) > + dev_err(&pdev->dev, > + "ixgbe_get_caps failed %d\n", err); [Kalesh] You can fit this log in one line > + } > + > if (adapter->hw.mac.type == ixgbe_mac_82599EB) > adapter->flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF; > > -- > 2.43.0 > >
>-----Original Message----- >From: Kalesh Anakkur Purayil <kalesh-anakkur.purayil@broadcom.com> >Sent: Friday, October 18, 2024 5:06 AM >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>; Sokolowski, Jan <jan.sokolowski@intel.com> >Subject: Re: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection > >On Thu, Oct 3, 2024 at 7:48 PM Piotr Kwapulinski ><piotr.kwapulinski@intel.com> wrote: >> >> Add low level support for E610 device capabilities detection. The >> capabilities are discovered via the Admin Command Interface. Discover the >> following capabilities: >> - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset >> - device caps: vsi, fdir, 1588 >> - phy caps >> >> 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 Sokolowski <jan.sokolowski@intel.com> >> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com> > >Hi Piotr, > >Some minor cosmetic comments in line. Hi Kalesh, I'll update. Thank you for review. Piotr > >> --- >> drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 540 ++++++++++++++++++ >> drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 12 + >> drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 + >> 3 files changed, 560 insertions(+) >> >> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c >> index 28bd7da..3bc88df 100644 >> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c >> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c >> @@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res) >> total_delay++; >> } >> } >> + >> +/** >> + * ixgbe_parse_e610_caps - Parse common device/function capabilities >> + * @hw: pointer to the HW struct >> + * @caps: pointer to common capabilities structure >> + * @elem: the capability element to parse >> + * @prefix: message prefix for tracing capabilities >> + * >> + * Given a capability element, extract relevant details into the common >> + * capability structure. >> + * >> + * Return: true if the capability matches one of the common capability ids, >> + * false otherwise. >> + */ >> +static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_caps *caps, >> + struct ixgbe_aci_cmd_list_caps_elem *elem, >> + const char *prefix) >> +{ >> + u32 logical_id = elem->logical_id; >> + u32 phys_id = elem->phys_id; >> + u32 number = elem->number; >> + u16 cap = elem->cap; >> + >> + switch (cap) { >> + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: >> + caps->valid_functions = number; >> + break; >> + case IXGBE_ACI_CAPS_SRIOV: >> + caps->sr_iov_1_1 = (number == 1); >> + break; >> + case IXGBE_ACI_CAPS_VMDQ: >> + caps->vmdq = (number == 1); >> + break; >> + case IXGBE_ACI_CAPS_DCB: >> + caps->dcb = (number == 1); >> + caps->active_tc_bitmap = logical_id; >> + caps->maxtc = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_RSS: >> + caps->rss_table_size = number; >> + caps->rss_table_entry_width = logical_id; >> + break; >> + case IXGBE_ACI_CAPS_RXQS: >> + caps->num_rxq = number; >> + caps->rxq_first_id = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_TXQS: >> + caps->num_txq = number; >> + caps->txq_first_id = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_MSIX: >> + caps->num_msix_vectors = number; >> + caps->msix_vector_first_id = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_NVM_VER: >> + break; >> + case IXGBE_ACI_CAPS_MAX_MTU: >> + caps->max_mtu = number; >> + break; >> + case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE: >> + caps->pcie_reset_avoidance = (number > 0); >> + break; >> + case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT: >> + caps->reset_restrict_support = (number == 1); >> + break; >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0: >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1: >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2: >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3: >> + { >> + u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0; >> + >> + caps->ext_topo_dev_img_ver_high[index] = number; >> + caps->ext_topo_dev_img_ver_low[index] = logical_id; >> + caps->ext_topo_dev_img_part_num[index] = >> + FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id); >> + caps->ext_topo_dev_img_load_en[index] = >> + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0; >> + caps->ext_topo_dev_img_prog_en[index] = >> + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0; >> + break; >> + } >> + default: >> + /* Not one of the recognized common capabilities */ >> + return false; >> + } >> + >> + return true; >> +} >> + >> +/** >> + * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities. >> + */ >> +static void >> +ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >[Kalesh] Do you really need a local variable here? Same comment >applies to functions below as well. >> + >> + dev_p->num_funcs = hweight32(number); >> +} >> + >> +/** >> + * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_VF for device capabilities. >> + */ >> +static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >> + >> + dev_p->num_vfs_exposed = number; >> +} >> + >> +/** >> + * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_VSI for device capabilities. >> + */ >> +static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >> + >> + dev_p->num_vsi_allocd_to_host = number; >> +} >> + >> +/** >> + * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_FD for device capabilities. >> + */ >> +static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >> + >> + dev_p->num_flow_director_fltr = number; >> +} >> + >> +/** >> + * ixgbe_parse_dev_caps - Parse device capabilities >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @buf: buffer containing the device capability records >> + * @cap_count: the number of capabilities >> + * >> + * Helper device to parse device (0x000B) capabilities list. For >> + * capabilities shared between device and function, this relies on >> + * ixgbe_parse_e610_caps. >> + * >> + * Loop through the list of provided capabilities and extract the relevant >> + * data into the device capabilities structured. >> + */ >> +static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + void *buf, u32 cap_count) >> +{ >> + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; >> + u32 i; >> + >> + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; >> + >> + memset(dev_p, 0, sizeof(*dev_p)); >> + >> + for (i = 0; i < cap_count; i++) { >> + u16 cap = cap_resp[i].cap; >> + >> + ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i], >> + "dev caps"); >> + >> + switch (cap) { >> + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: >> + ixgbe_parse_valid_functions_cap(hw, dev_p, >> + &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_VF: >> + ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_VSI: >> + ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_FD: >> + ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]); >> + break; >> + default: >> + /* Don't list common capabilities as unknown */ >> + break; >> + } >> + } >> +} >> + >> +/** >> + * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps >> + * @hw: pointer to the HW struct >> + * @func_p: pointer to function capabilities structure >> + * @cap: pointer to the capability element to parse >> + * >> + * Extract function capabilities for IXGBE_ACI_CAPS_VF. >> + */ >> +static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 logical_id = cap->logical_id; >> + u32 number = cap->number; >> + >> + func_p->num_allocd_vfs = number; >> + func_p->vf_base_id = logical_id; >> +} >> + >> +/** >> + * ixgbe_get_num_per_func - determine number of resources per PF >> + * @hw: pointer to the HW structure >> + * @max: value to be evenly split between each PF >> + * >> + * Determine the number of valid functions by going through the bitmap returned >> + * from parsing capabilities and use this to calculate the number of resources >> + * per PF based on the max value passed in. >> + * >> + * Return: the number of resources per PF or 0, if no PH are available. >> + */ >> +static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max) >> +{ >> +#define IXGBE_CAPS_VALID_FUNCS_M GENMASK(7, 0) >> + u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions & >> + IXGBE_CAPS_VALID_FUNCS_M); >> + >> + return funcs ? (max / funcs) : 0; >> +} >> + >> +/** >> + * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps >> + * @hw: pointer to the HW struct >> + * @func_p: pointer to function capabilities structure >> + * @cap: pointer to the capability element to parse >> + * >> + * Extract function capabilities for IXGBE_ACI_CAPS_VSI. >> + */ >> +static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI); >> +} >> + >> +/** >> + * ixgbe_parse_func_caps - Parse function capabilities >> + * @hw: pointer to the HW struct >> + * @func_p: pointer to function capabilities structure >> + * @buf: buffer containing the function capability records >> + * @cap_count: the number of capabilities >> + * >> + * Helper function to parse function (0x000A) capabilities list. For >> + * capabilities shared between device and function, this relies on >> + * ixgbe_parse_e610_caps. >> + * >> + * Loop through the list of provided capabilities and extract the relevant >> + * data into the function capabilities structured. >> + */ >> +static void ixgbe_parse_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_p, >> + void *buf, u32 cap_count) >> +{ >> + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; >> + u32 i; >> + >> + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; >> + >> + memset(func_p, 0, sizeof(*func_p)); >> + >> + for (i = 0; i < cap_count; i++) { >> + u16 cap = cap_resp[i].cap; >> + >> + ixgbe_parse_e610_caps(hw, &func_p->common_cap, >> + &cap_resp[i], "func caps"); >> + >> + switch (cap) { >> + case IXGBE_ACI_CAPS_VF: >> + ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_VSI: >> + ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]); >> + break; >> + default: >> + /* Don't list common capabilities as unknown */ >> + break; >> + } >> + } >> +} >> + >> +/** >> + * ixgbe_aci_list_caps - query function/device capabilities >> + * @hw: pointer to the HW struct >> + * @buf: a buffer to hold the capabilities >> + * @buf_size: size of the buffer >> + * @cap_count: if not NULL, set to the number of capabilities reported >> + * @opc: capabilities type to discover, device or function >> + * >> + * Get the function (0x000A) or device (0x000B) capabilities description from >> + * firmware and store it in the buffer. >> + * >> + * If the cap_count pointer is not NULL, then it is set to the number of >> + * capabilities firmware will report. Note that if the buffer size is too >> + * small, it is possible the command will return -ENOMEM. The >> + * cap_count will still be updated in this case. It is recommended that the >> + * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible >> + * buffer that firmware could return) to avoid this. >> + * >> + * Return: the exit code of the operation. >> + * Exit code of -ENOMEM means the buffer size is too small. >> + */ >> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size, >> + u32 *cap_count, enum ixgbe_aci_opc opc) >> +{ >> + struct ixgbe_aci_cmd_list_caps *cmd; >> + struct ixgbe_aci_desc desc; >> + int err; >> + >> + cmd = &desc.params.get_cap; >> + >> + if (opc != ixgbe_aci_opc_list_func_caps && >> + opc != ixgbe_aci_opc_list_dev_caps) >> + return -EINVAL; >> + >> + ixgbe_fill_dflt_direct_cmd_desc(&desc, opc); >> + err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size); >> + >> + if (cap_count) >[Kalesh] Do you need a check for !err as well here? >> + *cap_count = cmd->count; >> + >> + return err; >> +} >> + >> +/** >> + * ixgbe_discover_dev_caps - Read and extract device capabilities >> + * @hw: pointer to the hardware structure >> + * @dev_caps: pointer to device capabilities structure >> + * >> + * Read the device capabilities and extract them into the dev_caps structure >> + * for later use. >> + * >> + * Return: the exit code of the operation. >> + */ >> +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_caps) >> +{ >> + u8 *cbuf __free(kfree); >> + u32 cap_count; >> + int err; >> + >> + cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); >> + if (!cbuf) >> + return -ENOMEM; >> + /* Although the driver doesn't know the number of capabilities the >> + * device will return, we can simply send a 4KB buffer, the maximum >> + * possible size that firmware can return. >> + */ >> + cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / >> + sizeof(struct ixgbe_aci_cmd_list_caps_elem); >> + >> + err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE, >> + &cap_count, >> + ixgbe_aci_opc_list_dev_caps); >> + if (err) >> + return err; >> + >> + ixgbe_parse_dev_caps(hw, dev_caps, cbuf, cap_count); >> + >> + return 0; >> +} >> + >> +/** >> + * ixgbe_discover_func_caps - Read and extract function capabilities >> + * @hw: pointer to the hardware structure >> + * @func_caps: pointer to function capabilities structure >> + * >> + * Read the function capabilities and extract them into the func_caps structure >> + * for later use. >> + * >> + * Return: the exit code of the operation. >> + */ >> +int ixgbe_discover_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_caps) >> +{ >> + u8 *cbuf __free(kfree); >> + u32 cap_count; >> + int err; >> + >> + cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); >> + if (!cbuf) >> + return -ENOMEM; >> + >> + /* Although the driver doesn't know the number of capabilities the >> + * device will return, we can simply send a 4KB buffer, the maximum >> + * possible size that firmware can return. >> + */ >> + cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / >> + sizeof(struct ixgbe_aci_cmd_list_caps_elem); >> + >> + err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE, >> + &cap_count, >> + ixgbe_aci_opc_list_func_caps); >> + if (err) >> + return err; >> + >> + ixgbe_parse_func_caps(hw, func_caps, cbuf, cap_count); >> + >> + return 0; >> +} >> + >> +/** >> + * ixgbe_get_caps - get info about the HW >> + * @hw: pointer to the hardware structure >> + * >> + * Retrieve both device and function capabilities. >> + * >> + * Return: the exit code of the operation. >> + */ >> +int ixgbe_get_caps(struct ixgbe_hw *hw) >> +{ >> + int err; >> + >> + err = ixgbe_discover_dev_caps(hw, &hw->dev_caps); >> + if (err) >> + return err; >> + >> + return ixgbe_discover_func_caps(hw, &hw->func_caps); >> +} >> + >> +/** >> + * ixgbe_aci_disable_rxen - disable RX >> + * @hw: pointer to the HW struct >> + * >> + * Request a safe disable of Receive Enable using ACI command (0x000C). >> + * >> + * Return: the exit code of the operation. >> + */ >> +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw) >> +{ >> + struct ixgbe_aci_cmd_disable_rxen *cmd; >> + struct ixgbe_aci_desc desc; >> + >> + cmd = &desc.params.disable_rxen; >> + >> + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_disable_rxen); >> + >> + cmd->lport_num = hw->bus.func; >> + >> + return ixgbe_aci_send_cmd(hw, &desc, NULL, 0); >> +} >> + >> +/** >> + * ixgbe_aci_get_phy_caps - returns PHY capabilities >> + * @hw: pointer to the HW struct >> + * @qual_mods: report qualified modules >> + * @report_mode: report mode capabilities >> + * @pcaps: structure for PHY capabilities to be filled >> + * >> + * Returns the various PHY capabilities supported on the Port >> + * using ACI command (0x0600). >> + * >> + * Return: the exit code of the operation. >> + */ >> +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) >> +{ >> + struct ixgbe_aci_cmd_get_phy_caps *cmd; >> + u16 pcaps_size = sizeof(*pcaps); >> + struct ixgbe_aci_desc desc; >> + int err; >> + >> + cmd = &desc.params.get_phy; >> + >> + if (!pcaps || (report_mode & ~IXGBE_ACI_REPORT_MODE_M)) >> + return -EINVAL; >> + >> + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_phy_caps); >> + >> + if (qual_mods) >> + cmd->param0 |= IXGBE_ACI_GET_PHY_RQM; >> + >> + cmd->param0 |= report_mode; >> + err = ixgbe_aci_send_cmd(hw, &desc, pcaps, pcaps_size); >> + >> + if (!err && report_mode == IXGBE_ACI_REPORT_TOPO_CAP_MEDIA) { >> + hw->phy.phy_type_low = pcaps->phy_type_low; >> + hw->phy.phy_type_high = pcaps->phy_type_high; >> + memcpy(hw->link.link_info.module_type, &pcaps->module_type, >> + sizeof(hw->link.link_info.module_type)); >> + } >> + >> + return err; >> +} >> + >> +/** >> + * ixgbe_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data >> + * @caps: PHY ability structure to copy data from >> + * @cfg: PHY configuration structure to copy data to >> + * >> + * Helper function to copy data from PHY capabilities data structure >> + * to PHY configuration data structure >> + */ >> +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) >> +{ >> + if (!caps || !cfg) >> + return; >> + >> + memset(cfg, 0, sizeof(*cfg)); >> + cfg->phy_type_low = caps->phy_type_low; >> + cfg->phy_type_high = caps->phy_type_high; >> + cfg->caps = caps->caps; >> + cfg->low_power_ctrl_an = caps->low_power_ctrl_an; >> + cfg->eee_cap = caps->eee_cap; >> + cfg->eeer_value = caps->eeer_value; >> + cfg->link_fec_opt = caps->link_fec_options; >> + cfg->module_compliance_enforcement = >> + caps->module_compliance_enforcement; >> +} >> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h >> index 18b831b..5c5a676 100644 >> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h >> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h >> @@ -15,5 +15,17 @@ void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode); >> int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res, >> enum ixgbe_aci_res_access_type access, u32 timeout); >> void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res); >> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size, >> + u32 *cap_count, enum ixgbe_aci_opc opc); >> +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_caps); >> +int ixgbe_discover_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_caps); >> +int ixgbe_get_caps(struct ixgbe_hw *hw); >> +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw); >> +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); >> >> #endif /* _IXGBE_E610_H_ */ >> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c >> index 8b8404d..0302a21 100644 >> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c >> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c >> @@ -43,6 +43,7 @@ >> #include "ixgbe.h" >> #include "ixgbe_common.h" >> #include "ixgbe_dcb_82599.h" >> +#include "ixgbe_e610.h" >> #include "ixgbe_phy.h" >> #include "ixgbe_sriov.h" >> #include "ixgbe_model.h" >> @@ -10932,6 +10933,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) >> if (err) >> goto err_sw_init; >> >> + if (adapter->hw.mac.type == ixgbe_mac_e610) { >> + err = ixgbe_get_caps(&adapter->hw); >> + if (err) >> + dev_err(&pdev->dev, >> + "ixgbe_get_caps failed %d\n", err); >[Kalesh] You can fit this log in one line >> + } >> + >> if (adapter->hw.mac.type == ixgbe_mac_82599EB) >> adapter->flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF; >> >> -- >> 2.43.0 >> >> > > >-- >Regards, >Kalesh A P
>-----Original Message----- >From: Kalesh Anakkur Purayil <kalesh-anakkur.purayil@broadcom.com> >Sent: Friday, October 18, 2024 5:06 AM >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>; Sokolowski, Jan <jan.sokolowski@intel.com> >Subject: Re: [PATCH iwl-next v9 2/7] ixgbe: Add support for E610 device capabilities detection > >On Thu, Oct 3, 2024 at 7:48 PM Piotr Kwapulinski ><piotr.kwapulinski@intel.com> wrote: >> >> Add low level support for E610 device capabilities detection. The >> capabilities are discovered via the Admin Command Interface. Discover the >> following capabilities: >> - function caps: vmdq, dcb, rss, rx/tx qs, msix, nvm, orom, reset >> - device caps: vsi, fdir, 1588 >> - phy caps >> >> 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 Sokolowski <jan.sokolowski@intel.com> >> Signed-off-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com> > >Hi Piotr, > >Some minor cosmetic comments in line. > >> --- >> drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 540 ++++++++++++++++++ >> drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 12 + >> drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 + >> 3 files changed, 560 insertions(+) >> >> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c >> index 28bd7da..3bc88df 100644 >> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c >> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c >> @@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res) >> total_delay++; >> } >> } >> + >> +/** >> + * ixgbe_parse_e610_caps - Parse common device/function capabilities >> + * @hw: pointer to the HW struct >> + * @caps: pointer to common capabilities structure >> + * @elem: the capability element to parse >> + * @prefix: message prefix for tracing capabilities >> + * >> + * Given a capability element, extract relevant details into the common >> + * capability structure. >> + * >> + * Return: true if the capability matches one of the common capability ids, >> + * false otherwise. >> + */ >> +static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_caps *caps, >> + struct ixgbe_aci_cmd_list_caps_elem *elem, >> + const char *prefix) >> +{ >> + u32 logical_id = elem->logical_id; >> + u32 phys_id = elem->phys_id; >> + u32 number = elem->number; >> + u16 cap = elem->cap; >> + >> + switch (cap) { >> + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: >> + caps->valid_functions = number; >> + break; >> + case IXGBE_ACI_CAPS_SRIOV: >> + caps->sr_iov_1_1 = (number == 1); >> + break; >> + case IXGBE_ACI_CAPS_VMDQ: >> + caps->vmdq = (number == 1); >> + break; >> + case IXGBE_ACI_CAPS_DCB: >> + caps->dcb = (number == 1); >> + caps->active_tc_bitmap = logical_id; >> + caps->maxtc = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_RSS: >> + caps->rss_table_size = number; >> + caps->rss_table_entry_width = logical_id; >> + break; >> + case IXGBE_ACI_CAPS_RXQS: >> + caps->num_rxq = number; >> + caps->rxq_first_id = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_TXQS: >> + caps->num_txq = number; >> + caps->txq_first_id = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_MSIX: >> + caps->num_msix_vectors = number; >> + caps->msix_vector_first_id = phys_id; >> + break; >> + case IXGBE_ACI_CAPS_NVM_VER: >> + break; >> + case IXGBE_ACI_CAPS_MAX_MTU: >> + caps->max_mtu = number; >> + break; >> + case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE: >> + caps->pcie_reset_avoidance = (number > 0); >> + break; >> + case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT: >> + caps->reset_restrict_support = (number == 1); >> + break; >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0: >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1: >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2: >> + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3: >> + { >> + u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0; >> + >> + caps->ext_topo_dev_img_ver_high[index] = number; >> + caps->ext_topo_dev_img_ver_low[index] = logical_id; >> + caps->ext_topo_dev_img_part_num[index] = >> + FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id); >> + caps->ext_topo_dev_img_load_en[index] = >> + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0; >> + caps->ext_topo_dev_img_prog_en[index] = >> + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0; >> + break; >> + } >> + default: >> + /* Not one of the recognized common capabilities */ >> + return false; >> + } >> + >> + return true; >> +} >> + >> +/** >> + * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities. >> + */ >> +static void >> +ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >[Kalesh] Do you really need a local variable here? Same comment >applies to functions below as well. >> + >> + dev_p->num_funcs = hweight32(number); >> +} >> + >> +/** >> + * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_VF for device capabilities. >> + */ >> +static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >> + >> + dev_p->num_vfs_exposed = number; >> +} >> + >> +/** >> + * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_VSI for device capabilities. >> + */ >> +static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >> + >> + dev_p->num_vsi_allocd_to_host = number; >> +} >> + >> +/** >> + * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @cap: capability element to parse >> + * >> + * Parse IXGBE_ACI_CAPS_FD for device capabilities. >> + */ >> +static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 number = cap->number; >> + >> + dev_p->num_flow_director_fltr = number; >> +} >> + >> +/** >> + * ixgbe_parse_dev_caps - Parse device capabilities >> + * @hw: pointer to the HW struct >> + * @dev_p: pointer to device capabilities structure >> + * @buf: buffer containing the device capability records >> + * @cap_count: the number of capabilities >> + * >> + * Helper device to parse device (0x000B) capabilities list. For >> + * capabilities shared between device and function, this relies on >> + * ixgbe_parse_e610_caps. >> + * >> + * Loop through the list of provided capabilities and extract the relevant >> + * data into the device capabilities structured. >> + */ >> +static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_dev_caps *dev_p, >> + void *buf, u32 cap_count) >> +{ >> + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; >> + u32 i; >> + >> + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; >> + >> + memset(dev_p, 0, sizeof(*dev_p)); >> + >> + for (i = 0; i < cap_count; i++) { >> + u16 cap = cap_resp[i].cap; >> + >> + ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i], >> + "dev caps"); >> + >> + switch (cap) { >> + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: >> + ixgbe_parse_valid_functions_cap(hw, dev_p, >> + &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_VF: >> + ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_VSI: >> + ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_FD: >> + ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]); >> + break; >> + default: >> + /* Don't list common capabilities as unknown */ >> + break; >> + } >> + } >> +} >> + >> +/** >> + * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps >> + * @hw: pointer to the HW struct >> + * @func_p: pointer to function capabilities structure >> + * @cap: pointer to the capability element to parse >> + * >> + * Extract function capabilities for IXGBE_ACI_CAPS_VF. >> + */ >> +static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + u32 logical_id = cap->logical_id; >> + u32 number = cap->number; >> + >> + func_p->num_allocd_vfs = number; >> + func_p->vf_base_id = logical_id; >> +} >> + >> +/** >> + * ixgbe_get_num_per_func - determine number of resources per PF >> + * @hw: pointer to the HW structure >> + * @max: value to be evenly split between each PF >> + * >> + * Determine the number of valid functions by going through the bitmap returned >> + * from parsing capabilities and use this to calculate the number of resources >> + * per PF based on the max value passed in. >> + * >> + * Return: the number of resources per PF or 0, if no PH are available. >> + */ >> +static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max) >> +{ >> +#define IXGBE_CAPS_VALID_FUNCS_M GENMASK(7, 0) >> + u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions & >> + IXGBE_CAPS_VALID_FUNCS_M); >> + >> + return funcs ? (max / funcs) : 0; >> +} >> + >> +/** >> + * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps >> + * @hw: pointer to the HW struct >> + * @func_p: pointer to function capabilities structure >> + * @cap: pointer to the capability element to parse >> + * >> + * Extract function capabilities for IXGBE_ACI_CAPS_VSI. >> + */ >> +static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_p, >> + struct ixgbe_aci_cmd_list_caps_elem *cap) >> +{ >> + func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI); >> +} >> + >> +/** >> + * ixgbe_parse_func_caps - Parse function capabilities >> + * @hw: pointer to the HW struct >> + * @func_p: pointer to function capabilities structure >> + * @buf: buffer containing the function capability records >> + * @cap_count: the number of capabilities >> + * >> + * Helper function to parse function (0x000A) capabilities list. For >> + * capabilities shared between device and function, this relies on >> + * ixgbe_parse_e610_caps. >> + * >> + * Loop through the list of provided capabilities and extract the relevant >> + * data into the function capabilities structured. >> + */ >> +static void ixgbe_parse_func_caps(struct ixgbe_hw *hw, >> + struct ixgbe_hw_func_caps *func_p, >> + void *buf, u32 cap_count) >> +{ >> + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; >> + u32 i; >> + >> + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; >> + >> + memset(func_p, 0, sizeof(*func_p)); >> + >> + for (i = 0; i < cap_count; i++) { >> + u16 cap = cap_resp[i].cap; >> + >> + ixgbe_parse_e610_caps(hw, &func_p->common_cap, >> + &cap_resp[i], "func caps"); >> + >> + switch (cap) { >> + case IXGBE_ACI_CAPS_VF: >> + ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]); >> + break; >> + case IXGBE_ACI_CAPS_VSI: >> + ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]); >> + break; >> + default: >> + /* Don't list common capabilities as unknown */ >> + break; >> + } >> + } >> +} >> + >> +/** >> + * ixgbe_aci_list_caps - query function/device capabilities >> + * @hw: pointer to the HW struct >> + * @buf: a buffer to hold the capabilities >> + * @buf_size: size of the buffer >> + * @cap_count: if not NULL, set to the number of capabilities reported >> + * @opc: capabilities type to discover, device or function >> + * >> + * Get the function (0x000A) or device (0x000B) capabilities description from >> + * firmware and store it in the buffer. >> + * >> + * If the cap_count pointer is not NULL, then it is set to the number of >> + * capabilities firmware will report. Note that if the buffer size is too >> + * small, it is possible the command will return -ENOMEM. The >> + * cap_count will still be updated in this case. It is recommended that the >> + * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible >> + * buffer that firmware could return) to avoid this. >> + * >> + * Return: the exit code of the operation. >> + * Exit code of -ENOMEM means the buffer size is too small. >> + */ >> +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size, >> + u32 *cap_count, enum ixgbe_aci_opc opc) >> +{ >> + struct ixgbe_aci_cmd_list_caps *cmd; >> + struct ixgbe_aci_desc desc; >> + int err; >> + >> + cmd = &desc.params.get_cap; >> + >> + if (opc != ixgbe_aci_opc_list_func_caps && >> + opc != ixgbe_aci_opc_list_dev_caps) >> + return -EINVAL; >> + >> + ixgbe_fill_dflt_direct_cmd_desc(&desc, opc); >> + err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size); >> + >> + if (cap_count) >[Kalesh] Do you need a check for !err as well here? Thank you for pointing this out - in fact, it is tried/caught by the callers. Piotr [...]
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index 28bd7da..3bc88df 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -493,3 +493,543 @@ void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res) total_delay++; } } + +/** + * ixgbe_parse_e610_caps - Parse common device/function capabilities + * @hw: pointer to the HW struct + * @caps: pointer to common capabilities structure + * @elem: the capability element to parse + * @prefix: message prefix for tracing capabilities + * + * Given a capability element, extract relevant details into the common + * capability structure. + * + * Return: true if the capability matches one of the common capability ids, + * false otherwise. + */ +static bool ixgbe_parse_e610_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_caps *caps, + struct ixgbe_aci_cmd_list_caps_elem *elem, + const char *prefix) +{ + u32 logical_id = elem->logical_id; + u32 phys_id = elem->phys_id; + u32 number = elem->number; + u16 cap = elem->cap; + + switch (cap) { + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: + caps->valid_functions = number; + break; + case IXGBE_ACI_CAPS_SRIOV: + caps->sr_iov_1_1 = (number == 1); + break; + case IXGBE_ACI_CAPS_VMDQ: + caps->vmdq = (number == 1); + break; + case IXGBE_ACI_CAPS_DCB: + caps->dcb = (number == 1); + caps->active_tc_bitmap = logical_id; + caps->maxtc = phys_id; + break; + case IXGBE_ACI_CAPS_RSS: + caps->rss_table_size = number; + caps->rss_table_entry_width = logical_id; + break; + case IXGBE_ACI_CAPS_RXQS: + caps->num_rxq = number; + caps->rxq_first_id = phys_id; + break; + case IXGBE_ACI_CAPS_TXQS: + caps->num_txq = number; + caps->txq_first_id = phys_id; + break; + case IXGBE_ACI_CAPS_MSIX: + caps->num_msix_vectors = number; + caps->msix_vector_first_id = phys_id; + break; + case IXGBE_ACI_CAPS_NVM_VER: + break; + case IXGBE_ACI_CAPS_MAX_MTU: + caps->max_mtu = number; + break; + case IXGBE_ACI_CAPS_PCIE_RESET_AVOIDANCE: + caps->pcie_reset_avoidance = (number > 0); + break; + case IXGBE_ACI_CAPS_POST_UPDATE_RESET_RESTRICT: + caps->reset_restrict_support = (number == 1); + break; + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0: + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG1: + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG2: + case IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG3: + { + u8 index = cap - IXGBE_ACI_CAPS_EXT_TOPO_DEV_IMG0; + + caps->ext_topo_dev_img_ver_high[index] = number; + caps->ext_topo_dev_img_ver_low[index] = logical_id; + caps->ext_topo_dev_img_part_num[index] = + FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id); + caps->ext_topo_dev_img_load_en[index] = + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0; + caps->ext_topo_dev_img_prog_en[index] = + (phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0; + break; + } + default: + /* Not one of the recognized common capabilities */ + return false; + } + + return true; +} + +/** + * ixgbe_parse_valid_functions_cap - Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS caps + * @hw: pointer to the HW struct + * @dev_p: pointer to device capabilities structure + * @cap: capability element to parse + * + * Parse IXGBE_ACI_CAPS_VALID_FUNCTIONS for device capabilities. + */ +static void +ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw, + struct ixgbe_hw_dev_caps *dev_p, + struct ixgbe_aci_cmd_list_caps_elem *cap) +{ + u32 number = cap->number; + + dev_p->num_funcs = hweight32(number); +} + +/** + * ixgbe_parse_vf_dev_caps - Parse IXGBE_ACI_CAPS_VF device caps + * @hw: pointer to the HW struct + * @dev_p: pointer to device capabilities structure + * @cap: capability element to parse + * + * Parse IXGBE_ACI_CAPS_VF for device capabilities. + */ +static void ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_dev_caps *dev_p, + struct ixgbe_aci_cmd_list_caps_elem *cap) +{ + u32 number = cap->number; + + dev_p->num_vfs_exposed = number; +} + +/** + * ixgbe_parse_vsi_dev_caps - Parse IXGBE_ACI_CAPS_VSI device caps + * @hw: pointer to the HW struct + * @dev_p: pointer to device capabilities structure + * @cap: capability element to parse + * + * Parse IXGBE_ACI_CAPS_VSI for device capabilities. + */ +static void ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_dev_caps *dev_p, + struct ixgbe_aci_cmd_list_caps_elem *cap) +{ + u32 number = cap->number; + + dev_p->num_vsi_allocd_to_host = number; +} + +/** + * ixgbe_parse_fdir_dev_caps - Parse IXGBE_ACI_CAPS_FD device caps + * @hw: pointer to the HW struct + * @dev_p: pointer to device capabilities structure + * @cap: capability element to parse + * + * Parse IXGBE_ACI_CAPS_FD for device capabilities. + */ +static void ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_dev_caps *dev_p, + struct ixgbe_aci_cmd_list_caps_elem *cap) +{ + u32 number = cap->number; + + dev_p->num_flow_director_fltr = number; +} + +/** + * ixgbe_parse_dev_caps - Parse device capabilities + * @hw: pointer to the HW struct + * @dev_p: pointer to device capabilities structure + * @buf: buffer containing the device capability records + * @cap_count: the number of capabilities + * + * Helper device to parse device (0x000B) capabilities list. For + * capabilities shared between device and function, this relies on + * ixgbe_parse_e610_caps. + * + * Loop through the list of provided capabilities and extract the relevant + * data into the device capabilities structured. + */ +static void ixgbe_parse_dev_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_dev_caps *dev_p, + void *buf, u32 cap_count) +{ + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; + u32 i; + + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; + + memset(dev_p, 0, sizeof(*dev_p)); + + for (i = 0; i < cap_count; i++) { + u16 cap = cap_resp[i].cap; + + ixgbe_parse_e610_caps(hw, &dev_p->common_cap, &cap_resp[i], + "dev caps"); + + switch (cap) { + case IXGBE_ACI_CAPS_VALID_FUNCTIONS: + ixgbe_parse_valid_functions_cap(hw, dev_p, + &cap_resp[i]); + break; + case IXGBE_ACI_CAPS_VF: + ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]); + break; + case IXGBE_ACI_CAPS_VSI: + ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]); + break; + case IXGBE_ACI_CAPS_FD: + ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]); + break; + default: + /* Don't list common capabilities as unknown */ + break; + } + } +} + +/** + * ixgbe_parse_vf_func_caps - Parse IXGBE_ACI_CAPS_VF function caps + * @hw: pointer to the HW struct + * @func_p: pointer to function capabilities structure + * @cap: pointer to the capability element to parse + * + * Extract function capabilities for IXGBE_ACI_CAPS_VF. + */ +static void ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_func_caps *func_p, + struct ixgbe_aci_cmd_list_caps_elem *cap) +{ + u32 logical_id = cap->logical_id; + u32 number = cap->number; + + func_p->num_allocd_vfs = number; + func_p->vf_base_id = logical_id; +} + +/** + * ixgbe_get_num_per_func - determine number of resources per PF + * @hw: pointer to the HW structure + * @max: value to be evenly split between each PF + * + * Determine the number of valid functions by going through the bitmap returned + * from parsing capabilities and use this to calculate the number of resources + * per PF based on the max value passed in. + * + * Return: the number of resources per PF or 0, if no PH are available. + */ +static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max) +{ +#define IXGBE_CAPS_VALID_FUNCS_M GENMASK(7, 0) + u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions & + IXGBE_CAPS_VALID_FUNCS_M); + + return funcs ? (max / funcs) : 0; +} + +/** + * ixgbe_parse_vsi_func_caps - Parse IXGBE_ACI_CAPS_VSI function caps + * @hw: pointer to the HW struct + * @func_p: pointer to function capabilities structure + * @cap: pointer to the capability element to parse + * + * Extract function capabilities for IXGBE_ACI_CAPS_VSI. + */ +static void ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_func_caps *func_p, + struct ixgbe_aci_cmd_list_caps_elem *cap) +{ + func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI); +} + +/** + * ixgbe_parse_func_caps - Parse function capabilities + * @hw: pointer to the HW struct + * @func_p: pointer to function capabilities structure + * @buf: buffer containing the function capability records + * @cap_count: the number of capabilities + * + * Helper function to parse function (0x000A) capabilities list. For + * capabilities shared between device and function, this relies on + * ixgbe_parse_e610_caps. + * + * Loop through the list of provided capabilities and extract the relevant + * data into the function capabilities structured. + */ +static void ixgbe_parse_func_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_func_caps *func_p, + void *buf, u32 cap_count) +{ + struct ixgbe_aci_cmd_list_caps_elem *cap_resp; + u32 i; + + cap_resp = (struct ixgbe_aci_cmd_list_caps_elem *)buf; + + memset(func_p, 0, sizeof(*func_p)); + + for (i = 0; i < cap_count; i++) { + u16 cap = cap_resp[i].cap; + + ixgbe_parse_e610_caps(hw, &func_p->common_cap, + &cap_resp[i], "func caps"); + + switch (cap) { + case IXGBE_ACI_CAPS_VF: + ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]); + break; + case IXGBE_ACI_CAPS_VSI: + ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]); + break; + default: + /* Don't list common capabilities as unknown */ + break; + } + } +} + +/** + * ixgbe_aci_list_caps - query function/device capabilities + * @hw: pointer to the HW struct + * @buf: a buffer to hold the capabilities + * @buf_size: size of the buffer + * @cap_count: if not NULL, set to the number of capabilities reported + * @opc: capabilities type to discover, device or function + * + * Get the function (0x000A) or device (0x000B) capabilities description from + * firmware and store it in the buffer. + * + * If the cap_count pointer is not NULL, then it is set to the number of + * capabilities firmware will report. Note that if the buffer size is too + * small, it is possible the command will return -ENOMEM. The + * cap_count will still be updated in this case. It is recommended that the + * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible + * buffer that firmware could return) to avoid this. + * + * Return: the exit code of the operation. + * Exit code of -ENOMEM means the buffer size is too small. + */ +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size, + u32 *cap_count, enum ixgbe_aci_opc opc) +{ + struct ixgbe_aci_cmd_list_caps *cmd; + struct ixgbe_aci_desc desc; + int err; + + cmd = &desc.params.get_cap; + + if (opc != ixgbe_aci_opc_list_func_caps && + opc != ixgbe_aci_opc_list_dev_caps) + return -EINVAL; + + ixgbe_fill_dflt_direct_cmd_desc(&desc, opc); + err = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size); + + if (cap_count) + *cap_count = cmd->count; + + return err; +} + +/** + * ixgbe_discover_dev_caps - Read and extract device capabilities + * @hw: pointer to the hardware structure + * @dev_caps: pointer to device capabilities structure + * + * Read the device capabilities and extract them into the dev_caps structure + * for later use. + * + * Return: the exit code of the operation. + */ +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_dev_caps *dev_caps) +{ + u8 *cbuf __free(kfree); + u32 cap_count; + int err; + + cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); + if (!cbuf) + return -ENOMEM; + /* Although the driver doesn't know the number of capabilities the + * device will return, we can simply send a 4KB buffer, the maximum + * possible size that firmware can return. + */ + cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / + sizeof(struct ixgbe_aci_cmd_list_caps_elem); + + err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE, + &cap_count, + ixgbe_aci_opc_list_dev_caps); + if (err) + return err; + + ixgbe_parse_dev_caps(hw, dev_caps, cbuf, cap_count); + + return 0; +} + +/** + * ixgbe_discover_func_caps - Read and extract function capabilities + * @hw: pointer to the hardware structure + * @func_caps: pointer to function capabilities structure + * + * Read the function capabilities and extract them into the func_caps structure + * for later use. + * + * Return: the exit code of the operation. + */ +int ixgbe_discover_func_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_func_caps *func_caps) +{ + u8 *cbuf __free(kfree); + u32 cap_count; + int err; + + cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); + if (!cbuf) + return -ENOMEM; + + /* Although the driver doesn't know the number of capabilities the + * device will return, we can simply send a 4KB buffer, the maximum + * possible size that firmware can return. + */ + cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / + sizeof(struct ixgbe_aci_cmd_list_caps_elem); + + err = ixgbe_aci_list_caps(hw, cbuf, IXGBE_ACI_MAX_BUFFER_SIZE, + &cap_count, + ixgbe_aci_opc_list_func_caps); + if (err) + return err; + + ixgbe_parse_func_caps(hw, func_caps, cbuf, cap_count); + + return 0; +} + +/** + * ixgbe_get_caps - get info about the HW + * @hw: pointer to the hardware structure + * + * Retrieve both device and function capabilities. + * + * Return: the exit code of the operation. + */ +int ixgbe_get_caps(struct ixgbe_hw *hw) +{ + int err; + + err = ixgbe_discover_dev_caps(hw, &hw->dev_caps); + if (err) + return err; + + return ixgbe_discover_func_caps(hw, &hw->func_caps); +} + +/** + * ixgbe_aci_disable_rxen - disable RX + * @hw: pointer to the HW struct + * + * Request a safe disable of Receive Enable using ACI command (0x000C). + * + * Return: the exit code of the operation. + */ +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw) +{ + struct ixgbe_aci_cmd_disable_rxen *cmd; + struct ixgbe_aci_desc desc; + + cmd = &desc.params.disable_rxen; + + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_disable_rxen); + + cmd->lport_num = hw->bus.func; + + return ixgbe_aci_send_cmd(hw, &desc, NULL, 0); +} + +/** + * ixgbe_aci_get_phy_caps - returns PHY capabilities + * @hw: pointer to the HW struct + * @qual_mods: report qualified modules + * @report_mode: report mode capabilities + * @pcaps: structure for PHY capabilities to be filled + * + * Returns the various PHY capabilities supported on the Port + * using ACI command (0x0600). + * + * Return: the exit code of the operation. + */ +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) +{ + struct ixgbe_aci_cmd_get_phy_caps *cmd; + u16 pcaps_size = sizeof(*pcaps); + struct ixgbe_aci_desc desc; + int err; + + cmd = &desc.params.get_phy; + + if (!pcaps || (report_mode & ~IXGBE_ACI_REPORT_MODE_M)) + return -EINVAL; + + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_phy_caps); + + if (qual_mods) + cmd->param0 |= IXGBE_ACI_GET_PHY_RQM; + + cmd->param0 |= report_mode; + err = ixgbe_aci_send_cmd(hw, &desc, pcaps, pcaps_size); + + if (!err && report_mode == IXGBE_ACI_REPORT_TOPO_CAP_MEDIA) { + hw->phy.phy_type_low = pcaps->phy_type_low; + hw->phy.phy_type_high = pcaps->phy_type_high; + memcpy(hw->link.link_info.module_type, &pcaps->module_type, + sizeof(hw->link.link_info.module_type)); + } + + return err; +} + +/** + * ixgbe_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data + * @caps: PHY ability structure to copy data from + * @cfg: PHY configuration structure to copy data to + * + * Helper function to copy data from PHY capabilities data structure + * to PHY configuration data structure + */ +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) +{ + if (!caps || !cfg) + return; + + memset(cfg, 0, sizeof(*cfg)); + cfg->phy_type_low = caps->phy_type_low; + cfg->phy_type_high = caps->phy_type_high; + cfg->caps = caps->caps; + cfg->low_power_ctrl_an = caps->low_power_ctrl_an; + cfg->eee_cap = caps->eee_cap; + cfg->eeer_value = caps->eeer_value; + cfg->link_fec_opt = caps->link_fec_options; + cfg->module_compliance_enforcement = + caps->module_compliance_enforcement; +} diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h index 18b831b..5c5a676 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h @@ -15,5 +15,17 @@ void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode); int ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res, enum ixgbe_aci_res_access_type access, u32 timeout); void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res); +int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size, + u32 *cap_count, enum ixgbe_aci_opc opc); +int ixgbe_discover_dev_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_dev_caps *dev_caps); +int ixgbe_discover_func_caps(struct ixgbe_hw *hw, + struct ixgbe_hw_func_caps *func_caps); +int ixgbe_get_caps(struct ixgbe_hw *hw); +int ixgbe_aci_disable_rxen(struct ixgbe_hw *hw); +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); #endif /* _IXGBE_E610_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 8b8404d..0302a21 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -43,6 +43,7 @@ #include "ixgbe.h" #include "ixgbe_common.h" #include "ixgbe_dcb_82599.h" +#include "ixgbe_e610.h" #include "ixgbe_phy.h" #include "ixgbe_sriov.h" #include "ixgbe_model.h" @@ -10932,6 +10933,13 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_sw_init; + if (adapter->hw.mac.type == ixgbe_mac_e610) { + err = ixgbe_get_caps(&adapter->hw); + if (err) + dev_err(&pdev->dev, + "ixgbe_get_caps failed %d\n", err); + } + if (adapter->hw.mac.type == ixgbe_mac_82599EB) adapter->flags2 |= IXGBE_FLAG2_AUTO_DISABLE_VF;