Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9daf8208 authored by Anirudh Venkataramanan's avatar Anirudh Venkataramanan Committed by Jeff Kirsher
Browse files

ice: Add support for switch filter programming



A VSI needs traffic directed towards it. This is done by programming
filter rules on the switch (embedded vSwitch) element in the hardware,
which connects the VSI to the ingress/egress port.

This patch introduces data structures and functions necessary to add
remove or update switch rules on the switch element. This is a pretty low
level function that is generic enough to add a whole range of filters.

This patch also introduces two top level functions ice_add_mac and
ice_remove mac which through a series of intermediate helper functions
eventually call ice_aq_sw_rules to add/delete simple MAC based filters.
It's worth noting that one invocation of ice_add_mac/ice_remove_mac
is capable of adding/deleting multiple MAC filters.

Also worth noting is the fact that the driver maintains a list of currently
active filters, so every filter addition/removal causes an update to this
list. This is done for a couple of reasons:

1) If two VSIs try to add the same filters, we need to detect it and do
   things a little differently (i.e. use VSI lists, described below) as
   the same filter can't be added more than once.

2) In the event of a hardware reset we can simply walk through this list
   and restore the filters.

VSI Lists:
In a multi-VSI situation, it's possible that multiple VSIs want to add the
same filter rule. For example, two VSIs that want to receive broadcast
traffic would both add a filter for destination MAC ff:ff:ff:ff:ff:ff.
This can become cumbersome to maintain and so this is handled using a
VSI list.

A VSI list is resource that can be allocated in the hardware using the
ice_aq_alloc_free_res admin queue command. Simply put, a VSI list can
be thought of as a subscription list containing a set of VSIs to which
the packet should be forwarded, should the filter match.

For example, if VSI-0 has already added a broadcast filter, and VSI-1
wants to do the same thing, the filter creation flow will detect this,
allocate a VSI list and update the switch rule so that broadcast traffic
will now be forwarded to the VSI list which contains VSI-0 and VSI-1.

Signed-off-by: default avatarAnirudh Venkataramanan <anirudh.venkataramanan@intel.com>
Tested-by: default avatarTony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 3a858ba3
Loading
Loading
Loading
Loading
+249 −0
Original line number Original line Diff line number Diff line
@@ -8,6 +8,7 @@
 * descriptor format.  It is shared between Firmware and Software.
 * descriptor format.  It is shared between Firmware and Software.
 */
 */


#define ICE_MAX_VSI			768
#define ICE_AQC_TOPO_MAX_LEVEL_NUM	0x9
#define ICE_AQC_TOPO_MAX_LEVEL_NUM	0x9
#define ICE_AQ_SET_MAC_FRAME_SIZE_MAX	9728
#define ICE_AQ_SET_MAC_FRAME_SIZE_MAX	9728


@@ -191,6 +192,46 @@ struct ice_aqc_get_sw_cfg_resp {
	struct ice_aqc_get_sw_cfg_resp_elem elements[1];
	struct ice_aqc_get_sw_cfg_resp_elem elements[1];
};
};


/* These resource type defines are used for all switch resource
 * commands where a resource type is required, such as:
 * Get Resource Allocation command (indirect 0x0204)
 * Allocate Resources command (indirect 0x0208)
 * Free Resources command (indirect 0x0209)
 * Get Allocated Resource Descriptors Command (indirect 0x020A)
 */
#define ICE_AQC_RES_TYPE_VSI_LIST_REP			0x03
#define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE			0x04

/* Allocate Resources command (indirect 0x0208)
 * Free Resources command (indirect 0x0209)
 */
struct ice_aqc_alloc_free_res_cmd {
	__le16 num_entries; /* Number of Resource entries */
	u8 reserved[6];
	__le32 addr_high;
	__le32 addr_low;
};

/* Resource descriptor */
struct ice_aqc_res_elem {
	union {
		__le16 sw_resp;
		__le16 flu_resp;
	} e;
};

/* Buffer for Allocate/Free Resources commands */
struct ice_aqc_alloc_free_res_elem {
	__le16 res_type; /* Types defined above cmd 0x0204 */
#define ICE_AQC_RES_TYPE_SHARED_S	7
#define ICE_AQC_RES_TYPE_SHARED_M	(0x1 << ICE_AQC_RES_TYPE_SHARED_S)
#define ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_S	8
#define ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_M	\
				(0xF << ICE_AQC_RES_TYPE_VSI_PRUNE_LIST_S)
	__le16 num_elems;
	struct ice_aqc_res_elem elem[1];
};

