Commit d5486377 authored by David S. Miller's avatar David S. Miller

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue

Jeff Kirsher says:

====================
100GbE Intel Wired LAN Driver Updates 2018-10-02

This series contains updates to ice driver only.

Anirudh expands the use of VSI handles across the rest of the driver,
which includes refactoring the code to correctly use VSI handles.  After
a reset, ensure that all configurations for a VSI get re-applied before
moving on to rebuilding the next VSI.

Dave fixed the driver to check the current link state after reset to
ensure that the correct link state of a port is reported.  Fixed an
issue where if the driver is unloaded when traffic is in progress,
errors are generated.

Preethi breaks up the IRQ tracker into a software and hardware IRQ
tracker, where the software IRQ tracker tracks only the PF's IRQ
requests and does not play any role in the VF initialization.  The
hardware IRQ tracker represents the device's interrupt space and will be
looked up to see if the device has run our of interrupts when a
interrupt has to be allocated in the device for either PF or VF.

Md Fahad adds support for enabling/disabling RSS via ethtool.

Brett aligns the ice_reset_req enum values to the values that the
hardware understands.  Also added initial support for dynamic interrupt
moderation in the ice driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents dd0bb7f9 81b23589
......@@ -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;
......
......@@ -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
......
......@@ -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);
......
......@@ -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))
......
......@@ -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");
......
......@@ -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_ */
......@@ -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,30 +1921,31 @@ 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;
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);
/* 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);
if (pf->irq_tracker) {
devm_kfree(&pf->pdev->dev, pf->irq_tracker);
pf->irq_tracker = NULL;
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;
}
/**
......@@ -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,
......
......@@ -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;
......
......@@ -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_ */
......@@ -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);
/* A rule already exists with the new VSI being added */
if (cur_handle == vsi_handle) {
status = ICE_ERR_ALREADY_EXISTS;
goto exit;
}
cur_fltr = &v_list_itr->fltr_info;
status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr, new_fltr);
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);
}
}
}
......@@ -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_ */
......@@ -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 */
......
......@@ -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 */
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment