lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0a836e29-d08f-d14d-3861-fd211113ee35@oracle.com>
Date:   Mon, 12 Mar 2018 19:05:35 -0700
From:   Shannon Nelson <shannon.nelson@...cle.com>
To:     Anirudh Venkataramanan <anirudh.venkataramanan@...el.com>,
        intel-wired-lan@...ts.osuosl.org
Cc:     netdev@...r.kernel.org
Subject: Re: [Intel-wired-lan] [PATCH 04/15] ice: Get switch config, scheduler
 config and device capabilities

On 3/9/2018 9:21 AM, Anirudh Venkataramanan wrote:
> This patch adds to the initialization flow by getting switch
> configuration, scheduler configuration and device capabilities.
> 
> Switch configuration:
> On boot, an L2 switch element is created in the firmware per physical
> function. Each physical function is also mapped to a port, to which its
> switch element is connected. In other words, this switch can be visualized
> as an embedded vSwitch that can connect a physical functions's virtual
> station interfaces (VSIs) to the egress/ingress port. Egress/ingress
> filters will be eventually created and applied on this switch element.
> As part of the initialization flow, the driver gets configuration data
> from this switch element and stores it.
> 
> Scheduler configuration:
> The Tx scheduler is a subsystem responsible for setting and enforcing QoS.
> As part of the initialization flow, the driver queries and stores the
> default scheduler configuration for the given physical function.
> 
> Device capabilities:
> As part of initialization, the driver has to determine what the device is
> capable of (ex. max queues, VSIs, etc). This information is obtained from
> the firmware and stored by the driver.
> 
> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@...el.com>
> ---
>   drivers/net/ethernet/intel/ice/Makefile         |   4 +-
>   drivers/net/ethernet/intel/ice/ice.h            |   2 +
>   drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 209 ++++++++++++++
>   drivers/net/ethernet/intel/ice/ice_common.c     | 223 +++++++++++++++
>   drivers/net/ethernet/intel/ice/ice_common.h     |   2 +
>   drivers/net/ethernet/intel/ice/ice_sched.c      | 354 ++++++++++++++++++++++++
>   drivers/net/ethernet/intel/ice/ice_sched.h      |  42 +++
>   drivers/net/ethernet/intel/ice/ice_switch.c     | 158 +++++++++++
>   drivers/net/ethernet/intel/ice/ice_switch.h     |  28 ++
>   drivers/net/ethernet/intel/ice/ice_type.h       | 109 ++++++++
>   10 files changed, 1130 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/net/ethernet/intel/ice/ice_sched.c
>   create mode 100644 drivers/net/ethernet/intel/ice/ice_sched.h
>   create mode 100644 drivers/net/ethernet/intel/ice/ice_switch.c
>   create mode 100644 drivers/net/ethernet/intel/ice/ice_switch.h
> 
> diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
> index 373d481dbb25..809d85c04398 100644
> --- a/drivers/net/ethernet/intel/ice/Makefile
> +++ b/drivers/net/ethernet/intel/ice/Makefile
> @@ -27,4 +27,6 @@ obj-$(CONFIG_ICE) += ice.o
>   ice-y := ice_main.o	\
>   	 ice_controlq.o	\
>   	 ice_common.o	\
> -	 ice_nvm.o
> +	 ice_nvm.o	\
> +	 ice_switch.o	\
> +	 ice_sched.o
> diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
> index ab2800c31906..f6e3339591bb 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -30,7 +30,9 @@
>   #include <linux/bitmap.h>
>   #include "ice_devids.h"
>   #include "ice_type.h"
> +#include "ice_switch.h"
>   #include "ice_common.h"
> +#include "ice_sched.h"
>   
>   #define ICE_BAR0		0
>   #define ICE_AQ_LEN		64
> diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> index 05b22a1ffd70..66a3f41df673 100644
> --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
> @@ -22,6 +22,8 @@
>    * descriptor format.  It is shared between Firmware and Software.
>    */
>   
> +#define ICE_AQC_TOPO_MAX_LEVEL_NUM	0x9
> +
>   struct ice_aqc_generic {
>   	__le32 param0;
>   	__le32 param1;
> @@ -82,6 +84,40 @@ struct ice_aqc_req_res {
>   	u8 reserved[2];
>   };
>   
> +/* Get function capabilities (indirect 0x000A)
> + * Get device capabilities (indirect 0x000B)
> + */
> +struct ice_aqc_list_caps {
> +	u8 cmd_flags;
> +	u8 pf_index;
> +	u8 reserved[2];
> +	__le32 count;
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +/* Device/Function buffer entry, repeated per reported capability */
> +struct ice_aqc_list_caps_elem {
> +	__le16 cap;
> +#define ICE_AQC_CAPS_VSI				0x0017
> +#define ICE_AQC_CAPS_RSS				0x0040
> +#define ICE_AQC_CAPS_RXQS				0x0041
> +#define ICE_AQC_CAPS_TXQS				0x0042
> +#define ICE_AQC_CAPS_MSIX				0x0043
> +#define ICE_AQC_CAPS_MAX_MTU				0x0047
> +
> +	u8 major_ver;
> +	u8 minor_ver;
> +	/* Number of resources described by this capability */
> +	__le32 number;
> +	/* Only meaningful for some types of resources */
> +	__le32 logical_id;
> +	/* Only meaningful for some types of resources */
> +	__le32 phys_id;
> +	__le64 rsvd1;
> +	__le64 rsvd2;
> +};
> +
>   /* Clear PXE Command and response (direct 0x0110) */
>   struct ice_aqc_clear_pxe {
>   	u8 rx_cnt;
> @@ -89,6 +125,161 @@ struct ice_aqc_clear_pxe {
>   	u8 reserved[15];
>   };
>   
> +/* Get switch configuration (0x0200) */
> +struct ice_aqc_get_sw_cfg {
> +	/* Reserved for command and copy of request flags for response */
> +	__le16 flags;
> +	/* First desc in case of command and next_elem in case of response
> +	 * In case of response, if it is not zero, means all the configuration
> +	 * was not returned and new command shall be sent with this value in
> +	 * the 'first desc' field
> +	 */
> +	__le16 element;
> +	/* Reserved for command, only used for response */
> +	__le16 num_elems;
> +	__le16 rsvd;
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +/* Each entry in the response buffer is of the following type: */
> +struct ice_aqc_get_sw_cfg_resp_elem {
> +	/* VSI/Port Number */
> +	__le16 vsi_port_num;
> +#define ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_S	0
> +#define ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M	\
> +			(0x3FF << ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_S)
> +#define ICE_AQC_GET_SW_CONF_RESP_TYPE_S	14
> +#define ICE_AQC_GET_SW_CONF_RESP_TYPE_M	(0x3 << ICE_AQC_GET_SW_CONF_RESP_TYPE_S)
> +#define ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT	0
> +#define ICE_AQC_GET_SW_CONF_RESP_VIRT_PORT	1
> +#define ICE_AQC_GET_SW_CONF_RESP_VSI		2
> +
> +	/* SWID VSI/Port belongs to */
> +	__le16 swid;
> +
> +	/* Bit 14..0 : PF/VF number VSI belongs to
> +	 * Bit 15 : VF indication bit
> +	 */
> +	__le16 pf_vf_num;
> +#define ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_S	0
> +#define ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M	\
> +				(0x7FFF << ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_S)
> +#define ICE_AQC_GET_SW_CONF_RESP_IS_VF		BIT(15)
> +};
> +
> +/* The response buffer is as follows. Note that the length of the
> + * elements array varies with the length of the command response.
> + */
> +struct ice_aqc_get_sw_cfg_resp {
> +	struct ice_aqc_get_sw_cfg_resp_elem elements[1];
> +};
> +
> +/* Add TSE (indirect 0x0401)
> + * Delete TSE (indirect 0x040F)
> + * Move TSE (indirect 0x0408)
> + */
> +struct ice_aqc_add_move_delete_elem {
> +	__le16 num_grps_req;
> +	__le16 num_grps_updated;
> +	__le32 reserved;
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +struct ice_aqc_elem_info_bw {
> +	__le16 bw_profile_idx;
> +	__le16 bw_alloc;
> +};
> +
> +struct ice_aqc_txsched_elem {
> +	u8 elem_type; /* Special field, reserved for some aq calls */
> +#define ICE_AQC_ELEM_TYPE_UNDEFINED		0x0
> +#define ICE_AQC_ELEM_TYPE_ROOT_PORT		0x1
> +#define ICE_AQC_ELEM_TYPE_TC			0x2
> +#define ICE_AQC_ELEM_TYPE_SE_GENERIC		0x3
> +#define ICE_AQC_ELEM_TYPE_ENTRY_POINT		0x4
> +#define ICE_AQC_ELEM_TYPE_LEAF			0x5
> +#define ICE_AQC_ELEM_TYPE_SE_PADDED		0x6
> +	u8 valid_sections;
> +#define ICE_AQC_ELEM_VALID_GENERIC		BIT(0)
> +#define ICE_AQC_ELEM_VALID_CIR			BIT(1)
> +#define ICE_AQC_ELEM_VALID_EIR			BIT(2)
> +#define ICE_AQC_ELEM_VALID_SHARED		BIT(3)
> +	u8 generic;
> +#define ICE_AQC_ELEM_GENERIC_MODE_M		0x1
> +#define ICE_AQC_ELEM_GENERIC_PRIO_S		0x1
> +#define ICE_AQC_ELEM_GENERIC_PRIO_M	(0x7 << ICE_AQC_ELEM_GENERIC_PRIO_S)
> +#define ICE_AQC_ELEM_GENERIC_SP_S		0x4
> +#define ICE_AQC_ELEM_GENERIC_SP_M	(0x1 << ICE_AQC_ELEM_GENERIC_SP_S)
> +#define ICE_AQC_ELEM_GENERIC_ADJUST_VAL_S	0x5
> +#define ICE_AQC_ELEM_GENERIC_ADJUST_VAL_M	\
> +	(0x3 << ICE_AQC_ELEM_GENERIC_ADJUST_VAL_S)
> +	u8 flags; /* Special field, reserved for some aq calls */
> +#define ICE_AQC_ELEM_FLAG_SUSPEND_M		0x1
> +	struct ice_aqc_elem_info_bw cir_bw;
> +	struct ice_aqc_elem_info_bw eir_bw;
> +	__le16 srl_id;
> +	__le16 reserved2;
> +};
> +
> +struct ice_aqc_txsched_elem_data {
> +	__le32 parent_teid;
> +	__le32 node_teid;
> +	struct ice_aqc_txsched_elem data;
> +};
> +
> +struct ice_aqc_txsched_topo_grp_info_hdr {
> +	__le32 parent_teid;
> +	__le16 num_elems;
> +	__le16 reserved2;
> +};
> +
> +struct ice_aqc_delete_elem {
> +	struct ice_aqc_txsched_topo_grp_info_hdr hdr;
> +	__le32 teid[1];
> +};
> +
> +/* Query Scheduler Resource Allocation (indirect 0x0412)
> + * This indirect command retrieves the scheduler resources allocated by
> + * EMP Firmware to the given PF.
> + */
> +struct ice_aqc_query_txsched_res {
> +	u8 reserved[8];
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +struct ice_aqc_generic_sched_props {
> +	__le16 phys_levels;
> +	__le16 logical_levels;
> +	u8 flattening_bitmap;
> +	u8 max_device_cgds;
> +	u8 max_pf_cgds;
> +	u8 rsvd0;
> +	__le16 rdma_qsets;
> +	u8 rsvd1[22];
> +};
> +
> +struct ice_aqc_layer_props {
> +	u8 logical_layer;
> +	u8 chunk_size;
> +	__le16 max_device_nodes;
> +	__le16 max_pf_nodes;
> +	u8 rsvd0[2];
> +	__le16 max_shared_rate_lmtr;
> +	__le16 max_children;
> +	__le16 max_cir_rl_profiles;
> +	__le16 max_eir_rl_profiles;
> +	__le16 max_srl_profiles;
> +	u8 rsvd1[14];
> +};
> +
> +struct ice_aqc_query_txsched_res_resp {
> +	struct ice_aqc_generic_sched_props sched_props;
> +	struct ice_aqc_layer_props layer_props[ICE_AQC_TOPO_MAX_LEVEL_NUM];
> +};
> +
>   /* NVM Read command (indirect 0x0701)
>    * NVM Erase commands (direct 0x0702)
>    * NVM Update commands (indirect 0x0703)
> @@ -142,6 +333,10 @@ struct ice_aq_desc {
>   		struct ice_aqc_q_shutdown q_shutdown;
>   		struct ice_aqc_req_res res_owner;
>   		struct ice_aqc_clear_pxe clear_pxe;
> +		struct ice_aqc_list_caps get_cap;
> +		struct ice_aqc_get_sw_cfg get_sw_conf;
> +		struct ice_aqc_query_txsched_res query_sched_res;
> +		struct ice_aqc_add_move_delete_elem add_move_delete_elem;
>   		struct ice_aqc_nvm nvm;
>   	} params;
>   };
> @@ -150,16 +345,19 @@ struct ice_aq_desc {
>   #define ICE_AQ_LG_BUF	512
>   
>   #define ICE_AQ_FLAG_LB_S	9
> +#define ICE_AQ_FLAG_RD_S	10
>   #define ICE_AQ_FLAG_BUF_S	12
>   #define ICE_AQ_FLAG_SI_S	13
>   
>   #define ICE_AQ_FLAG_LB		BIT(ICE_AQ_FLAG_LB_S)  /* 0x200  */
> +#define ICE_AQ_FLAG_RD		BIT(ICE_AQ_FLAG_RD_S)  /* 0x400  */
>   #define ICE_AQ_FLAG_BUF		BIT(ICE_AQ_FLAG_BUF_S) /* 0x1000 */
>   #define ICE_AQ_FLAG_SI		BIT(ICE_AQ_FLAG_SI_S)  /* 0x2000 */
>   
>   /* error codes */
>   enum ice_aq_err {
>   	ICE_AQ_RC_OK		= 0,  /* success */
> +	ICE_AQ_RC_ENOMEM	= 9,  /* Out of memory */
>   	ICE_AQ_RC_EBUSY		= 12, /* Device or resource busy */
>   	ICE_AQ_RC_EEXIST	= 13, /* object already exists */
>   };
> @@ -174,11 +372,22 @@ enum ice_adminq_opc {
>   	ice_aqc_opc_req_res				= 0x0008,
>   	ice_aqc_opc_release_res				= 0x0009,
>   
> +	/* device/function capabilities */
> +	ice_aqc_opc_list_func_caps			= 0x000A,
> +	ice_aqc_opc_list_dev_caps			= 0x000B,
> +
>   	/* PXE */
>   	ice_aqc_opc_clear_pxe_mode			= 0x0110,
>   
> +	/* internal switch commands */
> +	ice_aqc_opc_get_sw_cfg				= 0x0200,
> +
>   	ice_aqc_opc_clear_pf_cfg			= 0x02A4,
>   
> +	/* transmit scheduler commands */
> +	ice_aqc_opc_delete_sched_elems			= 0x040F,
> +	ice_aqc_opc_query_sched_res			= 0x0412,
> +
>   	/* NVM commands */
>   	ice_aqc_opc_nvm_read				= 0x0701,
>   
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
> index eb3e06488705..a64e406c129a 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.c
> +++ b/drivers/net/ethernet/intel/ice/ice_common.c
> @@ -16,9 +16,12 @@
>    */
>   
>   #include "ice_common.h"
> +#include "ice_sched.h"
>   #include "ice_adminq_cmd.h"
>   
>   #define ICE_PF_RESET_WAIT_COUNT	200
> +#define ICE_GET_CAP_BUF_COUNT	40
> +#define ICE_GET_CAP_RETRY_COUNT	20
>   
>   /**
>    * ice_set_mac_type - Sets MAC type
> @@ -84,8 +87,37 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
>   	if (status)
>   		goto err_unroll_cqinit;
>   
> +	status = ice_get_caps(hw);
> +	if (status)
> +		goto err_unroll_cqinit;
> +
> +	hw->port_info = devm_kzalloc(ice_hw_to_dev(hw),
> +				     sizeof(*hw->port_info), GFP_KERNEL);
> +	if (!hw->port_info) {
> +		status = ICE_ERR_NO_MEMORY;
> +		goto err_unroll_cqinit;
> +	}
> +
> +	/* set the back pointer to hw */
> +	hw->port_info->hw = hw;
> +
> +	/* Initialize port_info struct with switch configuration data */
> +	status = ice_get_initial_sw_cfg(hw);
> +	if (status)
> +		goto err_unroll_alloc;
> +
> +	/* Query the allocated resources for tx scheduler */
> +	status = ice_sched_query_res_alloc(hw);
> +	if (status) {
> +		ice_debug(hw, ICE_DBG_SCHED,
> +			  "Failed to get scheduler allocated resources\n");
> +		goto err_unroll_alloc;
> +	}
> +
>   	return 0;
>   
> +err_unroll_alloc:
> +	devm_kfree(ice_hw_to_dev(hw), hw->port_info);
>   err_unroll_cqinit:
>   	ice_shutdown_all_ctrlq(hw);
>   	return status;
> @@ -97,7 +129,12 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
>    */
>   void ice_deinit_hw(struct ice_hw *hw)
>   {
> +	ice_sched_cleanup_all(hw);
>   	ice_shutdown_all_ctrlq(hw);
> +	if (hw->port_info) {
> +		devm_kfree(ice_hw_to_dev(hw), hw->port_info);
> +		hw->port_info = NULL;
> +	}
>   }
>   
>   /**
> @@ -519,6 +556,192 @@ void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
>   	}
>   }
>   
> +/**
> + * ice_parse_caps - parse function/device capabilities
> + * @hw: pointer to the hw struct
> + * @buf: pointer to a buffer containing function/device capability records
> + * @cap_count: number of capability records in the list
> + * @opc: type of capabilities list to parse
> + *
> + * Helper function to parse function(0x000a)/device(0x000b) capabilities list.
> + */
> +static void
> +ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
> +	       enum ice_adminq_opc opc)
> +{
> +	struct ice_aqc_list_caps_elem *cap_resp;
> +	struct ice_hw_func_caps *func_p = NULL;
> +	struct ice_hw_dev_caps *dev_p = NULL;
> +	struct ice_hw_common_caps *caps;
> +	u32 i;
> +
> +	if (!buf)
> +		return;
> +
> +	cap_resp = (struct ice_aqc_list_caps_elem *)buf;
> +
> +	if (opc == ice_aqc_opc_list_dev_caps) {
> +		dev_p = &hw->dev_caps;
> +		caps = &dev_p->common_cap;
> +	} else if (opc == ice_aqc_opc_list_func_caps) {
> +		func_p = &hw->func_caps;
> +		caps = &func_p->common_cap;
> +	} else {
> +		ice_debug(hw, ICE_DBG_INIT, "wrong opcode\n");
> +		return;
> +	}
> +
> +	for (i = 0; caps && i < cap_count; i++, cap_resp++) {
> +		u32 logical_id = le32_to_cpu(cap_resp->logical_id);
> +		u32 phys_id = le32_to_cpu(cap_resp->phys_id);
> +		u32 number = le32_to_cpu(cap_resp->number);
> +		u16 cap = le16_to_cpu(cap_resp->cap);
> +
> +		switch (cap) {
> +		case ICE_AQC_CAPS_VSI:
> +			if (dev_p) {
> +				dev_p->num_vsi_allocd_to_host = number;
> +				ice_debug(hw, ICE_DBG_INIT,
> +					  "HW caps: Dev.VSI cnt = %d\n",
> +					  dev_p->num_vsi_allocd_to_host);
> +			} else if (func_p) {
> +				func_p->guaranteed_num_vsi = number;
> +				ice_debug(hw, ICE_DBG_INIT,
> +					  "HW caps: Func.VSI cnt = %d\n",
> +					  func_p->guaranteed_num_vsi);
> +			}
> +			break;
> +		case ICE_AQC_CAPS_RSS:
> +			caps->rss_table_size = number;
> +			caps->rss_table_entry_width = logical_id;
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: RSS table size = %d\n",
> +				  caps->rss_table_size);
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: RSS table width = %d\n",
> +				  caps->rss_table_entry_width);
> +			break;
> +		case ICE_AQC_CAPS_RXQS:
> +			caps->num_rxq = number;
> +			caps->rxq_first_id = phys_id;
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: Num Rx Qs = %d\n", caps->num_rxq);
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: Rx first queue ID = %d\n",
> +				  caps->rxq_first_id);
> +			break;
> +		case ICE_AQC_CAPS_TXQS:
> +			caps->num_txq = number;
> +			caps->txq_first_id = phys_id;
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: Num Tx Qs = %d\n", caps->num_txq);
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: Tx first queue ID = %d\n",
> +				  caps->txq_first_id);
> +			break;
> +		case ICE_AQC_CAPS_MSIX:
> +			caps->num_msix_vectors = number;
> +			caps->msix_vector_first_id = phys_id;
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: MSIX vector count = %d\n",
> +				  caps->num_msix_vectors);
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: MSIX first vector index = %d\n",
> +				  caps->msix_vector_first_id);
> +			break;
> +		case ICE_AQC_CAPS_MAX_MTU:
> +			caps->max_mtu = number;
> +			if (dev_p)
> +				ice_debug(hw, ICE_DBG_INIT,
> +					  "HW caps: Dev.MaxMTU = %d\n",
> +					  caps->max_mtu);
> +			else if (func_p)
> +				ice_debug(hw, ICE_DBG_INIT,
> +					  "HW caps: func.MaxMTU = %d\n",
> +					  caps->max_mtu);
> +			break;
> +		default:
> +			ice_debug(hw, ICE_DBG_INIT,
> +				  "HW caps: Unknown capability[%d]: 0x%x\n", i,
> +				  cap);
> +			break;
> +		}
> +	}
> +}
> +
> +/**
> + * ice_aq_discover_caps - query function/device capabilities
> + * @hw: pointer to the hw struct
> + * @buf: a virtual buffer to hold the capabilities
> + * @buf_size: Size of the virtual buffer
> + * @data_size: Size of the returned data, or buf size needed if AQ err==ENOMEM
> + * @opc: capabilities type to discover - pass in the command opcode
> + * @cd: pointer to command details structure or NULL
> + *
> + * Get the function(0x000a)/device(0x000b) capabilities description from
> + * the firmware.
> + */
> +static enum ice_status
> +ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u16 *data_size,
> +		     enum ice_adminq_opc opc, struct ice_sq_cd *cd)
> +{
> +	struct ice_aqc_list_caps *cmd;
> +	struct ice_aq_desc desc;
> +	enum ice_status status;
> +
> +	cmd = &desc.params.get_cap;
> +
> +	if (opc != ice_aqc_opc_list_func_caps &&
> +	    opc != ice_aqc_opc_list_dev_caps)
> +		return ICE_ERR_PARAM;
> +
> +	ice_fill_dflt_direct_cmd_desc(&desc, opc);
> +
> +	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
> +	if (!status)
> +		ice_parse_caps(hw, buf, le32_to_cpu(cmd->count), opc);
> +	*data_size = le16_to_cpu(desc.datalen);
> +
> +	return status;
> +}
> +
> +/**
> + * ice_get_caps - get info about the HW
> + * @hw: pointer to the hardware structure
> + */
> +enum ice_status ice_get_caps(struct ice_hw *hw)
> +{
> +	enum ice_status status;
> +	u16 data_size = 0;
> +	u16 cbuf_len;
> +	u8 retries;
> +
> +	cbuf_len = ICE_GET_CAP_BUF_COUNT *
> +		sizeof(struct ice_aqc_list_caps_elem);
> +
> +	retries = ICE_GET_CAP_RETRY_COUNT;
> +
> +	do {
> +		void *cbuf;
> +
> +		cbuf = devm_kzalloc(ice_hw_to_dev(hw), cbuf_len, GFP_KERNEL);
> +		if (!cbuf)
> +			return ICE_ERR_NO_MEMORY;
> +
> +		status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &data_size,
> +					      ice_aqc_opc_list_func_caps, NULL);
> +		devm_kfree(ice_hw_to_dev(hw), cbuf);
> +
> +		if (!status || hw->adminq.sq_last_status != ICE_AQ_RC_ENOMEM)
> +			break;
> +
> +		/* If ENOMEM is returned, try again with bigger buffer */
> +		cbuf_len = data_size;
> +	} while (--retries);

If data size is the only reason for a retry, why bother with a retries 
variable of 20?  Is there any reason you won't be given the right 
data_size hint the first time?

sln

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