/* Add VSI (indirect 0x0210)
/* Add VSI (indirect 0x0210)
 * Update VSI (indirect 0x0211)
 * Update VSI (indirect 0x0211)
 * Get VSI (indirect 0x0212)
 * Get VSI (indirect 0x0212)
@@ -384,6 +425,202 @@ struct ice_aqc_vsi_props {
	u8 reserved[24];
	u8 reserved[24];
};
};


/* Add/Update/Remove/Get switch rules (indirect 0x02A0, 0x02A1, 0x02A2, 0x02A3)
 */
struct ice_aqc_sw_rules {
	/* ops: add switch rules, referring the number of rules.
	 * ops: update switch rules, referring the number of filters
	 * ops: remove switch rules, referring the entry index.
	 * ops: get switch rules, referring to the number of filters.
	 */
	__le16 num_rules_fltr_entry_index;
	u8 reserved[6];
	__le32 addr_high;
	__le32 addr_low;
};

/* Add/Update/Get/Remove lookup Rx/Tx command/response entry
 * This structures describes the lookup rules and associated actions.  "index"
 * is returned as part of a response to a successful Add command, and can be
 * used to identify the rule for Update/Get/Remove commands.
 */
struct ice_sw_rule_lkup_rx_tx {
	__le16 recipe_id;
#define ICE_SW_RECIPE_LOGICAL_PORT_FWD		10
	/* Source port for LOOKUP_RX and source VSI in case of LOOKUP_TX */
	__le16 src;
	__le32 act;

	/* Bit 0:1 - Action type */
#define ICE_SINGLE_ACT_TYPE_S	0x00
#define ICE_SINGLE_ACT_TYPE_M	(0x3 << ICE_SINGLE_ACT_TYPE_S)

	/* Bit 2 - Loop back enable
	 * Bit 3 - LAN enable
	 */
#define ICE_SINGLE_ACT_LB_ENABLE	BIT(2)
#define ICE_SINGLE_ACT_LAN_ENABLE	BIT(3)

	/* Action type = 0 - Forward to VSI or VSI list */
#define ICE_SINGLE_ACT_VSI_FORWARDING	0x0

#define ICE_SINGLE_ACT_VSI_ID_S		4
#define ICE_SINGLE_ACT_VSI_ID_M		(0x3FF << ICE_SINGLE_ACT_VSI_ID_S)
#define ICE_SINGLE_ACT_VSI_LIST_ID_S	4
#define ICE_SINGLE_ACT_VSI_LIST_ID_M	(0x3FF << ICE_SINGLE_ACT_VSI_LIST_ID_S)
	/* This bit needs to be set if action is forward to VSI list */
#define ICE_SINGLE_ACT_VSI_LIST		BIT(14)
#define ICE_SINGLE_ACT_VALID_BIT	BIT(17)
#define ICE_SINGLE_ACT_DROP		BIT(18)

	/* Action type = 1 - Forward to Queue of Queue group */
#define ICE_SINGLE_ACT_TO_Q		0x1
#define ICE_SINGLE_ACT_Q_INDEX_S	4
#define ICE_SINGLE_ACT_Q_INDEX_M	(0x7FF << ICE_SINGLE_ACT_Q_INDEX_S)
#define ICE_SINGLE_ACT_Q_REGION_S	15
#define ICE_SINGLE_ACT_Q_REGION_M	(0x7 << ICE_SINGLE_ACT_Q_REGION_S)
#define ICE_SINGLE_ACT_Q_PRIORITY	BIT(18)

	/* Action type = 2 - Prune */
#define ICE_SINGLE_ACT_PRUNE		0x2
#define ICE_SINGLE_ACT_EGRESS		BIT(15)
#define ICE_SINGLE_ACT_INGRESS		BIT(16)
#define ICE_SINGLE_ACT_PRUNET		BIT(17)
	/* Bit 18 should be set to 0 for this action */

