diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 9cce4cb91401..0b269c470343 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -172,7 +172,8 @@ struct ice_vsi { u32 rx_buf_failed; u32 rx_page_failed; int num_q_vectors; - int base_vector; + int sw_base_vector; /* Irq base for OS reserved vectors */ + int hw_base_vector; /* HW (absolute) index of a vector */ enum ice_vsi_type type; u16 vsi_num; /* HW (absolute) index of this VSI */ u16 idx; /* software index in pf->vsi[] */ @@ -229,6 +230,10 @@ struct ice_q_vector { u8 num_ring_tx; /* total number of tx rings in vector */ u8 num_ring_rx; /* total number of rx rings in vector */ char name[ICE_INT_NAME_STR_LEN]; + /* in usecs, need to use ice_intrl_to_usecs_reg() before writing this + * value to the device + */ + u8 intrl; } ____cacheline_internodealigned_in_smp; enum ice_pf_flags { @@ -240,8 +245,14 @@ enum ice_pf_flags { struct ice_pf { struct pci_dev *pdev; + + /* OS reserved IRQ details */ struct msix_entry *msix_entries; - struct ice_res_tracker *irq_tracker; + struct ice_res_tracker *sw_irq_tracker; + + /* HW reserved Interrupts for this PF */ + struct ice_res_tracker *hw_irq_tracker; + struct ice_vsi **vsi; /* VSIs created by the driver */ struct ice_sw *first_sw; /* first switch created by firmware */ DECLARE_BITMAP(state, __ICE_STATE_NBITS); @@ -256,9 +267,11 @@ struct ice_pf { struct mutex sw_mutex; /* lock for protecting VSI alloc flow */ u32 msg_enable; u32 hw_csum_rx_error; - u32 oicr_idx; /* Other interrupt cause vector index */ + u32 sw_oicr_idx; /* Other interrupt cause SW vector index */ + u32 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */ + u32 hw_oicr_idx; /* Other interrupt cause vector HW index */ + u32 num_avail_hw_msix; /* remaining HW MSIX vectors left unclaimed */ u32 num_lan_msix; /* Total MSIX vectors for base driver */ - u32 num_avail_msix; /* remaining MSIX vectors left unclaimed */ u16 num_lan_tx; /* num lan tx queues setup */ u16 num_lan_rx; /* num lan rx queues setup */ u16 q_left_tx; /* remaining num tx queues left unclaimed */ @@ -293,8 +306,8 @@ struct ice_netdev_priv { static inline void ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi, struct ice_q_vector *q_vector) { - u32 vector = (vsi && q_vector) ? vsi->base_vector + q_vector->v_idx : - ((struct ice_pf *)hw->back)->oicr_idx; + u32 vector = (vsi && q_vector) ? vsi->hw_base_vector + q_vector->v_idx : + ((struct ice_pf *)hw->back)->hw_oicr_idx; int itr = ICE_ITR_NONE; u32 val; diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index ef9229fa5510..68fbbb92d504 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -422,7 +422,7 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw) devm_kfree(ice_hw_to_dev(hw), lst_itr); } } - + ice_rm_all_sw_replay_rule_info(hw); devm_kfree(ice_hw_to_dev(hw), sw->recp_list); devm_kfree(ice_hw_to_dev(hw), sw); } @@ -597,6 +597,39 @@ void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf) ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg End ]\n"); } +/** + * ice_get_itr_intrl_gran - determine int/intrl granularity + * @hw: pointer to the hw struct + * + * Determines the itr/intrl granularities based on the maximum aggregate + * bandwidth according to the device's configuration during power-on. + */ +static enum ice_status ice_get_itr_intrl_gran(struct ice_hw *hw) +{ + u8 max_agg_bw = (rd32(hw, GL_PWR_MODE_CTL) & + GL_PWR_MODE_CTL_CAR_MAX_BW_M) >> + GL_PWR_MODE_CTL_CAR_MAX_BW_S; + + switch (max_agg_bw) { + case ICE_MAX_AGG_BW_200G: + case ICE_MAX_AGG_BW_100G: + case ICE_MAX_AGG_BW_50G: + hw->itr_gran = ICE_ITR_GRAN_ABOVE_25; + hw->intrl_gran = ICE_INTRL_GRAN_ABOVE_25; + break; + case ICE_MAX_AGG_BW_25G: + hw->itr_gran = ICE_ITR_GRAN_MAX_25; + hw->intrl_gran = ICE_INTRL_GRAN_MAX_25; + break; + default: + ice_debug(hw, ICE_DBG_INIT, + "Failed to determine itr/intrl granularity\n"); + return ICE_ERR_CFG; + } + + return 0; +} + /** * ice_init_hw - main hardware initialization routine * @hw: pointer to the hardware structure @@ -621,11 +654,9 @@ enum ice_status ice_init_hw(struct ice_hw *hw) if (status) return status; - /* set these values to minimum allowed */ - hw->itr_gran_200 = ICE_ITR_GRAN_MIN_200; - hw->itr_gran_100 = ICE_ITR_GRAN_MIN_100; - hw->itr_gran_50 = ICE_ITR_GRAN_MIN_50; - hw->itr_gran_25 = ICE_ITR_GRAN_MIN_25; + status = ice_get_itr_intrl_gran(hw); + if (status) + return status; status = ice_init_all_ctrlq(hw); if (status) @@ -1740,8 +1771,7 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, * ice_update_link_info - update status of the HW network link * @pi: port info structure of the interested logical port */ -static enum ice_status -ice_update_link_info(struct ice_port_info *pi) +enum ice_status ice_update_link_info(struct ice_port_info *pi) { struct ice_aqc_get_phy_caps_data *pcaps; struct ice_phy_info *phy_info; @@ -2055,7 +2085,7 @@ __ice_aq_get_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, /** * ice_aq_get_rss_lut * @hw: pointer to the hardware structure - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @lut_type: LUT table type * @lut: pointer to the LUT buffer provided by the caller * @lut_size: size of the LUT buffer @@ -2063,17 +2093,20 @@ __ice_aq_get_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, * get the RSS lookup table, PF or VSI type */ enum ice_status -ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, - u16 lut_size) +ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, + u8 *lut, u16 lut_size) { - return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0, - false); + if (!ice_is_vsi_valid(hw, vsi_handle) || !lut) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_lut(hw, ice_get_hw_vsi_num(hw, vsi_handle), + lut_type, lut, lut_size, 0, false); } /** * ice_aq_set_rss_lut * @hw: pointer to the hardware structure - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @lut_type: LUT table type * @lut: pointer to the LUT buffer provided by the caller * @lut_size: size of the LUT buffer @@ -2081,11 +2114,14 @@ ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, * set the RSS lookup table, PF or VSI type */ enum ice_status -ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, - u16 lut_size) +ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, + u8 *lut, u16 lut_size) { - return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0, - true); + if (!ice_is_vsi_valid(hw, vsi_handle) || !lut) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_lut(hw, ice_get_hw_vsi_num(hw, vsi_handle), + lut_type, lut, lut_size, 0, true); } /** @@ -2126,31 +2162,39 @@ ice_status __ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id, /** * ice_aq_get_rss_key * @hw: pointer to the hw struct - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @key: pointer to key info struct * * get the RSS key per VSI */ enum ice_status -ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *key) { - return __ice_aq_get_set_rss_key(hw, vsi_id, key, false); + if (!ice_is_vsi_valid(hw, vsi_handle) || !key) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_key(hw, ice_get_hw_vsi_num(hw, vsi_handle), + key, false); } /** * ice_aq_set_rss_key * @hw: pointer to the hw struct - * @vsi_id: VSI FW index + * @vsi_handle: software VSI handle * @keys: pointer to key info struct * * set the RSS key per VSI */ enum ice_status -ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *keys) { - return __ice_aq_get_set_rss_key(hw, vsi_id, keys, true); + if (!ice_is_vsi_valid(hw, vsi_handle) || !keys) + return ICE_ERR_PARAM; + + return __ice_aq_get_set_rss_key(hw, ice_get_hw_vsi_num(hw, vsi_handle), + keys, true); } /** @@ -2489,7 +2533,7 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) /** * ice_ena_vsi_txq * @pi: port information structure - * @vsi_id: VSI id + * @vsi_handle: software VSI handle * @tc: tc number * @num_qgrps: Number of added queue groups * @buf: list of queue groups to be added @@ -2499,7 +2543,7 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) * This function adds one lan q */ enum ice_status -ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, +ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size, struct ice_sq_cd *cd) { @@ -2516,15 +2560,19 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, hw = pi->hw; + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + mutex_lock(&pi->sched_lock); /* find a parent node */ - parent = ice_sched_get_free_qparent(pi, vsi_id, tc, + parent = ice_sched_get_free_qparent(pi, vsi_handle, tc, ICE_SCHED_NODE_OWNER_LAN); if (!parent) { status = ICE_ERR_PARAM; goto ena_txq_exit; } + buf->parent_teid = parent->info.node_teid; node.parent_teid = parent->info.node_teid; /* Mark that the values in the "generic" section as valid. The default @@ -2602,7 +2650,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, /** * ice_cfg_vsi_qs - configure the new/exisiting VSI queues * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc_bitmap: TC bitmap * @maxqs: max queues array per TC * @owner: lan or rdma @@ -2610,7 +2658,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, * This function adds/updates the VSI queues per TC. */ static enum ice_status -ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, +ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, u16 *maxqs, u8 owner) { enum ice_status status = 0; @@ -2619,6 +2667,9 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY) return ICE_ERR_CFG; + if (!ice_is_vsi_valid(pi->hw, vsi_handle)) + return ICE_ERR_PARAM; + mutex_lock(&pi->sched_lock); for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) { @@ -2626,7 +2677,7 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, if (!ice_sched_get_tc_node(pi, i)) continue; - status = ice_sched_cfg_vsi(pi, vsi_id, i, maxqs[i], owner, + status = ice_sched_cfg_vsi(pi, vsi_handle, i, maxqs[i], owner, ice_is_tc_ena(tc_bitmap, i)); if (status) break; @@ -2639,20 +2690,83 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, /** * ice_cfg_vsi_lan - configure VSI lan queues * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc_bitmap: TC bitmap * @max_lanqs: max lan queues array per TC * * This function adds/updates the VSI lan queues per TC. */ enum ice_status -ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, +ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, u16 *max_lanqs) { - return ice_cfg_vsi_qs(pi, vsi_id, tc_bitmap, max_lanqs, + return ice_cfg_vsi_qs(pi, vsi_handle, tc_bitmap, max_lanqs, ICE_SCHED_NODE_OWNER_LAN); } +/** + * ice_replay_pre_init - replay pre initialization + * @hw: pointer to the hw struct + * + * Initializes required config data for VSI, FD, ACL, and RSS before replay. + */ +static enum ice_status ice_replay_pre_init(struct ice_hw *hw) +{ + struct ice_switch_info *sw = hw->switch_info; + u8 i; + + /* Delete old entries from replay filter list head if there is any */ + ice_rm_all_sw_replay_rule_info(hw); + /* In start of replay, move entries into replay_rules list, it + * will allow adding rules entries back to filt_rules list, + * which is operational list. + */ + for (i = 0; i < ICE_SW_LKUP_LAST; i++) + list_replace_init(&sw->recp_list[i].filt_rules, + &sw->recp_list[i].filt_replay_rules); + + return 0; +} + +/** + * ice_replay_vsi - replay VSI configuration + * @hw: pointer to the hw struct + * @vsi_handle: driver VSI handle + * + * Restore all VSI configuration after reset. It is required to call this + * function with main VSI first. + */ +enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle) +{ + enum ice_status status; + + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + + /* Replay pre-initialization if there is any */ + if (vsi_handle == ICE_MAIN_VSI_HANDLE) { + status = ice_replay_pre_init(hw); + if (status) + return status; + } + + /* Replay per VSI all filters */ + status = ice_replay_vsi_all_fltr(hw, vsi_handle); + return status; +} + +/** + * ice_replay_post - post replay configuration cleanup + * @hw: pointer to the hw struct + * + * Post replay cleanup. + */ +void ice_replay_post(struct ice_hw *hw) +{ + /* Delete old entries from replay filter list head */ + ice_rm_all_sw_replay_rule_info(hw); +} + /** * ice_stat_update40 - read 40 bit stat from the chip and update stat values * @hw: ptr to the hardware info diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 80d288a07731..7b2a5bb2e550 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -21,6 +21,7 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, struct ice_rq_event_info *e, u16 *pending); enum ice_status ice_get_link_status(struct ice_port_info *pi, bool *link_up); +enum ice_status ice_update_link_info(struct ice_port_info *pi); enum ice_status ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res, enum ice_aq_res_access_type access, u32 timeout); @@ -37,17 +38,18 @@ ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx, u32 rxq_index); enum ice_status -ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, +ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, u8 *lut, u16 lut_size); enum ice_status -ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, +ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, u8 *lut, u16 lut_size); enum ice_status -ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *keys); enum ice_status -ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id, +ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle, struct ice_aqc_get_set_rss_keys *keys); + bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq); enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading); void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode); @@ -89,12 +91,14 @@ enum ice_status ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids, u32 *q_teids, struct ice_sq_cd *cmd_details); enum ice_status -ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap, +ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap, u16 *max_lanqs); enum ice_status -ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps, +ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size, struct ice_sq_cd *cd); +enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle); +void ice_replay_post(struct ice_hw *hw); void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf); void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg, bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat); diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 88f11498804b..9a78d83eaa3e 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -88,6 +88,8 @@ #define GLINT_DYN_CTL_SW_ITR_INDX_M ICE_M(0x3, 25) #define GLINT_DYN_CTL_INTENA_MSK_M BIT(31) #define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4)) +#define GLINT_RATE(_INT) (0x0015A000 + ((_INT) * 4)) +#define GLINT_RATE_INTRL_ENA_M BIT(6) #define PFINT_FW_CTL 0x0016C800 #define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, 0) #define PFINT_FW_CTL_ITR_INDX_S 11 @@ -173,6 +175,9 @@ #define PF_FUNC_RID 0x0009E880 #define PF_FUNC_RID_FUNC_NUM_S 0 #define PF_FUNC_RID_FUNC_NUM_M ICE_M(0x7, 0) +#define GL_PWR_MODE_CTL 0x000B820C +#define GL_PWR_MODE_CTL_CAR_MAX_BW_S 30 +#define GL_PWR_MODE_CTL_CAR_MAX_BW_M ICE_M(0x3, 30) #define GLPRT_BPRCH(_i) (0x00381384 + ((_i) * 8)) #define GLPRT_BPRCL(_i) (0x00381380 + ((_i) * 8)) #define GLPRT_BPTCH(_i) (0x00381244 + ((_i) * 8)) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 95588fe0e22f..acf3478a3f3b 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -137,7 +137,7 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) } /* make sure the context is associated with the right VSI */ - tlan_ctx->src_vsi = vsi->vsi_num; + tlan_ctx->src_vsi = ice_get_hw_vsi_num(hw, vsi->idx); tlan_ctx->tso_ena = ICE_TX_LEGACY; tlan_ctx->tso_qnum = pf_q; @@ -1039,9 +1039,9 @@ 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); + if (vsi->sw_base_vector || vsi->hw_base_vector) { + dev_dbg(&pf->pdev->dev, "VSI %d has non-zero HW base vector %d or SW base vector %d\n", + vsi->vsi_num, vsi->hw_base_vector, vsi->sw_base_vector); return -EEXIST; } @@ -1051,6 +1051,21 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) switch (vsi->type) { case ICE_VSI_PF: num_q_vectors = vsi->num_q_vectors; + /* reserve slots from OS requested IRQs */ + vsi->sw_base_vector = ice_get_res(pf, pf->sw_irq_tracker, + num_q_vectors, vsi->idx); + if (vsi->sw_base_vector < 0) { + dev_err(&pf->pdev->dev, + "Failed to get tracking for %d SW vectors for VSI %d, err=%d\n", + num_q_vectors, vsi->vsi_num, + vsi->sw_base_vector); + return -ENOENT; + } + pf->num_avail_sw_msix -= num_q_vectors; + + /* reserve slots from HW interrupts */ + vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker, + num_q_vectors, vsi->idx); break; default: dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", @@ -1058,17 +1073,18 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) break; } - if (num_q_vectors) - vsi->base_vector = ice_get_res(pf, pf->irq_tracker, - num_q_vectors, vsi->idx); - - if (vsi->base_vector < 0) { + if (vsi->hw_base_vector < 0) { dev_err(&pf->pdev->dev, - "Failed to get tracking for %d vectors for VSI %d, err=%d\n", - num_q_vectors, vsi->vsi_num, vsi->base_vector); + "Failed to get tracking for %d HW vectors for VSI %d, err=%d\n", + num_q_vectors, vsi->vsi_num, vsi->hw_base_vector); + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, + vsi->idx); + pf->num_avail_sw_msix += num_q_vectors; return -ENOENT; } + pf->num_avail_hw_msix -= num_q_vectors; + return 0; } @@ -1123,6 +1139,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->vsi = vsi; ring->dev = &pf->pdev->dev; ring->count = vsi->num_desc; + ring->itr_setting = ICE_DFLT_TX_ITR; vsi->tx_rings[i] = ring; } @@ -1142,6 +1159,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->netdev = vsi->netdev; ring->dev = &pf->pdev->dev; ring->count = vsi->num_desc; + ring->itr_setting = ICE_DFLT_RX_ITR; vsi->rx_rings[i] = ring; } @@ -1206,6 +1224,38 @@ static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) } } +/** + * ice_vsi_manage_rss_lut - disable/enable RSS + * @vsi: the VSI being changed + * @ena: boolean value indicating if this is an enable or disable request + * + * In the event of disable request for RSS, this function will zero out RSS + * LUT, while in the event of enable request for RSS, it will reconfigure RSS + * LUT. + */ +int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena) +{ + int err = 0; + u8 *lut; + + lut = devm_kzalloc(&vsi->back->pdev->dev, vsi->rss_table_size, + GFP_KERNEL); + if (!lut) + return -ENOMEM; + + if (ena) { + if (vsi->rss_lut_user) + memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size); + else + ice_fill_rss_lut(lut, vsi->rss_table_size, + vsi->rss_size); + } + + err = ice_set_rss(vsi, NULL, lut, vsi->rss_table_size); + devm_kfree(&vsi->back->pdev->dev, lut); + return err; +} + /** * ice_vsi_cfg_rss_lut_key - Configure RSS params for a VSI * @vsi: VSI to be configured @@ -1230,8 +1280,8 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) else ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); - status = ice_aq_set_rss_lut(&pf->hw, vsi->vsi_num, vsi->rss_lut_type, - lut, vsi->rss_table_size); + status = ice_aq_set_rss_lut(&pf->hw, vsi->idx, vsi->rss_lut_type, lut, + vsi->rss_table_size); if (status) { dev_err(&vsi->back->pdev->dev, @@ -1255,7 +1305,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) memcpy(&key->standard_rss_key, seed, ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE); - status = ice_aq_set_rss_key(&pf->hw, vsi->vsi_num, key); + status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key); if (status) { dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n", @@ -1290,10 +1340,10 @@ int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, return -ENOMEM; tmp->fltr_info.flag = ICE_FLTR_TX; - tmp->fltr_info.src = vsi->vsi_num; + tmp->fltr_info.src_id = ICE_SRC_ID_VSI; tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC; tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; - tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + tmp->fltr_info.vsi_handle = vsi->idx; ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr); INIT_LIST_HEAD(&tmp->list_entry); @@ -1394,8 +1444,8 @@ int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; tmp->fltr_info.flag = ICE_FLTR_TX; - tmp->fltr_info.src = vsi->vsi_num; - tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + tmp->fltr_info.src_id = ICE_SRC_ID_VSI; + tmp->fltr_info.vsi_handle = vsi->idx; tmp->fltr_info.l_data.vlan.vlan_id = vid; INIT_LIST_HEAD(&tmp->list_entry); @@ -1431,11 +1481,11 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) return -ENOMEM; list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; - list->fltr_info.fwd_id.vsi_id = vsi->vsi_num; + list->fltr_info.vsi_handle = vsi->idx; list->fltr_info.fltr_act = ICE_FWD_TO_VSI; list->fltr_info.l_data.vlan.vlan_id = vid; list->fltr_info.flag = ICE_FLTR_TX; - list->fltr_info.src = vsi->vsi_num; + list->fltr_info.src_id = ICE_SRC_ID_VSI; INIT_LIST_HEAD(&list->list_entry); list_add(&list->list_entry, &tmp_add_list); @@ -1524,7 +1574,7 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) * comm scheduler queue doorbell. */ vsi->tx_rings[i]->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); - status = ice_ena_vsi_txq(vsi->port_info, vsi->vsi_num, tc, + status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, num_q_grps, qg_buf, buf_len, NULL); if (status) { dev_err(&vsi->back->pdev->dev, @@ -1547,6 +1597,23 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) return err; } +/** + * ice_intrl_usec_to_reg - convert interrupt rate limit to register value + * @intrl: interrupt rate limit in usecs + * @gran: interrupt rate limit granularity in usecs + * + * This function converts a decimal interrupt rate limit in usecs to the format + * expected by firmware. + */ +static u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran) +{ + u32 val = intrl / gran; + + if (val) + return val | GLINT_RATE_INTRL_ENA_M; + return 0; +} + /** * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW * @vsi: the VSI being configured @@ -1554,7 +1621,7 @@ int ice_vsi_cfg_txqs(struct ice_vsi *vsi) void ice_vsi_cfg_msix(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - u16 vector = vsi->base_vector; + u16 vector = vsi->hw_base_vector; struct ice_hw *hw = &pf->hw; u32 txq = 0, rxq = 0; int i, q, itr; @@ -1563,23 +1630,27 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) for (i = 0; i < vsi->num_q_vectors; i++, vector++) { struct ice_q_vector *q_vector = vsi->q_vectors[i]; - itr_gran = hw->itr_gran_200; + itr_gran = hw->itr_gran; + + q_vector->intrl = ICE_DFLT_INTRL; if (q_vector->num_ring_rx) { q_vector->rx.itr = - ITR_TO_REG(vsi->rx_rings[rxq]->rx_itr_setting, + ITR_TO_REG(vsi->rx_rings[rxq]->itr_setting, itr_gran); q_vector->rx.latency_range = ICE_LOW_LATENCY; } if (q_vector->num_ring_tx) { q_vector->tx.itr = - ITR_TO_REG(vsi->tx_rings[txq]->tx_itr_setting, + ITR_TO_REG(vsi->tx_rings[txq]->itr_setting, itr_gran); q_vector->tx.latency_range = ICE_LOW_LATENCY; } wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), q_vector->rx.itr); wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), q_vector->tx.itr); + wr32(hw, GLINT_RATE(vector), + ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); /* Both Transmit Queue Interrupt Cause Control register * and Receive Queue Interrupt Cause control register @@ -1636,9 +1707,8 @@ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); - ctxt.vsi_num = vsi->vsi_num; - status = ice_aq_update_vsi(hw, &ctxt, NULL); + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); if (status) { dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", status, hw->adminq.sq_last_status); @@ -1677,9 +1747,8 @@ int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); - ctxt.vsi_num = vsi->vsi_num; - status = ice_aq_update_vsi(hw, &ctxt, NULL); + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); if (status) { dev_err(dev, "update VSI for VLAN strip failed, ena = %d err %d aq_err %d\n", ena, status, hw->adminq.sq_last_status); @@ -1764,7 +1833,7 @@ int ice_vsi_stop_tx_rings(struct ice_vsi *vsi) * the queue to schedule NAPI handler */ v_idx = vsi->tx_rings[i]->q_vector->v_idx; - wr32(hw, GLINT_DYN_CTL(vsi->base_vector + v_idx), + wr32(hw, GLINT_DYN_CTL(vsi->hw_base_vector + v_idx), GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); } status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids, @@ -1829,11 +1898,11 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | ICE_AQ_VSI_PROP_SW_VALID); - ctxt->vsi_num = vsi->vsi_num; - status = ice_aq_update_vsi(&vsi->back->hw, ctxt, NULL); + + status = ice_update_vsi(&vsi->back->hw, vsi->idx, ctxt, NULL); if (status) { - netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI %d failed, err = %d, aq_err = %d\n", - ena ? "Ena" : "Dis", vsi->vsi_num, status, + netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %d\n", + ena ? "Ena" : "Dis", vsi->idx, vsi->vsi_num, status, vsi->back->hw.adminq.sq_last_status); goto err_out; } @@ -1931,8 +2000,8 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, for (i = 0; i < vsi->tc_cfg.numtc; i++) max_txqs[i] = vsi->num_txq; - ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, - vsi->tc_cfg.ena_tc, max_txqs); + ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, + max_txqs); if (ret) { dev_info(&pf->pdev->dev, "Failed VSI lan queue config\n"); goto unroll_vector_base; @@ -1941,7 +2010,12 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, return vsi; unroll_vector_base: - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); + /* reclaim SW interrupts back to the common pool */ + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); + pf->num_avail_sw_msix += vsi->num_q_vectors; + /* reclaim HW interrupt back to the common pool */ + ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); + pf->num_avail_hw_msix += vsi->num_q_vectors; unroll_alloc_q_vector: ice_vsi_free_q_vectors(vsi); unroll_vsi_init: @@ -1962,7 +2036,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, static void ice_vsi_release_msix(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - u16 vector = vsi->base_vector; + u16 vector = vsi->hw_base_vector; struct ice_hw *hw = &pf->hw; u32 txq = 0; u32 rxq = 0; @@ -1994,7 +2068,7 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi) void ice_vsi_free_irq(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - int base = vsi->base_vector; + int base = vsi->sw_base_vector; if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { int i; @@ -2002,6 +2076,8 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) if (!vsi->q_vectors || !vsi->irqs_ready) return; + ice_vsi_release_msix(vsi); + vsi->irqs_ready = false; for (i = 0; i < vsi->num_q_vectors; i++) { u16 vector = i + base; @@ -2024,7 +2100,6 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) devm_free_irq(&pf->pdev->dev, irq_num, vsi->q_vectors[i]); } - ice_vsi_release_msix(vsi); } } @@ -2112,6 +2187,9 @@ static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id) int start = res->search_hint; int end = start; + if ((start + needed) > res->num_entries) + return -ENOMEM; + id |= ICE_RES_VALID_BIT; do { @@ -2185,9 +2263,9 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) */ void ice_vsi_dis_irq(struct ice_vsi *vsi) { + int base = vsi->sw_base_vector; struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; - int base = vsi->base_vector; u32 val; int i; @@ -2220,8 +2298,8 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi) /* disable each interrupt */ if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) { - for (i = vsi->base_vector; - i < (vsi->num_q_vectors + vsi->base_vector); i++) + for (i = vsi->hw_base_vector; + i < (vsi->num_q_vectors + vsi->hw_base_vector); i++) wr32(hw, GLINT_DYN_CTL(i), 0); ice_flush(hw); @@ -2264,10 +2342,12 @@ int ice_vsi_release(struct ice_vsi *vsi) ice_vsi_close(vsi); /* reclaim interrupt vectors back to PF */ - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); - pf->num_avail_msix += vsi->num_q_vectors; + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); + pf->num_avail_sw_msix += vsi->num_q_vectors; + ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); + pf->num_avail_hw_msix += vsi->num_q_vectors; - ice_remove_vsi_fltr(&pf->hw, vsi->vsi_num); + ice_remove_vsi_fltr(&pf->hw, vsi->idx); ice_vsi_delete(vsi); ice_vsi_free_q_vectors(vsi); ice_vsi_clear_rings(vsi); @@ -2301,8 +2381,10 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) return -EINVAL; ice_vsi_free_q_vectors(vsi); - ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx); - vsi->base_vector = 0; + ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); + ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); + vsi->sw_base_vector = 0; + vsi->hw_base_vector = 0; ice_vsi_clear_rings(vsi); ice_vsi_free_arrays(vsi, false); ice_vsi_set_num_qs(vsi); @@ -2342,8 +2424,8 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) for (i = 0; i < vsi->tc_cfg.numtc; i++) max_txqs[i] = vsi->num_txq; - ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num, - vsi->tc_cfg.ena_tc, max_txqs); + ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, + max_txqs); if (ret) { dev_info(&vsi->back->pdev->dev, "Failed VSI lan queue config\n"); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 4265464ee3d3..2617afe01c82 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -70,5 +70,7 @@ void ice_vsi_free_tx_rings(struct ice_vsi *vsi); int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc); +int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena); + irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data); #endif /* !_ICE_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a3513acd272b..46ccf265c218 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -95,7 +95,7 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf) /* Trigger sw interrupt to revive the queue */ v_idx = tx_ring->q_vector->v_idx; wr32(&vsi->back->hw, - GLINT_DYN_CTL(vsi->base_vector + v_idx), + GLINT_DYN_CTL(vsi->hw_base_vector + v_idx), (itr << GLINT_DYN_CTL_ITR_INDX_S) | GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M); @@ -253,7 +253,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) clear_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags); if (vsi->current_netdev_flags & IFF_PROMISC) { /* Apply TX filter rule to get traffic from VMs */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, true, + status = ice_cfg_dflt_vsi(hw, vsi->idx, true, ICE_FLTR_TX); if (status) { netdev_err(netdev, "Error setting default VSI %i tx rule\n", @@ -263,7 +263,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) goto out_promisc; } /* Apply RX filter rule to get traffic from wire */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, true, + status = ice_cfg_dflt_vsi(hw, vsi->idx, true, ICE_FLTR_RX); if (status) { netdev_err(netdev, "Error setting default VSI %i rx rule\n", @@ -274,7 +274,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) } } else { /* Clear TX filter rule to stop traffic from VMs */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, false, + status = ice_cfg_dflt_vsi(hw, vsi->idx, false, ICE_FLTR_TX); if (status) { netdev_err(netdev, "Error clearing default VSI %i tx rule\n", @@ -283,8 +283,8 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) err = -EIO; goto out_promisc; } - /* Clear filter RX to remove traffic from wire */ - status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, false, + /* Clear RX filter to remove traffic from wire */ + status = ice_cfg_dflt_vsi(hw, vsi->idx, false, ICE_FLTR_RX); if (status) { netdev_err(netdev, "Error clearing default VSI %i rx rule\n", @@ -1122,7 +1122,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) { int q_vectors = vsi->num_q_vectors; struct ice_pf *pf = vsi->back; - int base = vsi->base_vector; + int base = vsi->sw_base_vector; int rx_int_idx = 0; int tx_int_idx = 0; int vector, err; @@ -1203,7 +1203,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf) wr32(hw, PFINT_OICR_ENA, val); /* SW_ITR_IDX = 0, but don't change INTENA */ - wr32(hw, GLINT_DYN_CTL(pf->oicr_idx), + wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx), GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M); } @@ -1241,8 +1241,11 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) pf->corer_count++; else if (reset == ICE_RESET_GLOBR) pf->globr_count++; - else + else if (reset == ICE_RESET_EMPR) pf->empr_count++; + else + dev_dbg(&pf->pdev->dev, "Invalid reset type %d\n", + reset); /* If a reset cycle isn't already in progress, we set a bit in * pf->state so that the service task can start a reset/rebuild. @@ -1321,12 +1324,15 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf) ice_flush(&pf->hw); if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) { - synchronize_irq(pf->msix_entries[pf->oicr_idx].vector); + synchronize_irq(pf->msix_entries[pf->sw_oicr_idx].vector); devm_free_irq(&pf->pdev->dev, - pf->msix_entries[pf->oicr_idx].vector, pf); + pf->msix_entries[pf->sw_oicr_idx].vector, pf); } - ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID); + pf->num_avail_sw_msix += 1; + ice_free_res(pf->sw_irq_tracker, pf->sw_oicr_idx, ICE_RES_MISC_VEC_ID); + pf->num_avail_hw_msix += 1; + ice_free_res(pf->hw_irq_tracker, pf->hw_oicr_idx, ICE_RES_MISC_VEC_ID); } /** @@ -1356,39 +1362,53 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) if (ice_is_reset_in_progress(pf->state)) goto skip_req_irq; - /* reserve one vector in irq_tracker for misc interrupts */ - oicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); + /* reserve one vector in sw_irq_tracker for misc interrupts */ + oicr_idx = ice_get_res(pf, pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); if (oicr_idx < 0) return oicr_idx; - pf->oicr_idx = oicr_idx; + pf->num_avail_sw_msix -= 1; + pf->sw_oicr_idx = oicr_idx; + + /* reserve one vector in hw_irq_tracker for misc interrupts */ + oicr_idx = ice_get_res(pf, pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + if (oicr_idx < 0) { + ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + pf->num_avail_sw_msix += 1; + return oicr_idx; + } + pf->num_avail_hw_msix -= 1; + pf->hw_oicr_idx = oicr_idx; err = devm_request_irq(&pf->pdev->dev, - pf->msix_entries[pf->oicr_idx].vector, + pf->msix_entries[pf->sw_oicr_idx].vector, ice_misc_intr, 0, pf->int_name, pf); if (err) { dev_err(&pf->pdev->dev, "devm_request_irq for %s failed: %d\n", pf->int_name, err); - ice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); + ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + pf->num_avail_sw_msix += 1; + ice_free_res(pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID); + pf->num_avail_hw_msix += 1; return err; } skip_req_irq: ice_ena_misc_vector(pf); - val = ((pf->oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) | + val = ((pf->hw_oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) | PFINT_OICR_CTL_CAUSE_ENA_M); wr32(hw, PFINT_OICR_CTL, val); /* This enables Admin queue Interrupt causes */ - val = ((pf->oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) | + val = ((pf->hw_oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) | PFINT_FW_CTL_CAUSE_ENA_M); wr32(hw, PFINT_FW_CTL, val); - itr_gran = hw->itr_gran_200; + itr_gran = hw->itr_gran; - wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx), + wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx), ITR_TO_REG(ICE_ITR_8K, itr_gran)); ice_flush(hw); @@ -1797,6 +1817,7 @@ static int ice_ena_msix_range(struct ice_pf *pf) /* reserve vectors for LAN traffic */ pf->num_lan_msix = min_t(int, num_online_cpus(), v_left); v_budget += pf->num_lan_msix; + v_left -= pf->num_lan_msix; pf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget, sizeof(struct msix_entry), GFP_KERNEL); @@ -1824,10 +1845,11 @@ static int ice_ena_msix_range(struct ice_pf *pf) "not enough vectors. requested = %d, obtained = %d\n", v_budget, v_actual); if (v_actual >= (pf->num_lan_msix + 1)) { - pf->num_avail_msix = v_actual - (pf->num_lan_msix + 1); + pf->num_avail_sw_msix = v_actual - + (pf->num_lan_msix + 1); } else if (v_actual >= 2) { pf->num_lan_msix = 1; - pf->num_avail_msix = v_actual - 2; + pf->num_avail_sw_msix = v_actual - 2; } else { pci_disable_msix(pf->pdev); err = -ERANGE; @@ -1859,13 +1881,33 @@ static void ice_dis_msix(struct ice_pf *pf) clear_bit(ICE_FLAG_MSIX_ENA, pf->flags); } +/** + * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme + * @pf: board private structure + */ +static void ice_clear_interrupt_scheme(struct ice_pf *pf) +{ + if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) + ice_dis_msix(pf); + + if (pf->sw_irq_tracker) { + devm_kfree(&pf->pdev->dev, pf->sw_irq_tracker); + pf->sw_irq_tracker = NULL; + } + + if (pf->hw_irq_tracker) { + devm_kfree(&pf->pdev->dev, pf->hw_irq_tracker); + pf->hw_irq_tracker = NULL; + } +} + /** * ice_init_interrupt_scheme - Determine proper interrupt scheme * @pf: board private structure to initialize */ static int ice_init_interrupt_scheme(struct ice_pf *pf) { - int vectors = 0; + int vectors = 0, hw_vectors = 0; ssize_t size; if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) @@ -1879,32 +1921,33 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf) /* set up vector assignment tracking */ size = sizeof(struct ice_res_tracker) + (sizeof(u16) * vectors); - pf->irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); - if (!pf->irq_tracker) { + pf->sw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); + if (!pf->sw_irq_tracker) { ice_dis_msix(pf); return -ENOMEM; } - pf->irq_tracker->num_entries = vectors; + /* populate SW interrupts pool with number of OS granted IRQs. */ + pf->num_avail_sw_msix = vectors; + pf->sw_irq_tracker->num_entries = vectors; + + /* set up HW vector assignment tracking */ + hw_vectors = pf->hw.func_caps.common_cap.num_msix_vectors; + size = sizeof(struct ice_res_tracker) + (sizeof(u16) * hw_vectors); + + pf->hw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); + if (!pf->hw_irq_tracker) { + ice_clear_interrupt_scheme(pf); + return -ENOMEM; + } + + /* populate HW interrupts pool with number of HW supported irqs. */ + pf->num_avail_hw_msix = hw_vectors; + pf->hw_irq_tracker->num_entries = hw_vectors; return 0; } -/** - * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme - * @pf: board private structure - */ -static void ice_clear_interrupt_scheme(struct ice_pf *pf) -{ - if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) - ice_dis_msix(pf); - - if (pf->irq_tracker) { - devm_kfree(&pf->pdev->dev, pf->irq_tracker); - pf->irq_tracker = NULL; - } -} - /** * ice_probe - Device initialization routine * @pdev: PCI device information struct @@ -2087,6 +2130,7 @@ static int ice_probe(struct pci_dev *pdev, static void ice_remove(struct pci_dev *pdev) { struct ice_pf *pf = pci_get_drvdata(pdev); + int i; if (!pf) return; @@ -2096,6 +2140,11 @@ static void ice_remove(struct pci_dev *pdev) ice_vsi_release_all(pf); ice_free_irq_msix_misc(pf); + ice_for_each_vsi(pf, i) { + if (!pf->vsi[i]) + continue; + ice_vsi_free_q_vectors(pf->vsi[i]); + } ice_clear_interrupt_scheme(pf); ice_deinit_pf(pf); ice_deinit_hw(&pf->hw); @@ -2372,6 +2421,12 @@ static int ice_set_features(struct net_device *netdev, struct ice_vsi *vsi = np->vsi; int ret = 0; + if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH)) + ret = ice_vsi_manage_rss_lut(vsi, true); + else if (!(features & NETIF_F_RXHASH) && + netdev->features & NETIF_F_RXHASH) + ret = ice_vsi_manage_rss_lut(vsi, false); + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !(netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) ret = ice_vsi_manage_vlan_stripping(vsi, true); @@ -3135,6 +3190,44 @@ static int ice_vsi_rebuild_all(struct ice_pf *pf) return 0; } +/** + * ice_vsi_replay_all - replay all VSIs configuration in the PF + * @pf: the PF + */ +static int ice_vsi_replay_all(struct ice_pf *pf) +{ + struct ice_hw *hw = &pf->hw; + enum ice_status ret; + int i; + + /* loop through pf->vsi array and replay the VSI if found */ + for (i = 0; i < pf->num_alloc_vsi; i++) { + if (!pf->vsi[i]) + continue; + + ret = ice_replay_vsi(hw, pf->vsi[i]->idx); + if (ret) { + dev_err(&pf->pdev->dev, + "VSI at index %d replay failed %d\n", + pf->vsi[i]->idx, ret); + return -EIO; + } + + /* Re-map HW VSI number, using VSI handle that has been + * previously validated in ice_replay_vsi() call above + */ + pf->vsi[i]->vsi_num = ice_get_hw_vsi_num(hw, pf->vsi[i]->idx); + + dev_info(&pf->pdev->dev, + "VSI at index %d filter replayed successfully - vsi_num %i\n", + pf->vsi[i]->idx, pf->vsi[i]->vsi_num); + } + + /* Clean up replay filter after successful re-configuration */ + ice_replay_post(hw); + return 0; +} + /** * ice_rebuild - rebuild after reset * @pf: pf to rebuild @@ -3175,16 +3268,26 @@ static void ice_rebuild(struct ice_pf *pf) if (err) goto err_sched_init_port; + /* reset search_hint of irq_trackers to 0 since interrupts are + * reclaimed and could be allocated from beginning during VSI rebuild + */ + pf->sw_irq_tracker->search_hint = 0; + pf->hw_irq_tracker->search_hint = 0; + err = ice_vsi_rebuild_all(pf); if (err) { dev_err(dev, "ice_vsi_rebuild_all failed\n"); goto err_vsi_rebuild; } - ret = ice_replay_all_fltr(&pf->hw); - if (ret) { + err = ice_update_link_info(hw->port_info); + if (err) + dev_err(&pf->pdev->dev, "Get link status error %d\n", err); + + /* Replay all VSIs Configuration, including filters after reset */ + if (ice_vsi_replay_all(pf)) { dev_err(&pf->pdev->dev, - "error replaying switch filter rules\n"); + "error replaying VSI configurations with switch filter rules\n"); goto err_vsi_rebuild; } @@ -3310,7 +3413,7 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) struct ice_aqc_get_set_rss_keys *buf = (struct ice_aqc_get_set_rss_keys *)seed; - status = ice_aq_set_rss_key(hw, vsi->vsi_num, buf); + status = ice_aq_set_rss_key(hw, vsi->idx, buf); if (status) { dev_err(&pf->pdev->dev, @@ -3321,8 +3424,8 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) } if (lut) { - status = ice_aq_set_rss_lut(hw, vsi->vsi_num, - vsi->rss_lut_type, lut, lut_size); + status = ice_aq_set_rss_lut(hw, vsi->idx, vsi->rss_lut_type, + lut, lut_size); if (status) { dev_err(&pf->pdev->dev, "Cannot set RSS lut, err %d aq_err %d\n", @@ -3353,7 +3456,7 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) struct ice_aqc_get_set_rss_keys *buf = (struct ice_aqc_get_set_rss_keys *)seed; - status = ice_aq_get_rss_key(hw, vsi->vsi_num, buf); + status = ice_aq_get_rss_key(hw, vsi->idx, buf); if (status) { dev_err(&pf->pdev->dev, "Cannot get RSS key, err %d aq_err %d\n", @@ -3363,8 +3466,8 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) } if (lut) { - status = ice_aq_get_rss_lut(hw, vsi->vsi_num, - vsi->rss_lut_type, lut, lut_size); + status = ice_aq_get_rss_lut(hw, vsi->idx, vsi->rss_lut_type, + lut, lut_size); if (status) { dev_err(&pf->pdev->dev, "Cannot get RSS lut, err %d aq_err %d\n", @@ -3426,9 +3529,9 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) else /* change from VEB to VEPA mode */ ctxt.info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_ALLOW_LB; - ctxt.vsi_num = vsi->vsi_num; ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID); - status = ice_aq_update_vsi(hw, &ctxt, NULL); + + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); if (status) { dev_err(dev, "update VSI for bridge mode failed, bmode = %d err %d aq_err %d\n", bmode, status, hw->adminq.sq_last_status); @@ -3568,7 +3671,7 @@ static void ice_tx_timeout(struct net_device *netdev) if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) val = rd32(&pf->hw, GLINT_DYN_CTL(tx_ring->q_vector->v_idx + - tx_ring->vsi->base_vector - 1)); + tx_ring->vsi->hw_base_vector)); netdev_info(netdev, "tx_timeout: VSI_num: %d, Q %d, NTC: 0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x, INT: 0x%x\n", vsi->vsi_num, hung_queue, tx_ring->next_to_clean, diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 9c4f408f222d..7cc8aa18a22b 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -599,9 +599,7 @@ ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids, static void ice_sched_clear_tx_topo(struct ice_port_info *pi) { struct ice_sched_agg_info *agg_info; - struct ice_sched_vsi_info *vsi_elem; struct ice_sched_agg_info *atmp; - struct ice_sched_vsi_info *tmp; struct ice_hw *hw; if (!pi) @@ -620,13 +618,6 @@ static void ice_sched_clear_tx_topo(struct ice_port_info *pi) } } - /* remove the vsi list */ - list_for_each_entry_safe(vsi_elem, tmp, &pi->vsi_info_list, - list_entry) { - list_del(&vsi_elem->list_entry); - devm_kfree(ice_hw_to_dev(hw), vsi_elem); - } - if (pi->root) { ice_free_sched_node(pi, pi->root); pi->root = NULL; @@ -676,31 +667,6 @@ void ice_sched_cleanup_all(struct ice_hw *hw) hw->max_cgds = 0; } -/** - * ice_sched_create_vsi_info_entry - create an empty new VSI entry - * @pi: port information structure - * @vsi_id: VSI Id - * - * This function creates a new VSI entry and adds it to list - */ -static struct ice_sched_vsi_info * -ice_sched_create_vsi_info_entry(struct ice_port_info *pi, u16 vsi_id) -{ - struct ice_sched_vsi_info *vsi_elem; - - if (!pi) - return NULL; - - vsi_elem = devm_kzalloc(ice_hw_to_dev(pi->hw), sizeof(*vsi_elem), - GFP_KERNEL); - if (!vsi_elem) - return NULL; - - list_add(&vsi_elem->list_entry, &pi->vsi_info_list); - vsi_elem->vsi_id = vsi_id; - return vsi_elem; -} - /** * ice_sched_add_elems - add nodes to hw and SW DB * @pi: port information structure @@ -1072,7 +1038,6 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi) pi->port_state = ICE_SCHED_PORT_STATE_READY; mutex_init(&pi->sched_lock); INIT_LIST_HEAD(&pi->agg_list); - INIT_LIST_HEAD(&pi->vsi_info_list); err_init_port: if (status && pi->root) { @@ -1141,27 +1106,6 @@ enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw) return status; } -/** - * ice_sched_get_vsi_info_entry - Get the vsi entry list for given vsi_id - * @pi: port information structure - * @vsi_id: vsi id - * - * This function retrieves the vsi list for the given vsi id - */ -static struct ice_sched_vsi_info * -ice_sched_get_vsi_info_entry(struct ice_port_info *pi, u16 vsi_id) -{ - struct ice_sched_vsi_info *list_elem; - - if (!pi) - return NULL; - - list_for_each_entry(list_elem, &pi->vsi_info_list, list_entry) - if (list_elem->vsi_id == vsi_id) - return list_elem; - return NULL; -} - /** * ice_sched_find_node_in_subtree - Find node in part of base node subtree * @hw: pointer to the hw struct @@ -1198,30 +1142,28 @@ ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base, /** * ice_sched_get_free_qparent - Get a free lan or rdma q group node * @pi: port information structure - * @vsi_id: vsi id + * @vsi_handle: software VSI handle * @tc: branch number * @owner: lan or rdma * * This function retrieves a free lan or rdma q group node */ struct ice_sched_node * -ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc, +ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 owner) { struct ice_sched_node *vsi_node, *qgrp_node = NULL; - struct ice_sched_vsi_info *list_elem; + struct ice_vsi_ctx *vsi_ctx; u16 max_children; u8 qgrp_layer; qgrp_layer = ice_sched_get_qgrp_layer(pi->hw); max_children = pi->hw->max_children[qgrp_layer]; - list_elem = ice_sched_get_vsi_info_entry(pi, vsi_id); - if (!list_elem) - goto lan_q_exit; - - vsi_node = list_elem->vsi_node[tc]; - + vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); + if (!vsi_ctx) + return NULL; + vsi_node = vsi_ctx->sched.vsi_node[tc]; /* validate invalid VSI id */ if (!vsi_node) goto lan_q_exit; @@ -1245,14 +1187,14 @@ ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc, * ice_sched_get_vsi_node - Get a VSI node based on VSI id * @hw: pointer to the hw struct * @tc_node: pointer to the TC node - * @vsi_id: VSI id + * @vsi_handle: software VSI handle * * This function retrieves a VSI node for a given VSI id from a given * TC branch */ static struct ice_sched_node * ice_sched_get_vsi_node(struct ice_hw *hw, struct ice_sched_node *tc_node, - u16 vsi_id) + u16 vsi_handle) { struct ice_sched_node *node; u8 vsi_layer; @@ -1262,7 +1204,7 @@ ice_sched_get_vsi_node(struct ice_hw *hw, struct ice_sched_node *tc_node, /* Check whether it already exists */ while (node) { - if (node->vsi_id == vsi_id) + if (node->vsi_handle == vsi_handle) return node; node = node->sibling; } @@ -1301,7 +1243,7 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes) /** * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree * @pi: port information structure - * @vsi_id: VSI id + * @vsi_handle: software VSI handle * @tc_node: pointer to the TC node * @num_nodes: pointer to the num nodes that needs to be added per layer * @owner: node owner (lan or rdma) @@ -1310,7 +1252,7 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes) * lan and rdma separately. */ static enum ice_status -ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, +ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, struct ice_sched_node *tc_node, u16 *num_nodes, u8 owner) { @@ -1323,7 +1265,7 @@ ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, qgl = ice_sched_get_qgrp_layer(hw); vsil = ice_sched_get_vsi_layer(hw); - parent = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + parent = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); for (i = vsil + 1; i <= qgl; i++) { if (!parent) return ICE_ERR_CFG; @@ -1436,7 +1378,7 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw, /** * ice_sched_add_vsi_support_nodes - add VSI supported nodes into tx tree * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc_node: pointer to TC node * @num_nodes: pointer to num nodes array * @@ -1444,7 +1386,7 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw, * VSI, its parent and intermediate nodes in below layers */ static enum ice_status -ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, +ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle, struct ice_sched_node *tc_node, u16 *num_nodes) { struct ice_sched_node *parent = tc_node; @@ -1478,7 +1420,7 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, return ICE_ERR_CFG; if (i == vsil) - parent->vsi_id = vsi_id; + parent->vsi_handle = vsi_handle; } return 0; @@ -1487,13 +1429,13 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id, /** * ice_sched_add_vsi_to_topo - add a new VSI into tree * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc: TC number * * This function adds a new VSI into scheduler tree */ static enum ice_status -ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc) +ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc) { u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; struct ice_sched_node *tc_node; @@ -1507,13 +1449,14 @@ ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc) ice_sched_calc_vsi_support_nodes(hw, tc_node, num_nodes); /* add vsi supported nodes to tc subtree */ - return ice_sched_add_vsi_support_nodes(pi, vsi_id, tc_node, num_nodes); + return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node, + num_nodes); } /** * ice_sched_update_vsi_child_nodes - update VSI child nodes * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc: TC number * @new_numqs: new number of max queues * @owner: owner of this subtree @@ -1521,14 +1464,14 @@ ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc) * This function updates the VSI child nodes based on the number of queues */ static enum ice_status -ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, - u16 new_numqs, u8 owner) +ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, + u8 tc, u16 new_numqs, u8 owner) { u16 prev_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; struct ice_sched_node *vsi_node; struct ice_sched_node *tc_node; - struct ice_sched_vsi_info *vsi; + struct ice_vsi_ctx *vsi_ctx; enum ice_status status = 0; struct ice_hw *hw = pi->hw; u16 prev_numqs; @@ -1538,16 +1481,16 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, if (!tc_node) return ICE_ERR_CFG; - vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); if (!vsi_node) return ICE_ERR_CFG; - vsi = ice_sched_get_vsi_info_entry(pi, vsi_id); - if (!vsi) - return ICE_ERR_CFG; + vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); + if (!vsi_ctx) + return ICE_ERR_PARAM; if (owner == ICE_SCHED_NODE_OWNER_LAN) - prev_numqs = vsi->max_lanq[tc]; + prev_numqs = vsi_ctx->sched.max_lanq[tc]; else return ICE_ERR_PARAM; @@ -1572,13 +1515,13 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++) new_num_nodes[i] -= prev_num_nodes[i]; - status = ice_sched_add_vsi_child_nodes(pi, vsi_id, tc_node, + status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node, new_num_nodes, owner); if (status) return status; } - vsi->max_lanq[tc] = new_numqs; + vsi_ctx->sched.max_lanq[tc] = new_numqs; return status; } @@ -1586,7 +1529,7 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, /** * ice_sched_cfg_vsi - configure the new/exisiting VSI * @pi: port information structure - * @vsi_id: VSI Id + * @vsi_handle: software VSI handle * @tc: TC number * @maxqs: max number of queues * @owner: lan or rdma @@ -1597,25 +1540,21 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, * disabled then suspend the VSI if it is not already. */ enum ice_status -ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs, +ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs, u8 owner, bool enable) { struct ice_sched_node *vsi_node, *tc_node; - struct ice_sched_vsi_info *vsi; + struct ice_vsi_ctx *vsi_ctx; enum ice_status status = 0; struct ice_hw *hw = pi->hw; tc_node = ice_sched_get_tc_node(pi, tc); if (!tc_node) return ICE_ERR_PARAM; - - vsi = ice_sched_get_vsi_info_entry(pi, vsi_id); - if (!vsi) - vsi = ice_sched_create_vsi_info_entry(pi, vsi_id); - if (!vsi) - return ICE_ERR_NO_MEMORY; - - vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); + if (!vsi_ctx) + return ICE_ERR_PARAM; + vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); /* suspend the VSI if tc is not enabled */ if (!enable) { @@ -1632,20 +1571,26 @@ ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs, /* TC is enabled, if it is a new VSI then add it to the tree */ if (!vsi_node) { - status = ice_sched_add_vsi_to_topo(pi, vsi_id, tc); + status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc); if (status) return status; - vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id); + vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle); if (!vsi_node) return ICE_ERR_CFG; - vsi->vsi_node[tc] = vsi_node; + vsi_ctx->sched.vsi_node[tc] = vsi_node; vsi_node->in_use = true; + /* invalidate the max queues whenever VSI gets added first time + * into the scheduler tree (boot or after reset). We need to + * recreate the child nodes all the time in these cases. + */ + vsi_ctx->sched.max_lanq[tc] = 0; } /* update the VSI child nodes */ - status = ice_sched_update_vsi_child_nodes(pi, vsi_id, tc, maxqs, owner); + status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs, + owner); if (status) return status; diff --git a/drivers/net/ethernet/intel/ice/ice_sched.h b/drivers/net/ethernet/intel/ice/ice_sched.h index badadcc120d3..5dc9cfa04c58 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.h +++ b/drivers/net/ethernet/intel/ice/ice_sched.h @@ -12,7 +12,6 @@ struct ice_sched_agg_vsi_info { struct list_head list_entry; DECLARE_BITMAP(tc_bitmap, ICE_MAX_TRAFFIC_CLASS); - u16 vsi_id; }; struct ice_sched_agg_info { @@ -35,9 +34,9 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer, void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node); struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc); struct ice_sched_node * -ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc, +ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 owner); enum ice_status -ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs, +ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs, u8 owner, bool enable); #endif /* _ICE_SCHED_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 65b4e1cca6be..e949224b5282 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -106,6 +106,7 @@ ice_init_def_sw_recp(struct ice_hw *hw) for (i = 0; i < ICE_SW_LKUP_LAST; i++) { recps[i].root_rid = i; INIT_LIST_HEAD(&recps[i].filt_rules); + INIT_LIST_HEAD(&recps[i].filt_replay_rules); mutex_init(&recps[i].filt_rule_lock); } @@ -247,7 +248,7 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, * * Update VSI context in the hardware (0x0211) */ -enum ice_status +static enum ice_status ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, struct ice_sq_cd *cd) { @@ -276,65 +277,6 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, return status; } -/** - * ice_update_fltr_vsi_map - update given filter VSI map - * @list_head: list for which filters needs to be updated - * @list_lock: filter lock which needs to be updated - * @old_vsi_num: old VSI HW id - * @new_vsi_num: new VSI HW id - * - * update the VSI map for a given filter list - */ -static void -ice_update_fltr_vsi_map(struct list_head *list_head, - struct mutex *list_lock, u16 old_vsi_num, - u16 new_vsi_num) -{ - struct ice_fltr_mgmt_list_entry *itr; - - mutex_lock(list_lock); - if (list_empty(list_head)) - goto exit_update_map; - - list_for_each_entry(itr, list_head, list_entry) { - if (itr->vsi_list_info && - test_bit(old_vsi_num, itr->vsi_list_info->vsi_map)) { - clear_bit(old_vsi_num, itr->vsi_list_info->vsi_map); - set_bit(new_vsi_num, itr->vsi_list_info->vsi_map); - } else if (itr->fltr_info.fltr_act == ICE_FWD_TO_VSI && - itr->fltr_info.fwd_id.vsi_id == old_vsi_num) { - itr->fltr_info.fwd_id.vsi_id = new_vsi_num; - itr->fltr_info.src = new_vsi_num; - } - } -exit_update_map: - mutex_unlock(list_lock); -} - -/** - * ice_update_all_fltr_vsi_map - update all filters VSI map - * @hw: pointer to the hardware structure - * @old_vsi_num: old VSI HW id - * @new_vsi_num: new VSI HW id - * - * update all filters VSI map - */ -static void -ice_update_all_fltr_vsi_map(struct ice_hw *hw, u16 old_vsi_num, u16 new_vsi_num) -{ - struct ice_switch_info *sw = hw->switch_info; - u8 i; - - for (i = 0; i < ICE_SW_LKUP_LAST; i++) { - struct list_head *head = &sw->recp_list[i].filt_rules; - struct mutex *lock; /* Lock to protect filter rule list */ - - lock = &sw->recp_list[i].filt_rule_lock; - ice_update_fltr_vsi_map(head, lock, old_vsi_num, - new_vsi_num); - } -} - /** * ice_is_vsi_valid - check whether the VSI is valid or not * @hw: pointer to the hw struct @@ -342,7 +284,7 @@ ice_update_all_fltr_vsi_map(struct ice_hw *hw, u16 old_vsi_num, u16 new_vsi_num) * * check whether the VSI is valid or not */ -static bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) +bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) { return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle]; } @@ -355,7 +297,7 @@ static bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle) * return the hw VSI number * Caution: call this function only if VSI is valid (ice_is_vsi_valid) */ -static u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) +u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) { return hw->vsi_ctx[vsi_handle]->vsi_num; } @@ -367,7 +309,7 @@ static u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle) * * return the VSI context entry for a given VSI handle */ -static struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) +struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle) { return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle]; } @@ -440,12 +382,8 @@ ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx); } else { /* update with new HW VSI num */ - if (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num) { - /* update all filter lists with new HW VSI num */ - ice_update_all_fltr_vsi_map(hw, tmp_vsi_ctx->vsi_num, - vsi_ctx->vsi_num); + if (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num) tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; - } } return status; @@ -476,6 +414,25 @@ ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, return status; } +/** + * ice_update_vsi + * @hw: pointer to the hw struct + * @vsi_handle: unique VSI handle + * @vsi_ctx: pointer to a VSI context struct + * @cd: pointer to command details structure or NULL + * + * Update VSI context in the hardware + */ +enum ice_status +ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + struct ice_sq_cd *cd) +{ + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle); + return ice_aq_update_vsi(hw, vsi_ctx, cd); +} + /** * ice_aq_alloc_free_vsi_list * @hw: pointer to the hw struct @@ -716,7 +673,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info, switch (f_info->fltr_act) { case ICE_FWD_TO_VSI: - act |= (f_info->fwd_id.vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & + act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M; if (f_info->lkup_type != ICE_SW_LKUP_VLAN) act |= ICE_SINGLE_ACT_VSI_FORWARDING | @@ -832,8 +789,8 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, enum ice_status status; u16 lg_act_size; u16 rules_size; - u16 vsi_info; u32 act; + u16 id; if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC) return ICE_ERR_PARAM; @@ -859,12 +816,11 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, /* First action VSI forwarding or VSI list forwarding depending on how * many VSIs */ - vsi_info = (m_ent->vsi_count > 1) ? - m_ent->fltr_info.fwd_id.vsi_list_id : - m_ent->fltr_info.fwd_id.vsi_id; + id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id : + m_ent->fltr_info.fwd_id.hw_vsi_id; act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT; - act |= (vsi_info << ICE_LG_ACT_VSI_LIST_ID_S) & + act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M; if (m_ent->vsi_count > 1) act |= ICE_LG_ACT_VSI_LIST; @@ -917,15 +873,15 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, /** * ice_create_vsi_list_map * @hw: pointer to the hardware structure - * @vsi_array: array of VSIs to form a VSI list - * @num_vsi: num VSI in the array + * @vsi_handle_arr: array of VSI handles to set in the VSI mapping + * @num_vsi: number of VSI handles in the array * @vsi_list_id: VSI list id generated as part of allocate resource * * Helper function to create a new entry of VSI list id to VSI mapping * using the given VSI list id */ static struct ice_vsi_list_map_info * -ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, +ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, u16 vsi_list_id) { struct ice_switch_info *sw = hw->switch_info; @@ -937,9 +893,9 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, return NULL; v_map->vsi_list_id = vsi_list_id; - + v_map->ref_cnt = 1; for (i = 0; i < num_vsi; i++) - set_bit(vsi_array[i], v_map->vsi_map); + set_bit(vsi_handle_arr[i], v_map->vsi_map); list_add(&v_map->list_entry, &sw->vsi_list_map_head); return v_map; @@ -948,8 +904,8 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, /** * ice_update_vsi_list_rule * @hw: pointer to the hardware structure - * @vsi_array: array of VSIs to form a VSI list - * @num_vsi: num VSI in the array + * @vsi_handle_arr: array of VSI handles to form a VSI list + * @num_vsi: number of VSI handles in the array * @vsi_list_id: VSI list id generated as part of allocate resource * @remove: Boolean value to indicate if this is a remove action * @opc: switch rules population command type - pass in the command opcode @@ -959,7 +915,7 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, * using the given VSI list id */ static enum ice_status -ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, +ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, u16 vsi_list_id, bool remove, enum ice_adminq_opc opc, enum ice_sw_lkup_type lkup_type) { @@ -990,9 +946,15 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL); if (!s_rule) return ICE_ERR_NO_MEMORY; - - for (i = 0; i < num_vsi; i++) - s_rule->pdata.vsi_list.vsi[i] = cpu_to_le16(vsi_array[i]); + for (i = 0; i < num_vsi; i++) { + if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) { + status = ICE_ERR_PARAM; + goto exit; + } + /* AQ call requires hw_vsi_id(s) */ + s_rule->pdata.vsi_list.vsi[i] = + cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i])); + } s_rule->type = cpu_to_le16(type); s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi); @@ -1000,6 +962,7 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL); +exit: devm_kfree(ice_hw_to_dev(hw), s_rule); return status; } @@ -1007,21 +970,16 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, /** * ice_create_vsi_list_rule - Creates and populates a VSI list rule * @hw: pointer to the hw struct - * @vsi_array: array of VSIs to form a VSI list - * @num_vsi: number of VSIs in the array + * @vsi_handle_arr: array of VSI handles to form a VSI list + * @num_vsi: number of VSI handles in the array * @vsi_list_id: stores the ID of the VSI list to be created * @lkup_type: switch rule filter's lookup type */ static enum ice_status -ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, +ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi, u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type) { enum ice_status status; - int i; - - for (i = 0; i < num_vsi; i++) - if (vsi_array[i] >= ICE_MAX_VSI) - return ICE_ERR_OUT_OF_RANGE; status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type, ice_aqc_opc_alloc_res); @@ -1029,9 +987,9 @@ ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi, return status; /* Update the newly created VSI list to include the specified VSIs */ - return ice_update_vsi_list_rule(hw, vsi_array, num_vsi, *vsi_list_id, - false, ice_aqc_opc_add_sw_rules, - lkup_type); + return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi, + *vsi_list_id, false, + ice_aqc_opc_add_sw_rules, lkup_type); } /** @@ -1217,15 +1175,15 @@ ice_add_update_vsi_list(struct ice_hw *hw, * new VSIs. */ struct ice_fltr_info tmp_fltr; - u16 vsi_id_arr[2]; + u16 vsi_handle_arr[2]; /* A rule already exists with the new VSI being added */ - if (cur_fltr->fwd_id.vsi_id == new_fltr->fwd_id.vsi_id) + if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id) return ICE_ERR_ALREADY_EXISTS; - vsi_id_arr[0] = cur_fltr->fwd_id.vsi_id; - vsi_id_arr[1] = new_fltr->fwd_id.vsi_id; - status = ice_create_vsi_list_rule(hw, &vsi_id_arr[0], 2, + vsi_handle_arr[0] = cur_fltr->vsi_handle; + vsi_handle_arr[1] = new_fltr->vsi_handle; + status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, &vsi_list_id, new_fltr->lkup_type); if (status) @@ -1245,7 +1203,7 @@ ice_add_update_vsi_list(struct ice_hw *hw, cur_fltr->fwd_id.vsi_list_id = vsi_list_id; cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; m_entry->vsi_list_info = - ice_create_vsi_list_map(hw, &vsi_id_arr[0], 2, + ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, vsi_list_id); /* If this entry was large action then the large action needs @@ -1257,11 +1215,11 @@ ice_add_update_vsi_list(struct ice_hw *hw, m_entry->sw_marker_id, m_entry->lg_act_idx); } else { - u16 vsi_id = new_fltr->fwd_id.vsi_id; + u16 vsi_handle = new_fltr->vsi_handle; enum ice_adminq_opc opcode; /* A rule already exists with the new VSI being added */ - if (test_bit(vsi_id, m_entry->vsi_list_info->vsi_map)) + if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map)) return 0; /* Update the previously created VSI list set with @@ -1270,12 +1228,12 @@ ice_add_update_vsi_list(struct ice_hw *hw, vsi_list_id = cur_fltr->fwd_id.vsi_list_id; opcode = ice_aqc_opc_update_sw_rules; - status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, - false, opcode, + status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, + vsi_list_id, false, opcode, new_fltr->lkup_type); /* update VSI list mapping info with new VSI id */ if (!status) - set_bit(vsi_id, m_entry->vsi_list_info->vsi_map); + set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map); } if (!status) m_entry->vsi_count++; @@ -1310,6 +1268,39 @@ ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info) return ret; } +/** + * ice_find_vsi_list_entry - Search VSI list map with VSI count 1 + * @hw: pointer to the hardware structure + * @recp_id: lookup type for which VSI lists needs to be searched + * @vsi_handle: VSI handle to be found in VSI list + * @vsi_list_id: VSI list id found containing vsi_handle + * + * Helper function to search a VSI list with single entry containing given VSI + * handle element. This can be extended further to search VSI list with more + * than 1 vsi_count. Returns pointer to VSI list entry if found. + */ +static struct ice_vsi_list_map_info * +ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle, + u16 *vsi_list_id) +{ + struct ice_vsi_list_map_info *map_info = NULL; + struct ice_switch_info *sw = hw->switch_info; + struct ice_fltr_mgmt_list_entry *list_itr; + struct list_head *list_head; + + list_head = &sw->recp_list[recp_id].filt_rules; + list_for_each_entry(list_itr, list_head, list_entry) { + if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) { + map_info = list_itr->vsi_list_info; + if (test_bit(vsi_handle, map_info->vsi_map)) { + *vsi_list_id = map_info->vsi_list_id; + return map_info; + } + } + } + return NULL; +} + /** * ice_add_rule_internal - add rule for a given lookup type * @hw: pointer to the hardware structure @@ -1328,6 +1319,11 @@ ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status = 0; + if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) + return ICE_ERR_PARAM; + f_entry->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); + rule_lock = &sw->recp_list[recp_id].filt_rule_lock; mutex_lock(rule_lock); @@ -1335,7 +1331,7 @@ ice_add_rule_internal(struct ice_hw *hw, u8 recp_id, if (new_fltr->flag & ICE_FLTR_RX) new_fltr->src = hw->port_info->lport; else if (new_fltr->flag & ICE_FLTR_TX) - new_fltr->src = f_entry->fltr_info.fwd_id.vsi_id; + new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id; m_entry = ice_find_rule_entry(hw, recp_id, new_fltr); if (!m_entry) { @@ -1388,12 +1384,12 @@ ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id, /** * ice_rem_update_vsi_list * @hw: pointer to the hardware structure - * @vsi_id: ID of the VSI to remove + * @vsi_handle: VSI handle of the VSI to remove * @fm_list: filter management entry for which the VSI list management needs to * be done */ static enum ice_status -ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_id, +ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle, struct ice_fltr_mgmt_list_entry *fm_list) { enum ice_sw_lkup_type lkup_type; @@ -1405,33 +1401,31 @@ ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_id, return ICE_ERR_PARAM; /* A rule with the VSI being removed does not exist */ - if (!test_bit(vsi_id, fm_list->vsi_list_info->vsi_map)) + if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map)) return ICE_ERR_DOES_NOT_EXIST; lkup_type = fm_list->fltr_info.lkup_type; vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id; - - status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id, true, + status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true, ice_aqc_opc_update_sw_rules, lkup_type); if (status) return status; fm_list->vsi_count--; - clear_bit(vsi_id, fm_list->vsi_list_info->vsi_map); + clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map); if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) || (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) { struct ice_vsi_list_map_info *vsi_list_info = fm_list->vsi_list_info; - u16 rem_vsi_id; + u16 rem_vsi_handle; - rem_vsi_id = find_first_bit(vsi_list_info->vsi_map, - ICE_MAX_VSI); - if (rem_vsi_id == ICE_MAX_VSI) + rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map, + ICE_MAX_VSI); + if (!ice_is_vsi_valid(hw, rem_vsi_handle)) return ICE_ERR_OUT_OF_RANGE; - - status = ice_update_vsi_list_rule(hw, &rem_vsi_id, 1, + status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1, vsi_list_id, true, ice_aqc_opc_update_sw_rules, lkup_type); @@ -1445,7 +1439,9 @@ ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_id, /* Change the list entry action from VSI_LIST to VSI */ fm_list->fltr_info.fltr_act = ICE_FWD_TO_VSI; - fm_list->fltr_info.fwd_id.vsi_id = rem_vsi_id; + fm_list->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, rem_vsi_handle); + fm_list->fltr_info.vsi_handle = rem_vsi_handle; list_del(&vsi_list_info->list_entry); devm_kfree(ice_hw_to_dev(hw), vsi_list_info); @@ -1470,7 +1466,12 @@ ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status = 0; bool remove_rule = false; - u16 vsi_id; + u16 vsi_handle; + + if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) + return ICE_ERR_PARAM; + f_entry->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); rule_lock = &sw->recp_list[recp_id].filt_rule_lock; mutex_lock(rule_lock); @@ -1482,9 +1483,14 @@ ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id, if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) { remove_rule = true; + } else if (!list_elem->vsi_list_info) { + status = ICE_ERR_DOES_NOT_EXIST; + goto exit; } else { - vsi_id = f_entry->fltr_info.fwd_id.vsi_id; - status = ice_rem_update_vsi_list(hw, vsi_id, list_elem); + if (list_elem->vsi_list_info->ref_cnt > 1) + list_elem->vsi_list_info->ref_cnt--; + vsi_handle = f_entry->fltr_info.vsi_handle; + status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem); if (status) goto exit; /* if vsi count goes to zero after updating the vsi list */ @@ -1556,8 +1562,19 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list) rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock; list_for_each_entry(m_list_itr, m_list, list_entry) { u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0]; + u16 vsi_handle; + u16 hw_vsi_id; m_list_itr->fltr_info.flag = ICE_FLTR_TX; + vsi_handle = m_list_itr->fltr_info.vsi_handle; + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); + m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id; + /* update the src in case it is vsi num */ + if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI) + return ICE_ERR_PARAM; + m_list_itr->fltr_info.src = hw_vsi_id; if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC || is_zero_ether_addr(add)) return ICE_ERR_PARAM; @@ -1676,57 +1693,145 @@ static enum ice_status ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry) { struct ice_switch_info *sw = hw->switch_info; - struct ice_fltr_info *new_fltr, *cur_fltr; struct ice_fltr_mgmt_list_entry *v_list_itr; + struct ice_fltr_info *new_fltr, *cur_fltr; + enum ice_sw_lkup_type lkup_type; + u16 vsi_list_id = 0, vsi_handle; struct mutex *rule_lock; /* Lock to protect filter rule list */ enum ice_status status = 0; + if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle)) + return ICE_ERR_PARAM; + + f_entry->fltr_info.fwd_id.hw_vsi_id = + ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle); new_fltr = &f_entry->fltr_info; + /* VLAN id should only be 12 bits */ if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID) return ICE_ERR_PARAM; + if (new_fltr->src_id != ICE_SRC_ID_VSI) + return ICE_ERR_PARAM; + + new_fltr->src = new_fltr->fwd_id.hw_vsi_id; + lkup_type = new_fltr->lkup_type; + vsi_handle = new_fltr->vsi_handle; rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock; mutex_lock(rule_lock); v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); if (!v_list_itr) { - u16 vsi_id = ICE_VSI_INVAL_ID; - u16 vsi_list_id = 0; + struct ice_vsi_list_map_info *map_info = NULL; if (new_fltr->fltr_act == ICE_FWD_TO_VSI) { - enum ice_sw_lkup_type lkup_type = new_fltr->lkup_type; - - /* All VLAN pruning rules use a VSI list. - * Convert the action to forwarding to a VSI list. + /* All VLAN pruning rules use a VSI list. Check if + * there is already a VSI list containing VSI that we + * want to add. If found, use the same vsi_list_id for + * this new VLAN rule or else create a new list. */ - vsi_id = new_fltr->fwd_id.vsi_id; - status = ice_create_vsi_list_rule(hw, &vsi_id, 1, - &vsi_list_id, - lkup_type); - if (status) - goto exit; + map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN, + vsi_handle, + &vsi_list_id); + if (!map_info) { + status = ice_create_vsi_list_rule(hw, + &vsi_handle, + 1, + &vsi_list_id, + lkup_type); + if (status) + goto exit; + } + /* Convert the action to forwarding to a VSI list. */ new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST; new_fltr->fwd_id.vsi_list_id = vsi_list_id; } status = ice_create_pkt_fwd_rule(hw, f_entry); - if (!status && vsi_id != ICE_VSI_INVAL_ID) { + if (!status) { v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr); if (!v_list_itr) { status = ICE_ERR_DOES_NOT_EXIST; goto exit; } - v_list_itr->vsi_list_info = - ice_create_vsi_list_map(hw, &vsi_id, 1, - vsi_list_id); + /* reuse VSI list for new rule and increment ref_cnt */ + if (map_info) { + v_list_itr->vsi_list_info = map_info; + map_info->ref_cnt++; + } else { + v_list_itr->vsi_list_info = + ice_create_vsi_list_map(hw, &vsi_handle, + 1, vsi_list_id); + } + } + } else if (v_list_itr->vsi_list_info->ref_cnt == 1) { + /* Update existing VSI list to add new VSI id only if it used + * by one VLAN rule. + */ + cur_fltr = &v_list_itr->fltr_info; + status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, + new_fltr); + } else { + /* If VLAN rule exists and VSI list being used by this rule is + * referenced by more than 1 VLAN rule. Then create a new VSI + * list appending previous VSI with new VSI and update existing + * VLAN rule to point to new VSI list id + */ + struct ice_fltr_info tmp_fltr; + u16 vsi_handle_arr[2]; + u16 cur_handle; + + /* Current implementation only supports reusing VSI list with + * one VSI count. We should never hit below condition + */ + if (v_list_itr->vsi_count > 1 && + v_list_itr->vsi_list_info->ref_cnt > 1) { + ice_debug(hw, ICE_DBG_SW, + "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n"); + status = ICE_ERR_CFG; + goto exit; } - goto exit; - } + cur_handle = + find_first_bit(v_list_itr->vsi_list_info->vsi_map, + ICE_MAX_VSI); - cur_fltr = &v_list_itr->fltr_info; - status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, new_fltr); + /* A rule already exists with the new VSI being added */ + if (cur_handle == vsi_handle) { + status = ICE_ERR_ALREADY_EXISTS; + goto exit; + } + + vsi_handle_arr[0] = cur_handle; + vsi_handle_arr[1] = vsi_handle; + status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2, + &vsi_list_id, lkup_type); + if (status) + goto exit; + + tmp_fltr = v_list_itr->fltr_info; + tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id; + tmp_fltr.fwd_id.vsi_list_id = vsi_list_id; + tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST; + /* Update the previous switch rule to a new VSI list which + * includes current VSI thats requested + */ + status = ice_update_pkt_fwd_rule(hw, &tmp_fltr); + if (status) + goto exit; + + /* before overriding VSI list map info. decrement ref_cnt of + * previous VSI list + */ + v_list_itr->vsi_list_info->ref_cnt--; + + /* now update to newly created list */ + v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id; + v_list_itr->vsi_list_info = + ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2, + vsi_list_id); + v_list_itr->vsi_count++; + } exit: mutex_unlock(rule_lock); @@ -1779,7 +1884,7 @@ ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) /** * ice_cfg_dflt_vsi - change state of VSI to set/clear default * @hw: pointer to the hardware structure - * @vsi_id: number of VSI to set as default + * @vsi_handle: VSI handle to set as default * @set: true to add the above mentioned switch rule, false to remove it * @direction: ICE_FLTR_RX or ICE_FLTR_TX * @@ -1787,13 +1892,18 @@ ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head) * (represented by swid) */ enum ice_status -ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction) +ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction) { struct ice_aqc_sw_rules_elem *s_rule; struct ice_fltr_info f_info; enum ice_adminq_opc opcode; enum ice_status status; u16 s_rule_size; + u16 hw_vsi_id; + + if (!ice_is_vsi_valid(hw, vsi_handle)) + return ICE_ERR_PARAM; + hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE : ICE_SW_RULE_RX_TX_NO_HDR_SIZE; @@ -1806,15 +1916,17 @@ ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction) f_info.lkup_type = ICE_SW_LKUP_DFLT; f_info.flag = direction; f_info.fltr_act = ICE_FWD_TO_VSI; - f_info.fwd_id.vsi_id = vsi_id; + f_info.fwd_id.hw_vsi_id = hw_vsi_id; if (f_info.flag & ICE_FLTR_RX) { f_info.src = hw->port_info->lport; + f_info.src_id = ICE_SRC_ID_LPORT; if (!set) f_info.fltr_rule_id = hw->port_info->dflt_rx_vsi_rule_id; } else if (f_info.flag & ICE_FLTR_TX) { - f_info.src = vsi_id; + f_info.src_id = ICE_SRC_ID_VSI; + f_info.src = hw_vsi_id; if (!set) f_info.fltr_rule_id = hw->port_info->dflt_tx_vsi_rule_id; @@ -1834,10 +1946,10 @@ ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction) u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index); if (f_info.flag & ICE_FLTR_TX) { - hw->port_info->dflt_tx_vsi_num = vsi_id; + hw->port_info->dflt_tx_vsi_num = hw_vsi_id; hw->port_info->dflt_tx_vsi_rule_id = index; } else if (f_info.flag & ICE_FLTR_RX) { - hw->port_info->dflt_rx_vsi_num = vsi_id; + hw->port_info->dflt_rx_vsi_num = hw_vsi_id; hw->port_info->dflt_rx_vsi_rule_id = index; } } else { @@ -1920,21 +2032,21 @@ ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list) /** * ice_vsi_uses_fltr - Determine if given VSI uses specified filter * @fm_entry: filter entry to inspect - * @vsi_id: ID of VSI to compare with filter info + * @vsi_handle: VSI handle to compare with filter info */ static bool -ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_id) +ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle) { return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI && - fm_entry->fltr_info.fwd_id.vsi_id == vsi_id) || + fm_entry->fltr_info.vsi_handle == vsi_handle) || (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST && - (test_bit(vsi_id, fm_entry->vsi_list_info->vsi_map)))); + (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map)))); } /** * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from * @vsi_list_head: pointer to the list to add entry to * @fi: pointer to fltr_info of filter entry to copy & add * @@ -1945,7 +2057,7 @@ ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_id) * extract which VSI to remove the fltr from, and pass on that information. */ static enum ice_status -ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, +ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, struct list_head *vsi_list_head, struct ice_fltr_info *fi) { @@ -1966,7 +2078,8 @@ ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, * values. */ tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; - tmp->fltr_info.fwd_id.vsi_id = vsi_id; + tmp->fltr_info.vsi_handle = vsi_handle; + tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); list_add(&tmp->list_entry, vsi_list_head); @@ -1976,9 +2089,9 @@ ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, /** * ice_add_to_vsi_fltr_list - Add VSI filters to the list * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from * @lkup_list_head: pointer to the list that has certain lookup type filters - * @vsi_list_head: pointer to the list pertaining to VSI with vsi_id + * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle * * Locates all filters in lkup_list_head that are used by the given VSI, * and adds COPIES of those entries to vsi_list_head (intended to be used @@ -1987,7 +2100,7 @@ ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, * deallocated by the caller when done with list. */ static enum ice_status -ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, +ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, struct list_head *lkup_list_head, struct list_head *vsi_list_head) { @@ -1995,17 +2108,17 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, enum ice_status status = 0; /* check to make sure VSI id is valid and within boundary */ - if (vsi_id >= ICE_MAX_VSI) + if (!ice_is_vsi_valid(hw, vsi_handle)) return ICE_ERR_PARAM; list_for_each_entry(fm_entry, lkup_list_head, list_entry) { struct ice_fltr_info *fi; fi = &fm_entry->fltr_info; - if (!ice_vsi_uses_fltr(fm_entry, vsi_id)) + if (!ice_vsi_uses_fltr(fm_entry, vsi_handle)) continue; - status = ice_add_entry_to_vsi_fltr_list(hw, vsi_id, + status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, vsi_list_head, fi); if (status) return status; @@ -2016,11 +2129,11 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id, /** * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from * @lkup: switch rule filter lookup type */ static void -ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, +ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, enum ice_sw_lkup_type lkup) { struct ice_switch_info *sw = hw->switch_info; @@ -2035,7 +2148,7 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, rule_lock = &sw->recp_list[lkup].filt_rule_lock; rule_head = &sw->recp_list[lkup].filt_rules; mutex_lock(rule_lock); - status = ice_add_to_vsi_fltr_list(hw, vsi_id, rule_head, + status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head, &remove_list_head); mutex_unlock(rule_lock); if (status) @@ -2069,102 +2182,120 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id, /** * ice_remove_vsi_fltr - Remove all filters for a VSI * @hw: pointer to the hardware structure - * @vsi_id: ID of VSI to remove filters from + * @vsi_handle: VSI handle to remove filters from */ -void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id) +void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle) { - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC_VLAN); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_VLAN); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_DFLT); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE_MAC); - ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC_VLAN); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC); + ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN); } /** - * ice_replay_fltr - Replay all the filters stored by a specific list head + * ice_replay_vsi_fltr - Replay filters for requested VSI * @hw: pointer to the hardware structure - * @list_head: list for which filters needs to be replayed + * @vsi_handle: driver VSI handle * @recp_id: Recipe id for which rules need to be replayed + * @list_head: list for which filters need to be replayed + * + * Replays the filter of recipe recp_id for a VSI represented via vsi_handle. + * It is required to pass valid VSI handle. */ static enum ice_status -ice_replay_fltr(struct ice_hw *hw, u8 recp_id, struct list_head *list_head) +ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id, + struct list_head *list_head) { struct ice_fltr_mgmt_list_entry *itr; - struct list_head l_head; enum ice_status status = 0; + u16 hw_vsi_id; if (list_empty(list_head)) return status; + hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); - /* Move entries from the given list_head to a temporary l_head so that - * they can be replayed. Otherwise when trying to re-add the same - * filter, the function will return already exists - */ - list_replace_init(list_head, &l_head); - - /* Mark the given list_head empty by reinitializing it so filters - * could be added again by *handler - */ - list_for_each_entry(itr, &l_head, list_entry) { + list_for_each_entry(itr, list_head, list_entry) { struct ice_fltr_list_entry f_entry; f_entry.fltr_info = itr->fltr_info; - if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN) { + if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN && + itr->fltr_info.vsi_handle == vsi_handle) { + /* update the src in case it is vsi num */ + if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) + f_entry.fltr_info.src = hw_vsi_id; status = ice_add_rule_internal(hw, recp_id, &f_entry); if (status) goto end; continue; } - - /* Add a filter per vsi separately */ - while (1) { - u16 vsi; - - vsi = find_first_bit(itr->vsi_list_info->vsi_map, - ICE_MAX_VSI); - if (vsi == ICE_MAX_VSI) - break; - - clear_bit(vsi, itr->vsi_list_info->vsi_map); - f_entry.fltr_info.fwd_id.vsi_id = vsi; - f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; - if (recp_id == ICE_SW_LKUP_VLAN) - status = ice_add_vlan_internal(hw, &f_entry); - else - status = ice_add_rule_internal(hw, recp_id, - &f_entry); - if (status) - goto end; - } + if (!test_bit(vsi_handle, itr->vsi_list_info->vsi_map)) + continue; + /* Clearing it so that the logic can add it back */ + clear_bit(vsi_handle, itr->vsi_list_info->vsi_map); + f_entry.fltr_info.vsi_handle = vsi_handle; + f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI; + /* update the src in case it is vsi num */ + if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI) + f_entry.fltr_info.src = hw_vsi_id; + if (recp_id == ICE_SW_LKUP_VLAN) + status = ice_add_vlan_internal(hw, &f_entry); + else + status = ice_add_rule_internal(hw, recp_id, &f_entry); + if (status) + goto end; } end: - /* Clear the filter management list */ - ice_rem_sw_rule_info(hw, &l_head); return status; } /** - * ice_replay_all_fltr - replay all filters stored in bookkeeping lists + * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists * @hw: pointer to the hardware structure + * @vsi_handle: driver VSI handle * - * NOTE: This function does not clean up partially added filters on error. - * It is up to caller of the function to issue a reset or fail early. + * Replays filters for requested VSI via vsi_handle. */ -enum ice_status ice_replay_all_fltr(struct ice_hw *hw) +enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle) { struct ice_switch_info *sw = hw->switch_info; enum ice_status status = 0; u8 i; for (i = 0; i < ICE_SW_LKUP_LAST; i++) { - struct list_head *head = &sw->recp_list[i].filt_rules; + struct list_head *head; - status = ice_replay_fltr(hw, i, head); + head = &sw->recp_list[i].filt_replay_rules; + status = ice_replay_vsi_fltr(hw, vsi_handle, i, head); if (status) return status; } return status; } + +/** + * ice_rm_all_sw_replay_rule_info - deletes filter replay rules + * @hw: pointer to the hw struct + * + * Deletes the filter replay rules. + */ +void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw) +{ + struct ice_switch_info *sw = hw->switch_info; + u8 i; + + if (!sw) + return; + + for (i = 0; i < ICE_SW_LKUP_LAST; i++) { + if (!list_empty(&sw->recp_list[i].filt_replay_rules)) { + struct list_head *l_head; + + l_head = &sw->recp_list[i].filt_replay_rules; + ice_rem_sw_rule_info(hw, l_head); + } + } +} diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index e12940e70000..7706e9b6003c 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -17,6 +17,7 @@ struct ice_vsi_ctx { u16 vsis_unallocated; u16 flags; struct ice_aqc_vsi_props info; + struct ice_sched_vsi_info sched; u8 alloc_from_pool; }; @@ -42,6 +43,14 @@ enum ice_sw_lkup_type { ICE_SW_LKUP_LAST }; +/* type of filter src id */ +enum ice_src_id { + ICE_SRC_ID_UNKNOWN = 0, + ICE_SRC_ID_VSI, + ICE_SRC_ID_QUEUE, + ICE_SRC_ID_LPORT, +}; + struct ice_fltr_info { /* Look up information: how to look up packet */ enum ice_sw_lkup_type lkup_type; @@ -56,6 +65,7 @@ struct ice_fltr_info { /* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */ u16 src; + enum ice_src_id src_id; union { struct { @@ -77,7 +87,10 @@ struct ice_fltr_info { u16 ethertype; u8 mac_addr[ETH_ALEN]; /* optional */ } ethertype_mac; - } l_data; + } l_data; /* Make sure to zero out the memory of l_data before using + * it or only set the data associated with lookup match + * rest everything should be zero + */ /* Depending on filter action */ union { @@ -85,12 +98,16 @@ struct ice_fltr_info { * queue id in case of ICE_FWD_TO_QGRP. */ u16 q_id:11; - u16 vsi_id:10; + u16 hw_vsi_id:10; u16 vsi_list_id:10; } fwd_id; + /* Sw VSI handle */ + u16 vsi_handle; + /* Set to num_queues if action is ICE_FWD_TO_QGRP. This field - * determines the range of queues the packet needs to be forwarded to + * determines the range of queues the packet needs to be forwarded to. + * Note that qgrp_size must be set to a power of 2. */ u8 qgrp_size; @@ -109,6 +126,7 @@ struct ice_sw_recipe { /* List of type ice_fltr_mgmt_list_entry */ struct list_head filt_rules; + struct list_head filt_replay_rules; /* linked list of type recipe_list_entry */ struct list_head rg_list; @@ -129,6 +147,8 @@ struct ice_vsi_list_map_info { struct list_head list_entry; DECLARE_BITMAP(vsi_map, ICE_MAX_VSI); u16 vsi_list_id; + /* counter to track how many rules are reusing this VSI list */ + u16 ref_cnt; }; struct ice_fltr_list_entry { @@ -159,28 +179,33 @@ struct ice_fltr_mgmt_list_entry { /* VSI related commands */ enum ice_status -ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, - struct ice_sq_cd *cd); -enum ice_status ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, struct ice_sq_cd *cd); enum ice_status ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, bool keep_vsi_alloc, struct ice_sq_cd *cd); +enum ice_status +ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, + struct ice_sq_cd *cd); +bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle); +struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle); enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); /* Switch/bridge related commands */ enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw); enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst); enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst); -void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id); +void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle); enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list); enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list); enum ice_status -ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction); - -enum ice_status ice_replay_all_fltr(struct ice_hw *hw); +ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction); enum ice_status ice_init_def_sw_recp(struct ice_hw *hw); +u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle); +bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle); + +enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle); +void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw); #endif /* _ICE_SWITCH_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 839fd9ff6043..a9b92974e041 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -104,10 +104,16 @@ enum ice_rx_dtype { #define ICE_RX_ITR ICE_IDX_ITR0 #define ICE_TX_ITR ICE_IDX_ITR1 #define ICE_ITR_DYNAMIC 0x8000 /* use top bit as a flag */ -#define ICE_ITR_8K 0x003E +#define ICE_ITR_8K 125 +#define ICE_DFLT_TX_ITR ICE_ITR_8K +#define ICE_DFLT_RX_ITR ICE_ITR_8K +/* apply ITR granularity translation to program the register. itr_gran is either + * 2 or 4 usecs so we need to divide by 2 first then shift by that value + */ +#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> \ + ((itr_gran) / 2)) -/* apply ITR HW granularity translation to program the HW registers */ -#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> (itr_gran)) +#define ICE_DFLT_INTRL 0 /* Legacy or Advanced Mode Queue */ #define ICE_TX_ADVANCED 0 @@ -130,12 +136,11 @@ struct ice_ring { u32 txq_teid; /* Added Tx queue TEID */ /* high bit set means dynamic, use accessor routines to read/write. - * hardware supports 2us/1us resolution for the ITR registers. + * hardware supports 4us/2us resolution for the ITR registers. * these values always store the USER setting, and must be converted * before programming to a register. */ - u16 rx_itr_setting; - u16 tx_itr_setting; + u16 itr_setting; u16 count; /* Number of descriptors */ u16 reg_idx; /* HW register index of the ring */ diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index e681804be4d4..f5c8de0ed0eb 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -18,6 +18,9 @@ static inline bool ice_is_tc_ena(u8 bitmap, u8 tc) return test_bit(tc, (unsigned long *)&bitmap); } +/* Driver always calls main vsi_handle first */ +#define ICE_MAIN_VSI_HANDLE 0 + /* debug masks - set these bits in hw->debug_mask to control output */ #define ICE_DBG_INIT BIT_ULL(1) #define ICE_DBG_LINK BIT_ULL(4) @@ -147,12 +150,18 @@ struct ice_mac_info { u8 perm_addr[ETH_ALEN]; }; -/* Various RESET request, These are not tied with HW reset types */ +/* Reset types used to determine which kind of reset was requested. These + * defines match what the RESET_TYPE field of the GLGEN_RSTAT register. + * ICE_RESET_PFR does not match any RESET_TYPE field in the GLGEN_RSTAT register + * because its reset source is different than the other types listed. + */ enum ice_reset_req { + ICE_RESET_POR = 0, ICE_RESET_INVAL = 0, - ICE_RESET_PFR = 1, - ICE_RESET_CORER = 2, - ICE_RESET_GLOBR = 3, + ICE_RESET_CORER = 1, + ICE_RESET_GLOBR = 2, + ICE_RESET_EMPR = 3, + ICE_RESET_PFR = 4, }; /* Bus parameters */ @@ -186,7 +195,7 @@ struct ice_sched_node { struct ice_sched_node **children; struct ice_aqc_txsched_elem_data info; u32 agg_id; /* aggregator group id */ - u16 vsi_id; + u16 vsi_handle; u8 in_use; /* suspended or in use */ u8 tx_sched_layer; /* Logical Layer (1-9) */ u8 num_children; @@ -245,8 +254,6 @@ struct ice_port_info { struct ice_mac_info mac; struct ice_phy_info phy; struct mutex sched_lock; /* protect access to TXSched tree */ - struct ice_sched_tx_policy sched_policy; - struct list_head vsi_info_list; struct list_head agg_list; /* lists all aggregator */ u8 lport; #define ICE_LPORT_MASK 0xff @@ -326,16 +333,26 @@ struct ice_hw { u32 fw_build; /* firmware build number */ struct ice_fw_log_cfg fw_log; - /* minimum allowed value for different speeds */ -#define ICE_ITR_GRAN_MIN_200 1 -#define ICE_ITR_GRAN_MIN_100 1 -#define ICE_ITR_GRAN_MIN_50 2 -#define ICE_ITR_GRAN_MIN_25 4 + +/* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL + * register. Used for determining the itr/intrl granularity during + * initialization. + */ +#define ICE_MAX_AGG_BW_200G 0x0 +#define ICE_MAX_AGG_BW_100G 0X1 +#define ICE_MAX_AGG_BW_50G 0x2 +#define ICE_MAX_AGG_BW_25G 0x3 + /* ITR granularity for different speeds */ +#define ICE_ITR_GRAN_ABOVE_25 2 +#define ICE_ITR_GRAN_MAX_25 4 /* ITR granularity in 1 us */ - u8 itr_gran_200; - u8 itr_gran_100; - u8 itr_gran_50; - u8 itr_gran_25; + u8 itr_gran; + /* INTRL granularity for different speeds */ +#define ICE_INTRL_GRAN_ABOVE_25 4 +#define ICE_INTRL_GRAN_MAX_25 8 + /* INTRL granularity in 1 us */ + u8 intrl_gran; + u8 ucast_shared; /* true if VSIs can share unicast addr */ };