From 9daf8208dd4dee4e13079bd0520a5fb8d20e8b06 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Tue, 20 Mar 2018 07:58:12 -0700 Subject: 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: Anirudh Venkataramanan Tested-by: Tony Brelinski Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 74 ++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) (limited to 'drivers/net/ethernet/intel/ice/ice_common.c') diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index a4ce8a87fb0d..67301fe75482 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -258,6 +258,66 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, 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 * @hw: pointer to the hardware structure @@ -321,6 +381,8 @@ enum ice_status ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_alloc; + hw->evb_veb = true; + /* Query the allocated resources for tx scheduler */ status = ice_sched_query_res_alloc(hw); if (status) { @@ -352,21 +414,27 @@ enum ice_status ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_sched; + status = ice_init_fltr_mgmt_struct(hw); + if (status) + goto err_unroll_sched; + /* Get port MAC information */ 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); 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); devm_kfree(ice_hw_to_dev(hw), mac_buf); if (status) - goto err_unroll_sched; + goto err_unroll_fltr_mgmt_struct; return 0; +err_unroll_fltr_mgmt_struct: + ice_cleanup_fltr_mgmt_struct(hw); err_unroll_sched: ice_sched_cleanup_all(hw); 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); hw->port_info = NULL; } + + ice_cleanup_fltr_mgmt_struct(hw); } /** -- cgit v1.2.3