	/* Action type = 2 - Pointer */
#define ICE_SINGLE_ACT_PTR		0x2
#define ICE_SINGLE_ACT_PTR_VAL_S	4
#define ICE_SINGLE_ACT_PTR_VAL_M	(0x1FFF << ICE_SINGLE_ACT_PTR_VAL_S)
	/* Bit 18 should be set to 1 */
#define ICE_SINGLE_ACT_PTR_BIT		BIT(18)

	/* Action type = 3 - Other actions. Last two bits
	 * are other action identifier
	 */
#define ICE_SINGLE_ACT_OTHER_ACTS		0x3
#define ICE_SINGLE_OTHER_ACT_IDENTIFIER_S	17
#define ICE_SINGLE_OTHER_ACT_IDENTIFIER_M	\
				(0x3 << \ ICE_SINGLE_OTHER_ACT_IDENTIFIER_S)

	/* Bit 17:18 - Defines other actions */
	/* Other action = 0 - Mirror VSI */
#define ICE_SINGLE_OTHER_ACT_MIRROR		0
#define ICE_SINGLE_ACT_MIRROR_VSI_ID_S	4
#define ICE_SINGLE_ACT_MIRROR_VSI_ID_M	\
				(0x3FF << ICE_SINGLE_ACT_MIRROR_VSI_ID_S)

	/* Other action = 3 - Set Stat count */
#define ICE_SINGLE_OTHER_ACT_STAT_COUNT		3
#define ICE_SINGLE_ACT_STAT_COUNT_INDEX_S	4
#define ICE_SINGLE_ACT_STAT_COUNT_INDEX_M	\
				(0x7F << ICE_SINGLE_ACT_STAT_COUNT_INDEX_S)

	__le16 index; /* The index of the rule in the lookup table */
	/* Length and values of the header to be matched per recipe or
	 * lookup-type
	 */
	__le16 hdr_len;
	u8 hdr[1];
} __packed;

/* Add/Update/Remove large action command/response entry
 * "index" is returned as part of a response to a successful Add command, and
 * can be used to identify the action for Update/Get/Remove commands.
 */
struct ice_sw_rule_lg_act {
	__le16 index; /* Index in large action table */
	__le16 size;
	__le32 act[1]; /* array of size for actions */
	/* Max number of large actions */
#define ICE_MAX_LG_ACT	4
	/* Bit 0:1 - Action type */
#define ICE_LG_ACT_TYPE_S	0
#define ICE_LG_ACT_TYPE_M	(0x7 << ICE_LG_ACT_TYPE_S)

	/* Action type = 0 - Forward to VSI or VSI list */
#define ICE_LG_ACT_VSI_FORWARDING	0
#define ICE_LG_ACT_VSI_ID_S		3
#define ICE_LG_ACT_VSI_ID_M		(0x3FF << ICE_LG_ACT_VSI_ID_S)
#define ICE_LG_ACT_VSI_LIST_ID_S	3
#define ICE_LG_ACT_VSI_LIST_ID_M	(0x3FF << ICE_LG_ACT_VSI_LIST_ID_S)
	/* This bit needs to be set if action is forward to VSI list */
#define ICE_LG_ACT_VSI_LIST		BIT(13)

#define ICE_LG_ACT_VALID_BIT		BIT(16)

	/* Action type = 1 - Forward to Queue of Queue group */
#define ICE_LG_ACT_TO_Q			0x1
#define ICE_LG_ACT_Q_INDEX_S		3
#define ICE_LG_ACT_Q_INDEX_M		(0x7FF << ICE_LG_ACT_Q_INDEX_S)
#define ICE_LG_ACT_Q_REGION_S		14
#define ICE_LG_ACT_Q_REGION_M		(0x7 << ICE_LG_ACT_Q_REGION_S)
#define ICE_LG_ACT_Q_PRIORITY_SET	BIT(17)

	/* Action type = 2 - Prune */
#define ICE_LG_ACT_PRUNE		0x2
#define ICE_LG_ACT_EGRESS		BIT(14)
#define ICE_LG_ACT_INGRESS		BIT(15)
#define ICE_LG_ACT_PRUNET		BIT(16)

	/* Action type = 3 - Mirror VSI */
#define ICE_LG_OTHER_ACT_MIRROR		0x3
#define ICE_LG_ACT_MIRROR_VSI_ID_S	3
#define ICE_LG_ACT_MIRROR_VSI_ID_M	(0x3FF << ICE_LG_ACT_MIRROR_VSI_ID_S)

