From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from aserp2130.oracle.com ([141.146.126.79]:46316 "EHLO aserp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932246AbeCMCFu (ORCPT ); Mon, 12 Mar 2018 22:05:50 -0400 Subject: Re: [Intel-wired-lan] [PATCH 07/15] ice: Add support for VSI allocation and deallocation To: Anirudh Venkataramanan , intel-wired-lan@lists.osuosl.org Cc: netdev@vger.kernel.org References: <20180309172136.9073-1-anirudh.venkataramanan@intel.com> <20180309172136.9073-8-anirudh.venkataramanan@intel.com> From: Shannon Nelson Message-ID: <88c85157-283d-d370-cd27-0da5f4e1c56e@oracle.com> Date: Mon, 12 Mar 2018 19:05:44 -0700 MIME-Version: 1.0 In-Reply-To: <20180309172136.9073-8-anirudh.venkataramanan@intel.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: netdev-owner@vger.kernel.org List-ID: On 3/9/2018 9:21 AM, Anirudh Venkataramanan wrote: > This patch introduces data structures and functions to alloc/free > VSIs. The driver represents a VSI using the ice_vsi structure. > > Some noteworthy points about VSI allocation: > > 1) A VSI is allocated in the firmware using the "add VSI" admin queue > command (implemented as ice_aq_add_vsi). The firmware returns an > identifier for the allocated VSI. The VSI context is used to program > certain aspects (loopback, queue map, etc.) of the VSI's configuration. > > 2) A VSI is deleted using the "free VSI" admin queue command (implemented > as ice_aq_free_vsi). > > 3) The driver represents a VSI using struct ice_vsi. This is allocated > and initialized as part of the ice_vsi_alloc flow, and deallocated > as part of the ice_vsi_delete flow. > > 4) Once the VSI is created, a netdev is allocated and associated with it. > The VSI's ring and vector related data structures are also allocated > and initialized. > > 5) A VSI's queues can either be contiguous or scattered. To do this, the > driver maintains a bitmap (vsi->avail_txqs) which is kept in sync with > the firmware's VSI queue allocation imap. If the VSI can't get a > contiguous queue allocation, it will fallback to scatter. This is > implemented in ice_vsi_get_qs which is called as part of the VSI setup > flow. In the release flow, the VSI's queues are released and the bitmap > is updated to reflect this by ice_vsi_put_qs. > > Signed-off-by: Anirudh Venkataramanan > --- > drivers/net/ethernet/intel/ice/ice.h | 71 ++ > drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 199 ++++ > drivers/net/ethernet/intel/ice/ice_main.c | 1108 +++++++++++++++++++++++ > drivers/net/ethernet/intel/ice/ice_switch.c | 115 +++ > drivers/net/ethernet/intel/ice/ice_switch.h | 21 + > drivers/net/ethernet/intel/ice/ice_txrx.h | 26 + > drivers/net/ethernet/intel/ice/ice_type.h | 4 + > 7 files changed, 1544 insertions(+) > > diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h > index c8079c852a48..b169f3751cc9 100644 > --- a/drivers/net/ethernet/intel/ice/ice.h > +++ b/drivers/net/ethernet/intel/ice/ice.h > @@ -25,6 +25,8 @@ > #include > #include > #include > +#include > +#include > #include > #include > #include > @@ -32,6 +34,7 @@ > #include > #include > #include > +#include > #include > #include "ice_devids.h" > #include "ice_type.h" > @@ -41,17 +44,42 @@ > #include "ice_sched.h" > > #define ICE_BAR0 0 > +#define ICE_DFLT_NUM_DESC 128 > +#define ICE_REQ_DESC_MULTIPLE 32 > #define ICE_INT_NAME_STR_LEN (IFNAMSIZ + 16) > #define ICE_AQ_LEN 64 > #define ICE_MIN_MSIX 2 > #define ICE_MAX_VSI_ALLOC 130 > #define ICE_MAX_TXQS 2048 > #define ICE_MAX_RXQS 2048 > +#define ICE_VSI_MAP_CONTIG 0 > +#define ICE_VSI_MAP_SCATTER 1 > +#define ICE_MAX_SCATTER_TXQS 16 > +#define ICE_MAX_SCATTER_RXQS 16 > #define ICE_RES_VALID_BIT 0x8000 > #define ICE_RES_MISC_VEC_ID (ICE_RES_VALID_BIT - 1) > +#define ICE_INVAL_Q_INDEX 0xffff > > #define ICE_DFLT_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) > > +#define ICE_MAX_MTU (ICE_AQ_SET_MAC_FRAME_SIZE_MAX - \ > + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN) > + > +#define ICE_UP_TABLE_TRANSLATE(val, i) \ > + (((val) << ICE_AQ_VSI_UP_TABLE_UP##i##_S) & \ > + ICE_AQ_VSI_UP_TABLE_UP##i##_M) > + > +struct ice_tc_info { > + u16 qoffset; > + u16 qcount; > +}; > + > +struct ice_tc_cfg { > + u8 numtc; /* Total number of enabled TCs */ > + u8 ena_tc; /* TX map */ > + struct ice_tc_info tc_info[ICE_MAX_TRAFFIC_CLASS]; > +}; > + > struct ice_res_tracker { > u16 num_entries; > u16 search_hint; > @@ -75,8 +103,47 @@ enum ice_state { > /* struct that defines a VSI, associated with a dev */ > struct ice_vsi { > struct net_device *netdev; > + struct ice_sw *vsw; /* switch this VSI is on */ > + struct ice_pf *back; /* back pointer to PF */ > struct ice_port_info *port_info; /* back pointer to port_info */ > + struct ice_ring **rx_rings; /* rx ring array */ > + struct ice_ring **tx_rings; /* tx ring array */ > + struct ice_q_vector **q_vectors; /* q_vector array */ > + DECLARE_BITMAP(state, __ICE_STATE_NBITS); > + int num_q_vectors; > + int base_vector; > + enum ice_vsi_type type; > u16 vsi_num; /* HW (absolute) index of this VSI */ > + u16 idx; /* software index in pf->vsi[] */ > + > + /* Interrupt thresholds */ > + u16 work_lmt; > + > + struct ice_aqc_vsi_props info; /* VSI properties */ > + > + /* queue information */ > + u8 tx_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ > + u8 rx_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ > + u16 txq_map[ICE_MAX_TXQS]; /* index in pf->avail_txqs */ > + u16 rxq_map[ICE_MAX_RXQS]; /* index in pf->avail_rxqs */ > + u16 alloc_txq; /* Allocated Tx queues */ > + u16 num_txq; /* Used Tx queues */ > + u16 alloc_rxq; /* Allocated Rx queues */ > + u16 num_rxq; /* Used Rx queues */ > + u16 num_desc; > + struct ice_tc_cfg tc_cfg; > +} ____cacheline_internodealigned_in_smp; > + > +/* struct that defines an interrupt vector */ > +struct ice_q_vector { > + struct ice_vsi *vsi; > + cpumask_t affinity_mask; > + struct napi_struct napi; > + struct ice_ring_container rx; > + struct ice_ring_container tx; > + u16 v_idx; /* index in the vsi->q_vector array. */ > + u8 num_ring_tx; /* total number of tx rings in vector */ > + u8 num_ring_rx; /* total number of rx rings in vector */ > } ____cacheline_internodealigned_in_smp; > > enum ice_pf_flags { > @@ -117,6 +184,10 @@ struct ice_pf { > char int_name[ICE_INT_NAME_STR_LEN]; > }; > > +struct ice_netdev_priv { > + struct ice_vsi *vsi; > +}; > + > /** > * ice_irq_dynamic_ena - Enable default interrupt generation settings > * @hw: pointer to hw struct > diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h > index 1acd936eec49..570169c99786 100644 > --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h > +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h > @@ -23,6 +23,7 @@ > */ > > #define ICE_AQC_TOPO_MAX_LEVEL_NUM 0x9 > +#define ICE_AQ_SET_MAC_FRAME_SIZE_MAX 9728 > > struct ice_aqc_generic { > __le32 param0; > @@ -204,6 +205,199 @@ struct ice_aqc_get_sw_cfg_resp { > struct ice_aqc_get_sw_cfg_resp_elem elements[1]; > }; > > +/* Add VSI (indirect 0x0210) > + * Update VSI (indirect 0x0211) > + * Get VSI (indirect 0x0212) > + * Free VSI (indirect 0x0213) > + */ > +struct ice_aqc_add_get_update_free_vsi { > + __le16 vsi_num; > +#define ICE_AQ_VSI_NUM_S 0 > +#define ICE_AQ_VSI_NUM_M (0x03FF << ICE_AQ_VSI_NUM_S) > +#define ICE_AQ_VSI_IS_VALID BIT(15) > + __le16 cmd_flags; > +#define ICE_AQ_VSI_KEEP_ALLOC 0x1 > + u8 vf_id; > + u8 reserved; > + __le16 vsi_flags; > +#define ICE_AQ_VSI_TYPE_S 0 > +#define ICE_AQ_VSI_TYPE_M (0x3 << ICE_AQ_VSI_TYPE_S) > +#define ICE_AQ_VSI_TYPE_VF 0x0 > +#define ICE_AQ_VSI_TYPE_VMDQ2 0x1 > +#define ICE_AQ_VSI_TYPE_PF 0x2 > +#define ICE_AQ_VSI_TYPE_EMP_MNG 0x3 > + __le32 addr_high; > + __le32 addr_low; > +}; > + > +/* Response descriptor for: > + * Add VSI (indirect 0x0210) > + * Update VSI (indirect 0x0211) > + * Free VSI (indirect 0x0213) > + */ > +struct ice_aqc_add_update_free_vsi_resp { > + __le16 vsi_num; > + __le16 ext_status; > + __le16 vsi_used; > + __le16 vsi_free; > + __le32 addr_high; > + __le32 addr_low; > +}; > + > +struct ice_aqc_vsi_props { > + __le16 valid_sections; > +#define ICE_AQ_VSI_PROP_SW_VALID BIT(0) > +#define ICE_AQ_VSI_PROP_SECURITY_VALID BIT(1) > +#define ICE_AQ_VSI_PROP_VLAN_VALID BIT(2) > +#define ICE_AQ_VSI_PROP_OUTER_TAG_VALID BIT(3) > +#define ICE_AQ_VSI_PROP_INGRESS_UP_VALID BIT(4) > +#define ICE_AQ_VSI_PROP_EGRESS_UP_VALID BIT(5) > +#define ICE_AQ_VSI_PROP_RXQ_MAP_VALID BIT(6) > +#define ICE_AQ_VSI_PROP_Q_OPT_VALID BIT(7) > +#define ICE_AQ_VSI_PROP_OUTER_UP_VALID BIT(8) > +#define ICE_AQ_VSI_PROP_FLOW_DIR_VALID BIT(11) > +#define ICE_AQ_VSI_PROP_PASID_VALID BIT(12) > + /* switch section */ > + u8 sw_id; > + u8 sw_flags; > +#define ICE_AQ_VSI_SW_FLAG_ALLOW_LB BIT(5) > +#define ICE_AQ_VSI_SW_FLAG_LOCAL_LB BIT(6) > +#define ICE_AQ_VSI_SW_FLAG_SRC_PRUNE BIT(7) > + u8 sw_flags2; > +#define ICE_AQ_VSI_SW_FLAG_RX_PRUNE_EN_S 0 > +#define ICE_AQ_VSI_SW_FLAG_RX_PRUNE_EN_M \ > + (0xF << ICE_AQ_VSI_SW_FLAG_RX_PRUNE_EN_S) > +#define ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA BIT(0) > +#define ICE_AQ_VSI_SW_FLAG_LAN_ENA BIT(4) > + u8 veb_stat_id; > +#define ICE_AQ_VSI_SW_VEB_STAT_ID_S 0 > +#define ICE_AQ_VSI_SW_VEB_STAT_ID_M (0x1F << ICE_AQ_VSI_SW_VEB_STAT_ID_S) > +#define ICE_AQ_VSI_SW_VEB_STAT_ID_VALID BIT(5) > + /* security section */ > + u8 sec_flags; > +#define ICE_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD BIT(0) > +#define ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF BIT(2) > +#define ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S 4 > +#define ICE_AQ_VSI_SEC_TX_PRUNE_ENA_M (0xF << ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S) > +#define ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA BIT(0) > + u8 sec_reserved; > + /* VLAN section */ > + __le16 pvid; /* VLANS include priority bits */ > + u8 pvlan_reserved[2]; > + u8 port_vlan_flags; > +#define ICE_AQ_VSI_PVLAN_MODE_S 0 > +#define ICE_AQ_VSI_PVLAN_MODE_M (0x3 << ICE_AQ_VSI_PVLAN_MODE_S) > +#define ICE_AQ_VSI_PVLAN_MODE_UNTAGGED 0x1 > +#define ICE_AQ_VSI_PVLAN_MODE_TAGGED 0x2 > +#define ICE_AQ_VSI_PVLAN_MODE_ALL 0x3 > +#define ICE_AQ_VSI_PVLAN_INSERT_PVID BIT(2) > +#define ICE_AQ_VSI_PVLAN_EMOD_S 3 > +#define ICE_AQ_VSI_PVLAN_EMOD_M (0x3 << ICE_AQ_VSI_PVLAN_EMOD_S) > +#define ICE_AQ_VSI_PVLAN_EMOD_STR_BOTH (0x0 << ICE_AQ_VSI_PVLAN_EMOD_S) > +#define ICE_AQ_VSI_PVLAN_EMOD_STR_UP (0x1 << ICE_AQ_VSI_PVLAN_EMOD_S) > +#define ICE_AQ_VSI_PVLAN_EMOD_STR (0x2 << ICE_AQ_VSI_PVLAN_EMOD_S) > +#define ICE_AQ_VSI_PVLAN_EMOD_NOTHING (0x3 << ICE_AQ_VSI_PVLAN_EMOD_S) > + u8 pvlan_reserved2[3]; > + /* ingress egress up sections */ > + __le32 ingress_table; /* bitmap, 3 bits per up */ > +#define ICE_AQ_VSI_UP_TABLE_UP0_S 0 > +#define ICE_AQ_VSI_UP_TABLE_UP0_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP0_S) > +#define ICE_AQ_VSI_UP_TABLE_UP1_S 3 > +#define ICE_AQ_VSI_UP_TABLE_UP1_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP1_S) > +#define ICE_AQ_VSI_UP_TABLE_UP2_S 6 > +#define ICE_AQ_VSI_UP_TABLE_UP2_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP2_S) > +#define ICE_AQ_VSI_UP_TABLE_UP3_S 9 > +#define ICE_AQ_VSI_UP_TABLE_UP3_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP3_S) > +#define ICE_AQ_VSI_UP_TABLE_UP4_S 12 > +#define ICE_AQ_VSI_UP_TABLE_UP4_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP4_S) > +#define ICE_AQ_VSI_UP_TABLE_UP5_S 15 > +#define ICE_AQ_VSI_UP_TABLE_UP5_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP5_S) > +#define ICE_AQ_VSI_UP_TABLE_UP6_S 18 > +#define ICE_AQ_VSI_UP_TABLE_UP6_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP6_S) > +#define ICE_AQ_VSI_UP_TABLE_UP7_S 21 > +#define ICE_AQ_VSI_UP_TABLE_UP7_M (0x7 << ICE_AQ_VSI_UP_TABLE_UP7_S) > + __le32 egress_table; /* same defines as for ingress table */ > + /* outer tags section */ > + __le16 outer_tag; > + u8 outer_tag_flags; > +#define ICE_AQ_VSI_OUTER_TAG_MODE_S 0 > +#define ICE_AQ_VSI_OUTER_TAG_MODE_M (0x3 << ICE_AQ_VSI_OUTER_TAG_MODE_S) > +#define ICE_AQ_VSI_OUTER_TAG_NOTHING 0x0 > +#define ICE_AQ_VSI_OUTER_TAG_REMOVE 0x1 > +#define ICE_AQ_VSI_OUTER_TAG_COPY 0x2 > +#define ICE_AQ_VSI_OUTER_TAG_TYPE_S 2 > +#define ICE_AQ_VSI_OUTER_TAG_TYPE_M (0x3 << ICE_AQ_VSI_OUTER_TAG_TYPE_S) > +#define ICE_AQ_VSI_OUTER_TAG_NONE 0x0 > +#define ICE_AQ_VSI_OUTER_TAG_STAG 0x1 > +#define ICE_AQ_VSI_OUTER_TAG_VLAN_8100 0x2 > +#define ICE_AQ_VSI_OUTER_TAG_VLAN_9100 0x3 > +#define ICE_AQ_VSI_OUTER_TAG_INSERT BIT(4) > +#define ICE_AQ_VSI_OUTER_TAG_ACCEPT_HOST BIT(6) > + u8 outer_tag_reserved; > + /* queue mapping section */ > + __le16 mapping_flags; > +#define ICE_AQ_VSI_Q_MAP_CONTIG 0x0 > +#define ICE_AQ_VSI_Q_MAP_NONCONTIG BIT(0) > + __le16 q_mapping[16]; > +#define ICE_AQ_VSI_Q_S 0 > +#define ICE_AQ_VSI_Q_M (0x7FF << ICE_AQ_VSI_Q_S) > + __le16 tc_mapping[8]; > +#define ICE_AQ_VSI_TC_Q_OFFSET_S 0 > +#define ICE_AQ_VSI_TC_Q_OFFSET_M (0x7FF << ICE_AQ_VSI_TC_Q_OFFSET_S) > +#define ICE_AQ_VSI_TC_Q_NUM_S 11 > +#define ICE_AQ_VSI_TC_Q_NUM_M (0xF << ICE_AQ_VSI_TC_Q_NUM_S) > + /* queueing option section */ > + u8 q_opt_rss; > +#define ICE_AQ_VSI_Q_OPT_RSS_LUT_S 0 > +#define ICE_AQ_VSI_Q_OPT_RSS_LUT_M (0x3 << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) > +#define ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI 0x0 > +#define ICE_AQ_VSI_Q_OPT_RSS_LUT_PF 0x2 > +#define ICE_AQ_VSI_Q_OPT_RSS_LUT_GBL 0x3 > +#define ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_S 2 > +#define ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M (0xF << ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_S) > +#define ICE_AQ_VSI_Q_OPT_RSS_HASH_S 6 > +#define ICE_AQ_VSI_Q_OPT_RSS_HASH_M (0x3 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) > +#define ICE_AQ_VSI_Q_OPT_RSS_TPLZ (0x0 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) > +#define ICE_AQ_VSI_Q_OPT_RSS_SYM_TPLZ (0x1 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) > +#define ICE_AQ_VSI_Q_OPT_RSS_XOR (0x2 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) > +#define ICE_AQ_VSI_Q_OPT_RSS_JHASH (0x3 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) > + u8 q_opt_tc; > +#define ICE_AQ_VSI_Q_OPT_TC_OVR_S 0 > +#define ICE_AQ_VSI_Q_OPT_TC_OVR_M (0x1F << ICE_AQ_VSI_Q_OPT_TC_OVR_S) > +#define ICE_AQ_VSI_Q_OPT_PROF_TC_OVR BIT(7) > + u8 q_opt_flags; > +#define ICE_AQ_VSI_Q_OPT_PE_FLTR_EN BIT(0) > + u8 q_opt_reserved[3]; > + /* outer up section */ > + __le32 outer_up_table; /* same structure and defines as ingress tbl */ > + /* section 10 */ > + __le16 sect_10_reserved; > + /* flow director section */ > + __le16 fd_options; > +#define ICE_AQ_VSI_FD_ENABLE BIT(0) > +#define ICE_AQ_VSI_FD_TX_AUTO_ENABLE BIT(1) > +#define ICE_AQ_VSI_FD_PROG_ENABLE BIT(3) > + __le16 max_fd_fltr_dedicated; > + __le16 max_fd_fltr_shared; > + __le16 fd_def_q; > +#define ICE_AQ_VSI_FD_DEF_Q_S 0 > +#define ICE_AQ_VSI_FD_DEF_Q_M (0x7FF << ICE_AQ_VSI_FD_DEF_Q_S) > +#define ICE_AQ_VSI_FD_DEF_GRP_S 12 > +#define ICE_AQ_VSI_FD_DEF_GRP_M (0x7 << ICE_AQ_VSI_FD_DEF_GRP_S) > + __le16 fd_report_opt; > +#define ICE_AQ_VSI_FD_REPORT_Q_S 0 > +#define ICE_AQ_VSI_FD_REPORT_Q_M (0x7FF << ICE_AQ_VSI_FD_REPORT_Q_S) > +#define ICE_AQ_VSI_FD_DEF_PRIORITY_S 12 > +#define ICE_AQ_VSI_FD_DEF_PRIORITY_M (0x7 << ICE_AQ_VSI_FD_DEF_PRIORITY_S) > +#define ICE_AQ_VSI_FD_DEF_DROP BIT(15) > + /* PASID section */ > + __le32 pasid_id; > +#define ICE_AQ_VSI_PASID_ID_S 0 > +#define ICE_AQ_VSI_PASID_ID_M (0xFFFFF << ICE_AQ_VSI_PASID_ID_S) > +#define ICE_AQ_VSI_PASID_ID_VALID BIT(31) > + u8 reserved[24]; > +}; > + > /* Get Default Topology (indirect 0x0400) */ > struct ice_aqc_get_topo { > u8 port_num; > @@ -590,6 +784,7 @@ struct ice_aq_desc { > 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; > + struct ice_aqc_add_get_update_free_vsi vsi_cmd; > struct ice_aqc_get_link_status get_link_status; > } params; > }; > @@ -640,6 +835,10 @@ enum ice_adminq_opc { > /* internal switch commands */ > ice_aqc_opc_get_sw_cfg = 0x0200, > > + /* VSI commands */ > + ice_aqc_opc_add_vsi = 0x0210, > + ice_aqc_opc_update_vsi = 0x0211, > + ice_aqc_opc_free_vsi = 0x0213, > ice_aqc_opc_clear_pf_cfg = 0x02A4, > > /* transmit scheduler commands */ > diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c > index b07ce86381bb..f9d0c99cae64 100644 > --- a/drivers/net/ethernet/intel/ice/ice_main.c > +++ b/drivers/net/ethernet/intel/ice/ice_main.c > @@ -42,6 +42,37 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)"); > > static struct workqueue_struct *ice_wq; > > +static int ice_vsi_release(struct ice_vsi *vsi); > + > +/** > + * ice_get_free_slot - get the next non-NULL location index in array > + * @array: array to search > + * @size: size of the array > + * @curr: last known occupied index to be used as a search hint > + * > + * void * is being used to keep the functionality generic. This lets us use this > + * function on any array of pointers. > + */ > +static int ice_get_free_slot(void *array, int size, int curr) > +{ > + int **tmp_array = (int **)array; > + int next; > + > + if (curr < (size - 1) && !tmp_array[curr + 1]) { > + next = curr + 1; > + } else { > + int i = 0; > + > + while ((i < size) && (tmp_array[i])) > + i++; > + if (i == size) > + next = 0xffff; Please use a named #define rather than a magic number > + else > + next = i; > + } > + return next; > +} > + > /** > * ice_search_res - Search the tracker for a block of resources > * @res: pointer to the resource > @@ -340,6 +371,270 @@ static void ice_set_ctrlq_len(struct ice_hw *hw) > hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN; > } > > +/** > + * ice_vsi_delete - delete a VSI from the switch > + * @vsi: pointer to VSI being removed > + */ > +static void ice_vsi_delete(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + struct ice_vsi_ctx ctxt; > + enum ice_status status; > + > + ctxt.vsi_num = vsi->vsi_num; > + > + memcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props)); > + > + status = ice_aq_free_vsi(&pf->hw, &ctxt, false, NULL); > + if (status) > + dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n", > + vsi->vsi_num); > +} > + > +/** > + * ice_vsi_setup_q_map - Setup a VSI queue map > + * @vsi: the VSI being configured > + * @ctxt: VSI context structure > + */ > +static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) > +{ > + u16 offset = 0, qmap = 0, pow = 0, qcount; > + u16 qcount_tx = vsi->alloc_txq; > + u16 qcount_rx = vsi->alloc_rxq; > + bool ena_tc0 = false; > + int i; > + > + /* at least TC0 should be enabled by default */ > + if (vsi->tc_cfg.numtc) { > + if (!(vsi->tc_cfg.ena_tc & BIT(0))) > + ena_tc0 = true; > + } else { > + ena_tc0 = true; > + } > + > + if (ena_tc0) { > + vsi->tc_cfg.numtc++; > + vsi->tc_cfg.ena_tc |= 1; > + } > + > + qcount = qcount_rx / vsi->tc_cfg.numtc; > + > + /* find higher power-of-2 of qcount */ > + pow = ilog2(qcount); > + > + if (!is_power_of_2(qcount)) > + pow++; > + > + /* TC mapping is a function of the number of Rx queues assigned to the > + * VSI for each traffic class and the offset of these queues. > + * The first 10 bits are for queue offset for TC0, next 4 bits for no:of > + * queues allocated to TC0. No:of queues is a power-of-2. > + * > + * If TC is not enabled, the queue offset is set to 0, and allocate one > + * queue, this way, traffic for the given TC will be sent to the default > + * queue. > + * > + * Setup number and offset of Rx queues for all TCs for the VSI > + */ > + for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) { > + if (!(vsi->tc_cfg.ena_tc & BIT(i))) { > + /* TC is not enabled */ > + vsi->tc_cfg.tc_info[i].qoffset = 0; > + vsi->tc_cfg.tc_info[i].qcount = 1; > + ctxt->info.tc_mapping[i] = 0; > + continue; > + } > + > + /* TC is enabled */ > + vsi->tc_cfg.tc_info[i].qoffset = offset; > + vsi->tc_cfg.tc_info[i].qcount = qcount; > + > + qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) & > + ICE_AQ_VSI_TC_Q_OFFSET_M) | > + ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & > + ICE_AQ_VSI_TC_Q_NUM_M); > + offset += qcount; > + ctxt->info.tc_mapping[i] = cpu_to_le16(qmap); > + } > + > + vsi->num_txq = qcount_tx; > + vsi->num_rxq = offset; > + > + /* Rx queue mapping */ > + ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG); > + /* q_mapping buffer holds the info for the first queue allocated for > + * this VSI in the PF space and also the number of queues associated > + * with this VSI. > + */ > + ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]); > + ctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq); > +} > + > +/** > + * ice_set_def_vsi_ctx - Set default VSI context before adding a VSI > + * @ctxt: the VSI context being set > + * > + * This initializes a default VSI context for all sections except the Queues. > + */ > +static void ice_set_def_vsi_ctx(struct ice_vsi_ctx *ctxt) > +{ > + u32 table = 0; > + > + memset(&ctxt->info, 0, sizeof(ctxt->info)); > + /* VSI's should be allocated from shared pool */ > + ctxt->alloc_from_pool = true; > + /* Src pruning enabled by default */ > + ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; > + /* Traffic from VSI can be sent to LAN */ > + ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; > + /* Allow all packets untagged/tagged */ > + ctxt->info.port_vlan_flags = ((ICE_AQ_VSI_PVLAN_MODE_ALL & > + ICE_AQ_VSI_PVLAN_MODE_M) >> > + ICE_AQ_VSI_PVLAN_MODE_S); > + /* Show VLAN/UP from packets in Rx descriptors */ > + ctxt->info.port_vlan_flags |= ((ICE_AQ_VSI_PVLAN_EMOD_STR_BOTH & > + ICE_AQ_VSI_PVLAN_EMOD_M) >> > + ICE_AQ_VSI_PVLAN_EMOD_S); > + /* Have 1:1 UP mapping for both ingress/egress tables */ > + table |= ICE_UP_TABLE_TRANSLATE(0, 0); > + table |= ICE_UP_TABLE_TRANSLATE(1, 1); > + table |= ICE_UP_TABLE_TRANSLATE(2, 2); > + table |= ICE_UP_TABLE_TRANSLATE(3, 3); > + table |= ICE_UP_TABLE_TRANSLATE(4, 4); > + table |= ICE_UP_TABLE_TRANSLATE(5, 5); > + table |= ICE_UP_TABLE_TRANSLATE(6, 6); > + table |= ICE_UP_TABLE_TRANSLATE(7, 7); > + ctxt->info.ingress_table = cpu_to_le32(table); > + ctxt->info.egress_table = cpu_to_le32(table); > + /* Have 1:1 UP mapping for outer to inner UP table */ > + ctxt->info.outer_up_table = cpu_to_le32(table); > + /* No Outer tag support outer_tag_flags remains to zero */ > +} > + > +/** > + * ice_vsi_add - Create a new VSI or fetch preallocated VSI > + * @vsi: the VSI being configured > + * > + * This initializes a VSI context depending on the VSI type to be added and > + * passes it down to the add_vsi aq command to create a new VSI. > + */ > +static int ice_vsi_add(struct ice_vsi *vsi) > +{ > + struct ice_vsi_ctx ctxt = { 0 }; > + struct ice_pf *pf = vsi->back; > + struct ice_hw *hw = &pf->hw; > + int ret = 0; > + > + switch (vsi->type) { > + case ICE_VSI_PF: > + ctxt.flags = ICE_AQ_VSI_TYPE_PF; > + break; > + default: > + return -ENODEV; > + } > + > + ice_set_def_vsi_ctx(&ctxt); > + /* if the switch is in VEB mode, allow VSI loopback */ > + if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB) > + ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; > + > + ctxt.info.sw_id = vsi->port_info->sw_id; > + ice_vsi_setup_q_map(vsi, &ctxt); > + > + ret = ice_aq_add_vsi(hw, &ctxt, NULL); > + if (ret) { > + dev_err(&vsi->back->pdev->dev, > + "Add VSI AQ call failed, err %d\n", ret); > + return -EIO; > + } > + vsi->info = ctxt.info; > + vsi->vsi_num = ctxt.vsi_num; > + > + return ret; > +} > + > +/** > + * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI > + * @vsi: the VSI having rings deallocated > + */ > +static void ice_vsi_clear_rings(struct ice_vsi *vsi) > +{ > + int i; > + > + if (vsi->tx_rings) { > + for (i = 0; i < vsi->alloc_txq; i++) { > + if (vsi->tx_rings[i]) { > + kfree_rcu(vsi->tx_rings[i], rcu); > + vsi->tx_rings[i] = NULL; > + } > + } > + } > + if (vsi->rx_rings) { > + for (i = 0; i < vsi->alloc_rxq; i++) { > + if (vsi->rx_rings[i]) { > + kfree_rcu(vsi->rx_rings[i], rcu); > + vsi->rx_rings[i] = NULL; > + } > + } > + } > +} > + > +/** > + * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI > + * @vsi: VSI which is having rings allocated > + */ > +static int ice_vsi_alloc_rings(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + int i; > + > + /* Allocate tx_rings */ > + for (i = 0; i < vsi->alloc_txq; i++) { > + struct ice_ring *ring; > + > + /* allocate with kzalloc(), free with kfree_rcu() */ > + ring = kzalloc(sizeof(*ring), GFP_KERNEL); > + > + if (!ring) > + goto err_out; > + > + ring->q_index = i; > + ring->reg_idx = vsi->txq_map[i]; > + ring->ring_active = false; > + ring->vsi = vsi; > + ring->netdev = vsi->netdev; > + ring->dev = &pf->pdev->dev; > + ring->count = vsi->num_desc; > + > + vsi->tx_rings[i] = ring; > + } > + > + /* Allocate rx_rings */ > + for (i = 0; i < vsi->alloc_rxq; i++) { > + struct ice_ring *ring; > + > + /* allocate with kzalloc(), free with kfree_rcu() */ > + ring = kzalloc(sizeof(*ring), GFP_KERNEL); > + if (!ring) > + goto err_out; > + > + ring->q_index = i; > + ring->reg_idx = vsi->rxq_map[i]; > + ring->ring_active = false; > + ring->vsi = vsi; > + ring->netdev = vsi->netdev; > + ring->dev = &pf->pdev->dev; > + ring->count = vsi->num_desc; > + vsi->rx_rings[i] = ring; > + } > + > + return 0; > + > +err_out: > + ice_vsi_clear_rings(vsi); > + return -ENOMEM; > +} > + > /** > * ice_ena_misc_vector - enable the non-queue interrupts > * @pf: board private structure > @@ -426,6 +721,188 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) > return ret; > } > > +/** > + * ice_vsi_map_rings_to_vectors - Map VSI rings to interrupt vectors > + * @vsi: the VSI being configured > + * > + * This function maps descriptor rings to the queue-specific vectors allotted > + * through the MSI-X enabling code. On a constrained vector budget, we map Tx > + * and Rx rings to the vector as "efficiently" as possible. > + */ > +static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) > +{ > + int q_vectors = vsi->num_q_vectors; > + int tx_rings_rem, rx_rings_rem; > + int v_id; > + > + /* initially assigning remaining rings count to VSIs num queue value */ > + tx_rings_rem = vsi->num_txq; > + rx_rings_rem = vsi->num_rxq; > + > + for (v_id = 0; v_id < q_vectors; v_id++) { > + struct ice_q_vector *q_vector = vsi->q_vectors[v_id]; > + int tx_rings_per_v, rx_rings_per_v, q_id, q_base; > + > + /* Tx rings mapping to vector */ > + tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id); > + q_vector->num_ring_tx = tx_rings_per_v; > + q_vector->tx.ring = NULL; > + q_base = vsi->num_txq - tx_rings_rem; > + > + for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) { > + struct ice_ring *tx_ring = vsi->tx_rings[q_id]; > + > + tx_ring->q_vector = q_vector; > + tx_ring->next = q_vector->tx.ring; > + q_vector->tx.ring = tx_ring; > + } > + tx_rings_rem -= tx_rings_per_v; > + > + /* Rx rings mapping to vector */ > + rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id); > + q_vector->num_ring_rx = rx_rings_per_v; > + q_vector->rx.ring = NULL; > + q_base = vsi->num_rxq - rx_rings_rem; > + > + for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) { > + struct ice_ring *rx_ring = vsi->rx_rings[q_id]; > + > + rx_ring->q_vector = q_vector; > + rx_ring->next = q_vector->rx.ring; > + q_vector->rx.ring = rx_ring; > + } > + rx_rings_rem -= rx_rings_per_v; > + } > +} > + > +/** > + * ice_vsi_set_num_qs - Set num queues, descriptors and vectors for a VSI > + * @vsi: the VSI being configured > + * > + * Return 0 on success and a negative value on error > + */ > +static void ice_vsi_set_num_qs(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + > + switch (vsi->type) { > + case ICE_VSI_PF: > + vsi->alloc_txq = pf->num_lan_tx; > + vsi->alloc_rxq = pf->num_lan_rx; > + vsi->num_desc = ALIGN(ICE_DFLT_NUM_DESC, ICE_REQ_DESC_MULTIPLE); > + vsi->num_q_vectors = max_t(int, pf->num_lan_rx, pf->num_lan_tx); > + break; > + default: > + dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", > + vsi->type); There should be a break or return here. > + } > +} > + > +/** > + * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the vsi > + * @vsi: VSI pointer > + * @alloc_qvectors: a bool to specify if q_vectors need to be allocated. > + * > + * On error: returns error code (negative) > + * On success: returns 0 > + */ > +static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors) > +{ > + struct ice_pf *pf = vsi->back; > + > + /* allocate memory for both Tx and Rx ring pointers */ > + vsi->tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq, > + sizeof(struct ice_ring *), GFP_KERNEL); > + if (!vsi->tx_rings) > + goto err_txrings; > + > + vsi->rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq, > + sizeof(struct ice_ring *), GFP_KERNEL); > + if (!vsi->rx_rings) > + goto err_rxrings; > + > + if (alloc_qvectors) { > + /* allocate memory for q_vector pointers */ > + vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, > + vsi->num_q_vectors, > + sizeof(struct ice_q_vector *), > + GFP_KERNEL); > + if (!vsi->q_vectors) > + goto err_vectors; > + } > + > + return 0; > + > +err_vectors: > + devm_kfree(&pf->pdev->dev, vsi->rx_rings); > +err_rxrings: > + devm_kfree(&pf->pdev->dev, vsi->tx_rings); > +err_txrings: > + return -ENOMEM; > +} > + > +/** > + * ice_vsi_alloc - Allocates the next available struct vsi in the PF > + * @pf: board private structure > + * @type: type of VSI > + * > + * returns a pointer to a VSI on success, NULL on failure. > + */ > +static struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type) > +{ > + struct ice_vsi *vsi = NULL; > + > + /* Need to protect the allocation of the VSIs at the PF level */ > + mutex_lock(&pf->sw_mutex); > + > + /* If we have already allocated our maximum number of VSIs, > + * pf->next_vsi will be 0xffff. If not, pf->next_vsi index > + * is available to be populated > + */ > + if (pf->next_vsi == 0xffff) { Magic number > + dev_dbg(&pf->pdev->dev, "out of VSI slots!\n"); > + goto unlock_pf; > + } > + > + vsi = devm_kzalloc(&pf->pdev->dev, sizeof(*vsi), GFP_KERNEL); > + if (!vsi) > + goto unlock_pf; > + > + vsi->type = type; > + vsi->back = pf; > + set_bit(__ICE_DOWN, vsi->state); > + vsi->idx = pf->next_vsi; > + vsi->work_lmt = ICE_DFLT_IRQ_WORK; > + > + ice_vsi_set_num_qs(vsi); > + > + switch (vsi->type) { > + case ICE_VSI_PF: > + if (ice_vsi_alloc_arrays(vsi, true)) > + goto err_rings; > + > + break; > + default: > + dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); > + goto unlock_pf; > + } > + > + /* fill VSI slot in the PF struct */ > + pf->vsi[pf->next_vsi] = vsi; > + > + /* prepare pf->next_vsi for next use */ > + pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi, > + pf->next_vsi); > + goto unlock_pf; > + > +err_rings: > + devm_kfree(&pf->pdev->dev, vsi); > + vsi = NULL; > +unlock_pf: > + mutex_unlock(&pf->sw_mutex); > + return vsi; > +} > + > /** > * ice_free_irq_msix_misc - Unroll misc vector setup > * @pf: board private structure > @@ -507,6 +984,579 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) > return 0; > } > > +/** > + * ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI > + * @vsi: the VSI getting queues > + * > + * Return 0 on success and a negative value on error > + */ > +static int ice_vsi_get_qs_contig(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + int offset, ret = 0; > + > + mutex_lock(&pf->avail_q_mutex); > + /* look for contiguous block of queues for tx */ > + offset = bitmap_find_next_zero_area(pf->avail_txqs, ICE_MAX_TXQS, > + 0, vsi->alloc_txq, 0); > + if (offset < ICE_MAX_TXQS) { > + int i; > + > + bitmap_set(pf->avail_txqs, offset, vsi->alloc_txq); > + for (i = 0; i < vsi->alloc_txq; i++) > + vsi->txq_map[i] = i + offset; > + } else { > + ret = -ENOMEM; > + vsi->tx_mapping_mode = ICE_VSI_MAP_SCATTER; > + } > + > + /* look for contiguous block of queues for rx */ > + offset = bitmap_find_next_zero_area(pf->avail_rxqs, ICE_MAX_RXQS, > + 0, vsi->alloc_rxq, 0); > + if (offset < ICE_MAX_RXQS) { > + int i; > + > + bitmap_set(pf->avail_rxqs, offset, vsi->alloc_rxq); > + for (i = 0; i < vsi->alloc_rxq; i++) > + vsi->rxq_map[i] = i + offset; > + } else { > + ret = -ENOMEM; > + vsi->rx_mapping_mode = ICE_VSI_MAP_SCATTER; > + } > + mutex_unlock(&pf->avail_q_mutex); > + > + return ret; > +} > + > +/** > + * ice_vsi_get_qs_scatter - Assign a scattered queues to VSI > + * @vsi: the VSI getting queues > + * > + * Return 0 on success and a negative value on error > + */ > +static int ice_vsi_get_qs_scatter(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + int i, index = 0; > + > + mutex_lock(&pf->avail_q_mutex); > + > + if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) { > + for (i = 0; i < vsi->alloc_txq; i++) { > + index = find_next_zero_bit(pf->avail_txqs, > + ICE_MAX_TXQS, index); > + if (index < ICE_MAX_TXQS) { > + set_bit(index, pf->avail_txqs); > + vsi->txq_map[i] = index; > + } else { > + goto err_scatter_tx; > + } > + } > + } > + > + if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) > + for (i = 0; i < vsi->alloc_rxq; i++) { > + index = find_next_zero_bit(pf->avail_rxqs, > + ICE_MAX_RXQS, index); > + if (index < ICE_MAX_RXQS) { > + set_bit(index, pf->avail_rxqs); > + vsi->rxq_map[i] = index; > + } else { > + goto err_scatter_rx; > + } > + } Put {}'s around this if block, like you did on the previous one. > + > + mutex_unlock(&pf->avail_q_mutex); > + return 0; > + > +err_scatter_rx: > + /* unflag any queues we have grabbed (i is failed position) */ > + for (index = 0; index < i; index++) { > + clear_bit(vsi->rxq_map[index], pf->avail_rxqs); > + vsi->rxq_map[index] = 0; > + } > + i = vsi->alloc_txq; > +err_scatter_tx: > + /* i is either position of failed attempt or vsi->alloc_txq */ > + for (index = 0; index < i; index++) { > + clear_bit(vsi->txq_map[index], pf->avail_txqs); > + vsi->txq_map[index] = 0; > + } > + > + mutex_unlock(&pf->avail_q_mutex); > + return -ENOMEM; > +} > + > +/** > + * ice_vsi_get_qs - Assign queues from PF to VSI > + * @vsi: the VSI to assign queues to > + * > + * Returns 0 on success and a negative value on error > + */ > +static int ice_vsi_get_qs(struct ice_vsi *vsi) > +{ > + int ret = 0; > + > + vsi->tx_mapping_mode = ICE_VSI_MAP_CONTIG; > + vsi->rx_mapping_mode = ICE_VSI_MAP_CONTIG; > + > + /* NOTE: ice_vsi_get_qs_contig() will set the rx/tx mapping > + * modes individually to scatter if assigning contiguous queues > + * to rx or tx fails > + */ > + ret = ice_vsi_get_qs_contig(vsi); > + if (ret < 0) { > + if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) > + vsi->alloc_txq = max_t(u16, vsi->alloc_txq, > + ICE_MAX_SCATTER_TXQS); > + if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) > + vsi->alloc_rxq = max_t(u16, vsi->alloc_rxq, > + ICE_MAX_SCATTER_RXQS); > + ret = ice_vsi_get_qs_scatter(vsi); > + } > + > + return ret; > +} > + > +/** > + * ice_vsi_put_qs - Release queues from VSI to PF > + * @vsi: the VSI thats going to release queues > + */ > +static void ice_vsi_put_qs(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + int i; > + > + mutex_lock(&pf->avail_q_mutex); > + > + for (i = 0; i < vsi->alloc_txq; i++) { > + clear_bit(vsi->txq_map[i], pf->avail_txqs); > + vsi->txq_map[i] = ICE_INVAL_Q_INDEX; > + } > + > + for (i = 0; i < vsi->alloc_rxq; i++) { > + clear_bit(vsi->rxq_map[i], pf->avail_rxqs); > + vsi->rxq_map[i] = ICE_INVAL_Q_INDEX; > + } > + > + mutex_unlock(&pf->avail_q_mutex); > +} > + > +/** > + * ice_free_q_vector - Free memory allocated for a specific interrupt vector > + * @vsi: VSI having the memory freed > + * @v_idx: index of the vector to be freed > + */ > +static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) > +{ > + struct ice_q_vector *q_vector; > + struct ice_ring *ring; > + > + if (!vsi->q_vectors[v_idx]) { > + dev_dbg(&vsi->back->pdev->dev, "Queue vector at index %d not found\n", > + v_idx); > + return; > + } > + q_vector = vsi->q_vectors[v_idx]; > + > + ice_for_each_ring(ring, q_vector->tx) > + ring->q_vector = NULL; > + ice_for_each_ring(ring, q_vector->rx) > + ring->q_vector = NULL; > + > + /* only VSI with an associated netdev is set up with NAPI */ > + if (vsi->netdev) > + netif_napi_del(&q_vector->napi); > + > + devm_kfree(&vsi->back->pdev->dev, q_vector); > + vsi->q_vectors[v_idx] = NULL; > +} > + > +/** > + * ice_vsi_free_q_vectors - Free memory allocated for interrupt vectors > + * @vsi: the VSI having memory freed > + */ > +static void ice_vsi_free_q_vectors(struct ice_vsi *vsi) > +{ > + int v_idx; > + > + for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++) > + ice_free_q_vector(vsi, v_idx); > +} > + > +/** > + * ice_cfg_netdev - Setup the netdev flags > + * @vsi: the VSI being configured > + * > + * Returns 0 on success, negative value on failure > + */ > +static int ice_cfg_netdev(struct ice_vsi *vsi) > +{ > + struct ice_netdev_priv *np; > + struct net_device *netdev; > + u8 mac_addr[ETH_ALEN]; > + > + netdev = alloc_etherdev_mqs(sizeof(struct ice_netdev_priv), > + vsi->alloc_txq, vsi->alloc_rxq); > + if (!netdev) > + return -ENOMEM; > + > + vsi->netdev = netdev; > + np = netdev_priv(netdev); > + np->vsi = vsi; > + > + /* set features that user can change */ > + netdev->hw_features = NETIF_F_SG | > + NETIF_F_HIGHDMA | > + NETIF_F_RXHASH; > + > + /* enable features */ > + netdev->features |= netdev->hw_features; > + > + if (vsi->type == ICE_VSI_PF) { > + SET_NETDEV_DEV(netdev, &vsi->back->pdev->dev); > + ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr); > + > + ether_addr_copy(netdev->dev_addr, mac_addr); > + ether_addr_copy(netdev->perm_addr, mac_addr); > + } > + > + netdev->priv_flags |= IFF_UNICAST_FLT; > + > + /* setup watchdog timeout value to be 5 second */ > + netdev->watchdog_timeo = 5 * HZ; > + > + netdev->min_mtu = ETH_MIN_MTU; > + netdev->max_mtu = ICE_MAX_MTU; > + > + return 0; > +} > + > +/** > + * ice_vsi_free_arrays - clean up vsi resources > + * @vsi: pointer to VSI being cleared > + * @free_qvectors: bool to specify if q_vectors should be deallocated > + */ > +static void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors) > +{ > + struct ice_pf *pf = vsi->back; > + > + /* free the ring and vector containers */ > + if (free_qvectors && vsi->q_vectors) { > + devm_kfree(&pf->pdev->dev, vsi->q_vectors); > + vsi->q_vectors = NULL; > + } > + if (vsi->tx_rings) { > + devm_kfree(&pf->pdev->dev, vsi->tx_rings); > + vsi->tx_rings = NULL; > + } > + if (vsi->rx_rings) { > + devm_kfree(&pf->pdev->dev, vsi->rx_rings); > + vsi->rx_rings = NULL; > + } > +} > + > +/** > + * ice_vsi_clear - clean up and deallocate the provided vsi > + * @vsi: pointer to VSI being cleared > + * > + * This deallocates the vsi's queue resources, removes it from the PF's > + * VSI array if necessary, and deallocates the VSI > + * > + * Returns 0 on success, negative on failure > + */ > +static int ice_vsi_clear(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = NULL; > + > + if (!vsi) > + return 0; > + > + if (!vsi->back) > + return -EINVAL; > + > + pf = vsi->back; > + > + if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) { > + dev_dbg(&pf->pdev->dev, "vsi does not exist at pf->vsi[%d]\n", > + vsi->idx); > + return -EINVAL; > + } > + > + mutex_lock(&pf->sw_mutex); > + /* updates the PF for this cleared vsi */ > + > + pf->vsi[vsi->idx] = NULL; > + if (vsi->idx < pf->next_vsi) > + pf->next_vsi = vsi->idx; > + > + ice_vsi_free_arrays(vsi, true); > + mutex_unlock(&pf->sw_mutex); > + devm_kfree(&pf->pdev->dev, vsi); > + > + return 0; > +} > + > +/** > + * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector > + * @vsi: the VSI being configured > + * @v_idx: index of the vector in the vsi struct > + * > + * We allocate one q_vector. If allocation fails we return -ENOMEM. > + */ > +static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) > +{ > + struct ice_pf *pf = vsi->back; > + struct ice_q_vector *q_vector; > + > + /* allocate q_vector */ > + q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL); > + if (!q_vector) > + return -ENOMEM; > + > + q_vector->vsi = vsi; > + q_vector->v_idx = v_idx; > + /* only set affinity_mask if the CPU is online */ > + if (cpu_online(v_idx)) > + cpumask_set_cpu(v_idx, &q_vector->affinity_mask); > + > + /* tie q_vector and vsi together */ > + vsi->q_vectors[v_idx] = q_vector; > + > + return 0; > +} > + > +/** > + * ice_vsi_alloc_q_vectors - Allocate memory for interrupt vectors > + * @vsi: the VSI being configured > + * > + * We allocate one q_vector per queue interrupt. If allocation fails we > + * return -ENOMEM. > + */ > +static int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + int v_idx = 0, num_q_vectors; > + int err; > + > + if (vsi->q_vectors[0]) { > + dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n", > + vsi->vsi_num); > + return -EEXIST; > + } > + > + if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { > + num_q_vectors = vsi->num_q_vectors; > + } else { > + err = -EINVAL; > + goto err_out; > + } > + > + for (v_idx = 0; v_idx < num_q_vectors; v_idx++) { > + err = ice_vsi_alloc_q_vector(vsi, v_idx); > + if (err) > + goto err_out; > + } > + > + return 0; > + > +err_out: > + while (v_idx--) > + ice_free_q_vector(vsi, v_idx); > + > + dev_err(&pf->pdev->dev, > + "Failed to allocate %d q_vector for VSI %d, ret=%d\n", > + vsi->num_q_vectors, vsi->vsi_num, err); > + vsi->num_q_vectors = 0; > + return err; > +} > + > +/** > + * ice_vsi_setup_vector_base - Set up the base vector for the given VSI > + * @vsi: ptr to the VSI > + * > + * This should only be called after ice_vsi_alloc() which allocates the > + * corresponding SW VSI structure and initializes num_queue_pairs for the > + * newly allocated VSI. > + * > + * Returns 0 on success or negative on failure > + */ > +static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) > +{ > + struct ice_pf *pf = vsi->back; > + int num_q_vectors = 0; > + > + if (vsi->base_vector) { > + dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", > + vsi->vsi_num, vsi->base_vector); > + return -EEXIST; > + } > + > + if (!test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) > + return -ENOENT; > + > + switch (vsi->type) { > + case ICE_VSI_PF: > + num_q_vectors = vsi->num_q_vectors; > + break; > + default: > + dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", > + vsi->type); There should be a break here sln