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

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
...@@ -8,6 +8,7 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 */
......
...@@ -258,6 +258,66 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
/** /**
......
...@@ -162,6 +162,57 @@ static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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);
......
...@@ -7,6 +7,7 @@ ...@@ -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 { ...@@ -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,
......
This diff is collapsed.
...@@ -19,6 +19,122 @@ struct ice_vsi_ctx { ...@@ -19,6 +19,122 @@ struct ice_vsi_ctx {
bool alloc_from_pool; bool alloc_from_pool;
}; };
enum ice_sw_fwd_act_type {
ICE_FWD_TO_VSI = 0,
ICE_FWD_TO_VSI_LIST, /* Do not use this when adding filter */
ICE_FWD_TO_Q,
ICE_FWD_TO_QGRP,
ICE_DROP_PACKET,
ICE_INVAL_ACT
};
/* Switch recipe ID enum values are specific to hardware */
enum ice_sw_lkup_type {
ICE_SW_LKUP_ETHERTYPE = 0,
ICE_SW_LKUP_MAC = 1,
ICE_SW_LKUP_MAC_VLAN = 2,
ICE_SW_LKUP_PROMISC = 3,
ICE_SW_LKUP_VLAN = 4,
ICE_SW_LKUP_DFLT = 5,
ICE_SW_LKUP_ETHERTYPE_MAC = 8,
ICE_SW_LKUP_PROMISC_VLAN = 9,
};
struct ice_fltr_info {
/* Look up information: how to look up packet */
enum ice_sw_lkup_type lkup_type;
/* Forward action: filter action to do after lookup */
enum ice_sw_fwd_act_type fltr_act;
/* rule ID returned by firmware once filter rule is created */
u16 fltr_rule_id;
u16 flag;
#define ICE_FLTR_RX BIT(0)
#define ICE_FLTR_TX BIT(1)
#define ICE_FLTR_TX_RX (ICE_FLTR_RX | ICE_FLTR_TX)
/* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */
u16 src;
union {
struct {
u8 mac_addr[ETH_ALEN];
} mac;
struct {
u8 mac_addr[ETH_ALEN];
u16 vlan_id;
} mac_vlan;
struct {
u16 vlan_id;
} vlan;
/* Set lkup_type as ICE_SW_LKUP_ETHERTYPE
* if just using ethertype as filter. Set lkup_type as
* ICE_SW_LKUP_ETHERTYPE_MAC if MAC also needs to be
* passed in as filter.
*/
struct {
u16 ethertype;
u8 mac_addr[ETH_ALEN]; /* optional */
} ethertype_mac;
} l_data;
/* Depending on filter action */
union {
/* queue id in case of ICE_FWD_TO_Q and starting
* queue id in case of ICE_FWD_TO_QGRP.
*/
u16 q_id:11;
u16 vsi_id:10;
u16 vsi_list_id:10;
} fwd_id;
/* 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
*/
u8 qgrp_size;
/* Rule creations populate these indicators basing on the switch type */
bool lb_en; /* Indicate if packet can be looped back */
bool lan_en; /* Indicate if packet can be forwarded to the uplink */
};
/* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list id */
struct ice_vsi_list_map_info {
struct list_head list_entry;
DECLARE_BITMAP(vsi_map, ICE_MAX_VSI);
u16 vsi_list_id;
};
enum ice_sw_fltr_status {
ICE_FLTR_STATUS_NEW = 0,
ICE_FLTR_STATUS_FW_SUCCESS,
ICE_FLTR_STATUS_FW_FAIL,
};
struct ice_fltr_list_entry {
struct list_head list_entry;
enum ice_sw_fltr_status status;
struct ice_fltr_info fltr_info;
};
/* This defines an entry in the list that maintains MAC or VLAN membership
* to HW list mapping, since multiple VSIs can subscribe to the same MAC or
* VLAN. As an optimization the VSI list should be created only when a
* second VSI becomes a subscriber to the VLAN address.
*/
struct ice_fltr_mgmt_list_entry {
/* back pointer to VSI list id to VSI list mapping */
struct ice_vsi_list_map_info *vsi_list_info;
u16 vsi_count;
#define ICE_INVAL_LG_ACT_INDEX 0xffff
u16 lg_act_idx;
#define ICE_INVAL_SW_MARKER_ID 0xffff
u16 sw_marker_id;
struct list_head list_entry;
struct ice_fltr_info fltr_info;
#define ICE_INVAL_COUNTER_ID 0xff
u8 counter_index;
};
/* VSI related commands */ /* VSI related commands */
enum ice_status enum ice_status
ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
...@@ -32,4 +148,8 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx, ...@@ -32,4 +148,8 @@ ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);
/* Switch/bridge related commands */
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);
#endif /* _ICE_SWITCH_H_ */ #endif /* _ICE_SWITCH_H_ */
...@@ -223,6 +223,22 @@ struct ice_port_info { ...@@ -223,6 +223,22 @@ struct ice_port_info {
bool is_vf; bool is_vf;
}; };
struct ice_switch_info {
/* Switch VSI lists to MAC/VLAN translation */
struct mutex mac_list_lock; /* protect MAC list */
struct list_head mac_list_head;
struct mutex vlan_list_lock; /* protect VLAN list */
struct list_head vlan_list_head;
struct mutex eth_m_list_lock; /* protect ethtype list */
struct list_head eth_m_list_head;
struct mutex promisc_list_lock; /* protect promisc mode list */
struct list_head promisc_list_head;
struct mutex mac_vlan_list_lock; /* protect MAC-VLAN list */
struct list_head mac_vlan_list_head;
struct list_head vsi_list_map_head;
};
/* Port hardware description */ /* Port hardware description */
struct ice_hw { struct ice_hw {
u8 __iomem *hw_addr; u8 __iomem *hw_addr;
...@@ -248,11 +264,14 @@ struct ice_hw { ...@@ -248,11 +264,14 @@ struct ice_hw {
u8 max_cgds; u8 max_cgds;
u8 sw_entry_point_layer; u8 sw_entry_point_layer;
bool evb_veb; /* true for VEB, false for VEPA */
struct ice_bus_info bus; struct ice_bus_info bus;
struct ice_nvm_info nvm; struct ice_nvm_info nvm;
struct ice_hw_dev_caps dev_caps; /* device capabilities */ struct ice_hw_dev_caps dev_caps; /* device capabilities */
struct ice_hw_func_caps func_caps; /* function capabilities */ struct ice_hw_func_caps func_caps; /* function capabilities */
struct ice_switch_info *switch_info; /* switch filter lists */
/* Control Queue info */ /* Control Queue info */
struct ice_ctl_q_info adminq; struct ice_ctl_q_info adminq;
...@@ -276,6 +295,8 @@ struct ice_hw { ...@@ -276,6 +295,8 @@ struct ice_hw {
u8 itr_gran_100; u8 itr_gran_100;
u8 itr_gran_50; u8 itr_gran_50;
u8 itr_gran_25; u8 itr_gran_25;
bool ucast_shared; /* true if VSIs can share unicast addr */
}; };
/* Checksum and Shadow RAM pointers */ /* Checksum and Shadow RAM pointers */
......
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