	/* Action type = 5 - Large Action */
#define ICE_LG_ACT_GENERIC		0x5
#define ICE_LG_ACT_GENERIC_VALUE_S	3
#define ICE_LG_ACT_GENERIC_VALUE_M	(0xFFFF << ICE_LG_ACT_GENERIC_VALUE_S)
#define ICE_LG_ACT_GENERIC_OFFSET_S	19
#define ICE_LG_ACT_GENERIC_OFFSET_M	(0x7 << ICE_LG_ACT_GENERIC_OFFSET_S)
#define ICE_LG_ACT_GENERIC_PRIORITY_S	22
#define ICE_LG_ACT_GENERIC_PRIORITY_M	(0x7 << ICE_LG_ACT_GENERIC_PRIORITY_S)

	/* Action = 7 - Set Stat count */
#define ICE_LG_ACT_STAT_COUNT		0x7
#define ICE_LG_ACT_STAT_COUNT_S		3
#define ICE_LG_ACT_STAT_COUNT_M		(0x7F << ICE_LG_ACT_STAT_COUNT_S)
};

/* Add/Update/Remove VSI list command/response entry
 * "index" is returned as part of a response to a successful Add command, and
 * can be used to identify the VSI list for Update/Get/Remove commands.
 */
struct ice_sw_rule_vsi_list {
	__le16 index; /* Index of VSI/Prune list */
	__le16 number_vsi;
	__le16 vsi[1]; /* Array of number_vsi VSI numbers */
};

/* Query VSI list command/response entry */
struct ice_sw_rule_vsi_list_query {
	__le16 index;
	DECLARE_BITMAP(vsi_list, ICE_MAX_VSI);
} __packed;

/* Add switch rule response:
 * Content of return buffer is same as the input buffer. The status field and
 * LUT index are updated as part of the response
 */
struct ice_aqc_sw_rules_elem {
	__le16 type; /* Switch rule type, one of T_... */
#define ICE_AQC_SW_RULES_T_LKUP_RX		0x0
#define ICE_AQC_SW_RULES_T_LKUP_TX		0x1
#define ICE_AQC_SW_RULES_T_LG_ACT		0x2
#define ICE_AQC_SW_RULES_T_VSI_LIST_SET		0x3
#define ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR	0x4
#define ICE_AQC_SW_RULES_T_PRUNE_LIST_SET	0x5
#define ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR	0x6
	__le16 status;
	union {
		struct ice_sw_rule_lkup_rx_tx lkup_tx_rx;
		struct ice_sw_rule_lg_act lg_act;
		struct ice_sw_rule_vsi_list vsi_list;
		struct ice_sw_rule_vsi_list_query vsi_list_query;
	} __packed pdata;
};

/* Get Default Topology (indirect 0x0400) */
/* Get Default Topology (indirect 0x0400) */
struct ice_aqc_get_topo {
struct ice_aqc_get_topo {
	u8 port_num;
	u8 port_num;
@@ -766,11 +1003,13 @@ struct ice_aq_desc {
		struct ice_aqc_list_caps get_cap;
		struct ice_aqc_list_caps get_cap;
		struct ice_aqc_get_phy_caps get_phy;
		struct ice_aqc_get_phy_caps get_phy;
		struct ice_aqc_get_sw_cfg get_sw_conf;
		struct ice_aqc_get_sw_cfg get_sw_conf;
		struct ice_aqc_sw_rules sw_rules;
		struct ice_aqc_get_topo get_topo;
		struct ice_aqc_get_topo get_topo;
		struct ice_aqc_query_txsched_res query_sched_res;
		struct ice_aqc_query_txsched_res query_sched_res;
		struct ice_aqc_add_move_delete_elem add_move_delete_elem;
		struct ice_aqc_add_move_delete_elem add_move_delete_elem;
		struct ice_aqc_nvm nvm;
		struct ice_aqc_nvm nvm;
		struct ice_aqc_add_get_update_free_vsi vsi_cmd;
		struct ice_aqc_add_get_update_free_vsi vsi_cmd;
		struct ice_aqc_alloc_free_res_cmd sw_res_ctrl;
		struct ice_aqc_get_link_status get_link_status;
		struct ice_aqc_get_link_status get_link_status;
	} params;
	} params;
};
};
@@ -821,10 +1060,20 @@ enum ice_adminq_opc {
	/* internal switch commands */
	/* internal switch commands */
	ice_aqc_opc_get_sw_cfg				= 0x0200,
	ice_aqc_opc_get_sw_cfg				= 0x0200,


	/* Alloc/Free/Get Resources */
	ice_aqc_opc_alloc_res				= 0x0208,
	ice_aqc_opc_free_res				= 0x0209,

	/* VSI commands */
	/* VSI commands */
	ice_aqc_opc_add_vsi				= 0x0210,
	ice_aqc_opc_add_vsi				= 0x0210,
	ice_aqc_opc_update_vsi				= 0x0211,
	ice_aqc_opc_update_vsi				= 0x0211,
	ice_aqc_opc_free_vsi				= 0x0213,
	ice_aqc_opc_free_vsi				= 0x0213,

	/* switch rules population commands */
	ice_aqc_opc_add_sw_rules			= 0x02A0,
	ice_aqc_opc_update_sw_rules			= 0x02A1,
	ice_aqc_opc_remove_sw_rules			= 0x02A2,

	ice_aqc_opc_clear_pf_cfg			= 0x02A4,
	ice_aqc_opc_clear_pf_cfg			= 0x02A4,


	/* transmit scheduler commands */
	/* transmit scheduler commands */
+72 −2
Original line number Original line Diff line number Diff line
@@ -258,6 +258,66 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
	return status;
	return status;
}
}


/**
 * ice_init_fltr_mgmt_struct - initializes filter management list and locks
 * @hw: pointer to the hw struct
 */
static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw)
{
	struct ice_switch_info *sw;

	hw->switch_info = devm_kzalloc(ice_hw_to_dev(hw),
				       sizeof(*hw->switch_info), GFP_KERNEL);
	sw = hw->switch_info;

	if (!sw)
		return ICE_ERR_NO_MEMORY;

	INIT_LIST_HEAD(&sw->vsi_list_map_head);

	mutex_init(&sw->mac_list_lock);
	INIT_LIST_HEAD(&sw->mac_list_head);

	mutex_init(&sw->vlan_list_lock);
	INIT_LIST_HEAD(&sw->vlan_list_head);

	mutex_init(&sw->eth_m_list_lock);
	INIT_LIST_HEAD(&sw->eth_m_list_head);

	mutex_init(&sw->promisc_list_lock);
	INIT_LIST_HEAD(&sw->promisc_list_head);

	mutex_init(&sw->mac_vlan_list_lock);
	INIT_LIST_HEAD(&sw->mac_vlan_list_head);

	return 0;
}

/**
 * ice_cleanup_fltr_mgmt_struct - cleanup filter management list and locks
 * @hw: pointer to the hw struct
 */
static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
{
	struct ice_switch_info *sw = hw->switch_info;
	struct ice_vsi_list_map_info *v_pos_map;
	struct ice_vsi_list_map_info *v_tmp_map;

	list_for_each_entry_safe(v_pos_map, v_tmp_map, &sw->vsi_list_map_head,
				 list_entry) {
		list_del(&v_pos_map->list_entry);
		devm_kfree(ice_hw_to_dev(hw), v_pos_map);
	}

	mutex_destroy(&sw->mac_list_lock);
	mutex_destroy(&sw->vlan_list_lock);
	mutex_destroy(&sw->eth_m_list_lock);
	mutex_destroy(&sw->promisc_list_lock);
	mutex_destroy(&sw->mac_vlan_list_lock);

	devm_kfree(ice_hw_to_dev(hw), sw);
}

/**
/**
 * ice_init_hw - main hardware initialization routine
 * ice_init_hw - main hardware initialization routine
 * @hw: pointer to the hardware structure
 * @hw: pointer to the hardware structure
@@ -321,6 +381,8 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
	if (status)
	if (status)
		goto err_unroll_alloc;
		goto err_unroll_alloc;


	hw->evb_veb = true;

	/* Query the allocated resources for tx scheduler */
	/* Query the allocated resources for tx scheduler */
	status = ice_sched_query_res_alloc(hw);
	status = ice_sched_query_res_alloc(hw);
	if (status) {
	if (status) {
@@ -352,21 +414,27 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
	if (status)
	if (status)
		goto err_unroll_sched;
		goto err_unroll_sched;


	status = ice_init_fltr_mgmt_struct(hw);
	if (status)
		goto err_unroll_sched;

	/* Get port MAC information */
	/* Get port MAC information */
	mac_buf_len = sizeof(struct ice_aqc_manage_mac_read_resp);
	mac_buf_len = sizeof(struct ice_aqc_manage_mac_read_resp);
	mac_buf = devm_kzalloc(ice_hw_to_dev(hw), mac_buf_len, GFP_KERNEL);
	mac_buf = devm_kzalloc(ice_hw_to_dev(hw), mac_buf_len, GFP_KERNEL);


	if (!mac_buf)
	if (!mac_buf)
		goto err_unroll_sched;
		goto err_unroll_fltr_mgmt_struct;


	status = ice_aq_manage_mac_read(hw, mac_buf, mac_buf_len, NULL);
	status = ice_aq_manage_mac_read(hw, mac_buf, mac_buf_len, NULL);
	devm_kfree(ice_hw_to_dev(hw), mac_buf);
	devm_kfree(ice_hw_to_dev(hw), mac_buf);


	if (status)
	if (status)
		goto err_unroll_sched;
		goto err_unroll_fltr_mgmt_struct;


	return 0;
	return 0;


err_unroll_fltr_mgmt_struct:
	ice_cleanup_fltr_mgmt_struct(hw);
err_unroll_sched:
err_unroll_sched:
	ice_sched_cleanup_all(hw);
	ice_sched_cleanup_all(hw);
err_unroll_alloc:
err_unroll_alloc:
@@ -389,6 +457,8 @@ void ice_deinit_hw(struct ice_hw *hw)
		devm_kfree(ice_hw_to_dev(hw), hw->port_info);
		devm_kfree(ice_hw_to_dev(hw), hw->port_info);
		hw->port_info = NULL;
		hw->port_info = NULL;
	}
	}

	ice_cleanup_fltr_mgmt_struct(hw);
}
}


/**
/**
+92 −0
Original line number Original line Diff line number Diff line
@@ -162,6 +162,57 @@ static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id)
	return count;
	return count;
}
}


/**
 * ice_add_mac_to_list - Add a mac address filter entry to the list
 * @vsi: the VSI to be forwarded to
 * @add_list: pointer to the list which contains MAC filter entries
 * @macaddr: the MAC address to be added.
 *
 * Adds mac address filter entry to the temp list
 *
 * Returns 0 on success or ENOMEM on failure.
 */
static int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list,
			       const u8 *macaddr)
{
	struct ice_fltr_list_entry *tmp;
	struct ice_pf *pf = vsi->back;

	tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC);
	if (!tmp)
		return -ENOMEM;

	tmp->fltr_info.flag = ICE_FLTR_TX;
	tmp->fltr_info.src = vsi->vsi_num;
	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;
	ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr);

	INIT_LIST_HEAD(&tmp->list_entry);
	list_add(&tmp->list_entry, add_list);

	return 0;
}

/**
 * ice_free_fltr_list - free filter lists helper
 * @dev: pointer to the device struct
 * @h: pointer to the list head to be freed
 *
 * Helper function to free filter lists previously created using
 * ice_add_mac_to_list
 */
static void ice_free_fltr_list(struct device *dev, struct list_head *h)
{
	struct ice_fltr_list_entry *e, *tmp;

	list_for_each_entry_safe(e, tmp, h, list_entry) {
		list_del(&e->list_entry);
		devm_kfree(dev, e);
	}
}

/**
/**
 * __ice_clean_ctrlq - helper function to clean controlq rings
 * __ice_clean_ctrlq - helper function to clean controlq rings
 * @pf: ptr to struct ice_pf
 * @pf: ptr to struct ice_pf
@@ -1519,6 +1570,8 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,
 */
 */
static int ice_setup_pf_sw(struct ice_pf *pf)
static int ice_setup_pf_sw(struct ice_pf *pf)
{
{
	LIST_HEAD(tmp_add_list);
	u8 broadcast[ETH_ALEN];
	struct ice_vsi *vsi;
	struct ice_vsi *vsi;
	int status = 0;
	int status = 0;


@@ -1528,7 +1581,37 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
		goto error_exit;
		goto error_exit;
	}
	}


	/* tmp_add_list contains a list of MAC addresses for which MAC
	 * filters need to be programmed. Add the VSI's unicast MAC to
	 * this list
	 */
	status = ice_add_mac_to_list(vsi, &tmp_add_list,
				     vsi->port_info->mac.perm_addr);
	if (status)
		goto error_exit;

	/* VSI needs to receive broadcast traffic, so add the broadcast
	 * MAC address to the list.
	 */
	eth_broadcast_addr(broadcast);
	status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);
	if (status)
		goto error_exit;

	/* program MAC filters for entries in tmp_add_list */
	status = ice_add_mac(&pf->hw, &tmp_add_list);
	if (status) {
		dev_err(&pf->pdev->dev, "Could not add MAC filters\n");
		status = -ENOMEM;
		goto error_exit;
	}

	ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
	return status;

error_exit:
error_exit:
	ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);

	if (vsi) {
	if (vsi) {
		ice_vsi_free_q_vectors(vsi);
		ice_vsi_free_q_vectors(vsi);
		if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED)
		if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED)
@@ -1537,6 +1620,7 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
			free_netdev(vsi->netdev);
			free_netdev(vsi->netdev);
			vsi->netdev = NULL;
			vsi->netdev = NULL;
		}
		}

		ice_vsi_delete(vsi);
		ice_vsi_delete(vsi);
		ice_vsi_put_qs(vsi);
		ice_vsi_put_qs(vsi);
		pf->q_left_tx += vsi->alloc_txq;
		pf->q_left_tx += vsi->alloc_txq;
@@ -1869,6 +1953,13 @@ static int ice_probe(struct pci_dev *pdev,
			"probe failed due to setup pf switch:%d\n", err);
			"probe failed due to setup pf switch:%d\n", err);
		goto err_alloc_sw_unroll;
		goto err_alloc_sw_unroll;
	}
	}

	/* Driver is mostly up */
	clear_bit(__ICE_DOWN, pf->state);

	/* since everything is good, start the service timer */
	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));

	return 0;
	return 0;


err_alloc_sw_unroll:
err_alloc_sw_unroll:
@@ -2012,6 +2103,7 @@ static int ice_vsi_release(struct ice_vsi *vsi)
	ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx);
	ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx);
	pf->num_avail_msix += vsi->num_q_vectors;
	pf->num_avail_msix += vsi->num_q_vectors;


	ice_remove_vsi_fltr(&pf->hw, vsi->vsi_num);
	ice_vsi_delete(vsi);
	ice_vsi_delete(vsi);
	ice_vsi_free_q_vectors(vsi);
	ice_vsi_free_q_vectors(vsi);
	ice_vsi_clear_rings(vsi);
	ice_vsi_clear_rings(vsi);
+3 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
/* Error Codes */
/* Error Codes */
enum ice_status {
enum ice_status {
	ICE_ERR_PARAM				= -1,
	ICE_ERR_PARAM				= -1,
	ICE_ERR_NOT_IMPL			= -2,
	ICE_ERR_NOT_READY			= -3,
	ICE_ERR_NOT_READY			= -3,
	ICE_ERR_INVAL_SIZE			= -6,
	ICE_ERR_INVAL_SIZE			= -6,
	ICE_ERR_DEVICE_NOT_SUPPORTED		= -8,
	ICE_ERR_DEVICE_NOT_SUPPORTED		= -8,
@@ -15,6 +16,8 @@ enum ice_status {
	ICE_ERR_NO_MEMORY			= -11,
	ICE_ERR_NO_MEMORY			= -11,
	ICE_ERR_CFG				= -12,
	ICE_ERR_CFG				= -12,
	ICE_ERR_OUT_OF_RANGE			= -13,
	ICE_ERR_OUT_OF_RANGE			= -13,
	ICE_ERR_ALREADY_EXISTS			= -14,
	ICE_ERR_DOES_NOT_EXIST			= -15,
	ICE_ERR_BUF_TOO_SHORT			= -52,
	ICE_ERR_BUF_TOO_SHORT			= -52,
	ICE_ERR_NVM_BLANK_MODE			= -53,
	ICE_ERR_NVM_BLANK_MODE			= -53,
	ICE_ERR_AQ_ERROR			= -100,
	ICE_ERR_AQ_ERROR			= -100,
+1378 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading