Commit 5eda8afd authored by Akeem G Abodunrin's avatar Akeem G Abodunrin Committed by Jeff Kirsher

ice: Add support for PF/VF promiscuous mode

Implement support for VF promiscuous mode, MAC/VLAN/MAC_VLAN and PF
multicast MAC/VLAN/MAC_VLAN promiscuous mode.
Signed-off-by: default avatarAkeem G Abodunrin <akeem.g.abodunrin@intel.com>
Signed-off-by: default avatarAnirudh Venkataramanan <anirudh.venkataramanan@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent e1ca65a3
...@@ -125,6 +125,23 @@ extern const char ice_drv_ver[]; ...@@ -125,6 +125,23 @@ extern const char ice_drv_ver[];
#define ice_for_each_q_vector(vsi, i) \ #define ice_for_each_q_vector(vsi, i) \
for ((i) = 0; (i) < (vsi)->num_q_vectors; (i)++) for ((i) = 0; (i) < (vsi)->num_q_vectors; (i)++)
#define ICE_UCAST_PROMISC_BITS (ICE_PROMISC_UCAST_TX | ICE_PROMISC_MCAST_TX | \
ICE_PROMISC_UCAST_RX | ICE_PROMISC_MCAST_RX)
#define ICE_UCAST_VLAN_PROMISC_BITS (ICE_PROMISC_UCAST_TX | \
ICE_PROMISC_MCAST_TX | \
ICE_PROMISC_UCAST_RX | \
ICE_PROMISC_MCAST_RX | \
ICE_PROMISC_VLAN_TX | \
ICE_PROMISC_VLAN_RX)
#define ICE_MCAST_PROMISC_BITS (ICE_PROMISC_MCAST_TX | ICE_PROMISC_MCAST_RX)
#define ICE_MCAST_VLAN_PROMISC_BITS (ICE_PROMISC_MCAST_TX | \
ICE_PROMISC_MCAST_RX | \
ICE_PROMISC_VLAN_TX | \
ICE_PROMISC_VLAN_RX)
struct ice_tc_info { struct ice_tc_info {
u16 qoffset; u16 qoffset;
u16 qcount_tx; u16 qcount_tx;
...@@ -258,6 +275,7 @@ struct ice_vsi { ...@@ -258,6 +275,7 @@ struct ice_vsi {
u8 irqs_ready; u8 irqs_ready;
u8 current_isup; /* Sync 'link up' logging */ u8 current_isup; /* Sync 'link up' logging */
u8 stat_offsets_loaded; u8 stat_offsets_loaded;
u8 vlan_ena;
/* queue information */ /* queue information */
u8 tx_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ u8 tx_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */
......
...@@ -2119,10 +2119,11 @@ ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, ...@@ -2119,10 +2119,11 @@ ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
* ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI
* @vsi: VSI to enable or disable VLAN pruning on * @vsi: VSI to enable or disable VLAN pruning on
* @ena: set to true to enable VLAN pruning and false to disable it * @ena: set to true to enable VLAN pruning and false to disable it
* @vlan_promisc: enable valid security flags if not in VLAN promiscuous mode
* *
* returns 0 if VSI is updated, negative otherwise * returns 0 if VSI is updated, negative otherwise
*/ */
int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc)
{ {
struct ice_vsi_ctx *ctxt; struct ice_vsi_ctx *ctxt;
struct device *dev; struct device *dev;
...@@ -2150,8 +2151,10 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) ...@@ -2150,8 +2151,10 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena)
ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
} }
ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | if (!vlan_promisc)
ICE_AQ_VSI_PROP_SW_VALID); ctxt->info.valid_sections =
cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID |
ICE_AQ_VSI_PROP_SW_VALID);
status = ice_update_vsi(&vsi->back->hw, vsi->idx, ctxt, NULL); status = ice_update_vsi(&vsi->back->hw, vsi->idx, ctxt, NULL);
if (status) { if (status) {
......
...@@ -35,7 +35,7 @@ int ...@@ -35,7 +35,7 @@ int
ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
u16 rel_vmvf_num); u16 rel_vmvf_num);
int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena); int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc);
void ice_vsi_delete(struct ice_vsi *vsi); void ice_vsi_delete(struct ice_vsi *vsi);
......
...@@ -167,6 +167,39 @@ static bool ice_vsi_fltr_changed(struct ice_vsi *vsi) ...@@ -167,6 +167,39 @@ static bool ice_vsi_fltr_changed(struct ice_vsi *vsi)
test_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags); test_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags);
} }
/**
* ice_cfg_promisc - Enable or disable promiscuous mode for a given PF
* @vsi: the VSI being configured
* @promisc_m: mask of promiscuous config bits
* @set_promisc: enable or disable promisc flag request
*
*/
static int ice_cfg_promisc(struct ice_vsi *vsi, u8 promisc_m, bool set_promisc)
{
struct ice_hw *hw = &vsi->back->hw;
enum ice_status status = 0;
if (vsi->type != ICE_VSI_PF)
return 0;
if (vsi->vlan_ena) {
status = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_m,
set_promisc);
} else {
if (set_promisc)
status = ice_set_vsi_promisc(hw, vsi->idx, promisc_m,
0);
else
status = ice_clear_vsi_promisc(hw, vsi->idx, promisc_m,
0);
}
if (status)
return -EIO;
return 0;
}
/** /**
* ice_vsi_sync_fltr - Update the VSI filter list to the HW * ice_vsi_sync_fltr - Update the VSI filter list to the HW
* @vsi: ptr to the VSI * @vsi: ptr to the VSI
...@@ -182,6 +215,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) ...@@ -182,6 +215,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
struct ice_hw *hw = &pf->hw; struct ice_hw *hw = &pf->hw;
enum ice_status status = 0; enum ice_status status = 0;
u32 changed_flags = 0; u32 changed_flags = 0;
u8 promisc_m;
int err = 0; int err = 0;
if (!vsi->netdev) if (!vsi->netdev)
...@@ -245,8 +279,35 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) ...@@ -245,8 +279,35 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
} }
} }
/* check for changes in promiscuous modes */ /* check for changes in promiscuous modes */
if (changed_flags & IFF_ALLMULTI) if (changed_flags & IFF_ALLMULTI) {
netdev_warn(netdev, "Unsupported configuration\n"); if (vsi->current_netdev_flags & IFF_ALLMULTI) {
if (vsi->vlan_ena)
promisc_m = ICE_MCAST_VLAN_PROMISC_BITS;
else
promisc_m = ICE_MCAST_PROMISC_BITS;
err = ice_cfg_promisc(vsi, promisc_m, true);
if (err) {
netdev_err(netdev, "Error setting Multicast promiscuous mode on VSI %i\n",
vsi->vsi_num);
vsi->current_netdev_flags &= ~IFF_ALLMULTI;
goto out_promisc;
}
} else if (!(vsi->current_netdev_flags & IFF_ALLMULTI)) {
if (vsi->vlan_ena)
promisc_m = ICE_MCAST_VLAN_PROMISC_BITS;
else
promisc_m = ICE_MCAST_PROMISC_BITS;
err = ice_cfg_promisc(vsi, promisc_m, false);
if (err) {
netdev_err(netdev, "Error clearing Multicast promiscuous mode on VSI %i\n",
vsi->vsi_num);
vsi->current_netdev_flags |= IFF_ALLMULTI;
goto out_promisc;
}
}
}
if (((changed_flags & IFF_PROMISC) || promisc_forced_on) || if (((changed_flags & IFF_PROMISC) || promisc_forced_on) ||
test_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags)) { test_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags)) {
...@@ -1665,6 +1726,7 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto, ...@@ -1665,6 +1726,7 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto,
{ {
struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi; struct ice_vsi *vsi = np->vsi;
int ret;
if (vid >= VLAN_N_VID) { if (vid >= VLAN_N_VID) {
netdev_err(netdev, "VLAN id requested %d is out of range %d\n", netdev_err(netdev, "VLAN id requested %d is out of range %d\n",
...@@ -1677,8 +1739,7 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto, ...@@ -1677,8 +1739,7 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto,
/* Enable VLAN pruning when VLAN 0 is added */ /* Enable VLAN pruning when VLAN 0 is added */
if (unlikely(!vid)) { if (unlikely(!vid)) {
int ret = ice_cfg_vlan_pruning(vsi, true); ret = ice_cfg_vlan_pruning(vsi, true, false);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -1687,7 +1748,13 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto, ...@@ -1687,7 +1748,13 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto,
* needed to continue allowing all untagged packets since VLAN prune * needed to continue allowing all untagged packets since VLAN prune
* list is applied to all packets by the switch * list is applied to all packets by the switch
*/ */
return ice_vsi_add_vlan(vsi, vid); ret = ice_vsi_add_vlan(vsi, vid);
if (!ret) {
vsi->vlan_ena = true;
set_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags);
}
return ret;
} }
/** /**
...@@ -1704,7 +1771,7 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, ...@@ -1704,7 +1771,7 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto,
{ {
struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi; struct ice_vsi *vsi = np->vsi;
int status; int ret;
if (vsi->info.pvid) if (vsi->info.pvid)
return -EINVAL; return -EINVAL;
...@@ -1712,15 +1779,17 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, ...@@ -1712,15 +1779,17 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto,
/* Make sure ice_vsi_kill_vlan is successful before updating VLAN /* Make sure ice_vsi_kill_vlan is successful before updating VLAN
* information * information
*/ */
status = ice_vsi_kill_vlan(vsi, vid); ret = ice_vsi_kill_vlan(vsi, vid);
if (status) if (ret)
return status; return ret;
/* Disable VLAN pruning when VLAN 0 is removed */ /* Disable VLAN pruning when VLAN 0 is removed */
if (unlikely(!vid)) if (unlikely(!vid))
status = ice_cfg_vlan_pruning(vsi, false); ret = ice_cfg_vlan_pruning(vsi, false, false);
return status; vsi->vlan_ena = false;
set_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags);
return ret;
} }
/** /**
......
...@@ -2189,6 +2189,291 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle, ...@@ -2189,6 +2189,291 @@ ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
return status; return status;
} }
/**
* ice_determine_promisc_mask
* @fi: filter info to parse
*
* Helper function to determine which ICE_PROMISC_ mask corresponds
* to given filter into.
*/
static u8 ice_determine_promisc_mask(struct ice_fltr_info *fi)
{
u16 vid = fi->l_data.mac_vlan.vlan_id;
u8 *macaddr = fi->l_data.mac.mac_addr;
bool is_tx_fltr = false;
u8 promisc_mask = 0;
if (fi->flag == ICE_FLTR_TX)
is_tx_fltr = true;
if (is_broadcast_ether_addr(macaddr))
promisc_mask |= is_tx_fltr ?
ICE_PROMISC_BCAST_TX : ICE_PROMISC_BCAST_RX;
else if (is_multicast_ether_addr(macaddr))
promisc_mask |= is_tx_fltr ?
ICE_PROMISC_MCAST_TX : ICE_PROMISC_MCAST_RX;
else if (is_unicast_ether_addr(macaddr))
promisc_mask |= is_tx_fltr ?
ICE_PROMISC_UCAST_TX : ICE_PROMISC_UCAST_RX;
if (vid)
promisc_mask |= is_tx_fltr ?
ICE_PROMISC_VLAN_TX : ICE_PROMISC_VLAN_RX;
return promisc_mask;
}
/**
* ice_remove_promisc - Remove promisc based filter rules
* @hw: pointer to the hardware structure
* @recp_id: recipe id for which the rule needs to removed
* @v_list: list of promisc entries
*/
static enum ice_status
ice_remove_promisc(struct ice_hw *hw, u8 recp_id,
struct list_head *v_list)
{
struct ice_fltr_list_entry *v_list_itr, *tmp;
list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
v_list_itr->status =
ice_remove_rule_internal(hw, recp_id, v_list_itr);
if (v_list_itr->status)
return v_list_itr->status;
}
return 0;
}
/**
* ice_clear_vsi_promisc - clear specified promiscuous mode(s) for given VSI
* @hw: pointer to the hardware structure
* @vsi_handle: VSI handle to clear mode
* @promisc_mask: mask of promiscuous config bits to clear
* @vid: VLAN ID to clear VLAN promiscuous
*/
enum ice_status
ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
u16 vid)
{
struct ice_switch_info *sw = hw->switch_info;
struct ice_fltr_list_entry *fm_entry, *tmp;
struct list_head remove_list_head;
struct ice_fltr_mgmt_list_entry *itr;
struct list_head *rule_head;
struct mutex *rule_lock; /* Lock to protect filter rule list */
enum ice_status status = 0;
u8 recipe_id;
if (!ice_is_vsi_valid(hw, vsi_handle))
return ICE_ERR_PARAM;
if (vid)
recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
else
recipe_id = ICE_SW_LKUP_PROMISC;
rule_head = &sw->recp_list[recipe_id].filt_rules;
rule_lock = &sw->recp_list[recipe_id].filt_rule_lock;
INIT_LIST_HEAD(&remove_list_head);
mutex_lock(rule_lock);
list_for_each_entry(itr, rule_head, list_entry) {
u8 fltr_promisc_mask = 0;
if (!ice_vsi_uses_fltr(itr, vsi_handle))
continue;
fltr_promisc_mask |=
ice_determine_promisc_mask(&itr->fltr_info);
/* Skip if filter is not completely specified by given mask */
if (fltr_promisc_mask & ~promisc_mask)
continue;
status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
&remove_list_head,
&itr->fltr_info);
if (status) {
mutex_unlock(rule_lock);
goto free_fltr_list;
}
}
mutex_unlock(rule_lock);
status = ice_remove_promisc(hw, recipe_id, &remove_list_head);
free_fltr_list:
list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
list_del(&fm_entry->list_entry);
devm_kfree(ice_hw_to_dev(hw), fm_entry);
}
return status;
}
/**
* ice_set_vsi_promisc - set given VSI to given promiscuous mode(s)
* @hw: pointer to the hardware structure
* @vsi_handle: VSI handle to configure
* @promisc_mask: mask of promiscuous config bits
* @vid: VLAN ID to set VLAN promiscuous
*/
enum ice_status
ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid)
{
enum { UCAST_FLTR = 1, MCAST_FLTR, BCAST_FLTR };
struct ice_fltr_list_entry f_list_entry;
struct ice_fltr_info new_fltr;
enum ice_status status = 0;
bool is_tx_fltr;
u16 hw_vsi_id;
int pkt_type;
u8 recipe_id;
if (!ice_is_vsi_valid(hw, vsi_handle))
return ICE_ERR_PARAM;
hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
memset(&new_fltr, 0, sizeof(new_fltr));
if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) {
new_fltr.lkup_type = ICE_SW_LKUP_PROMISC_VLAN;
new_fltr.l_data.mac_vlan.vlan_id = vid;
recipe_id = ICE_SW_LKUP_PROMISC_VLAN;
} else {
new_fltr.lkup_type = ICE_SW_LKUP_PROMISC;
recipe_id = ICE_SW_LKUP_PROMISC;
}
/* Separate filters must be set for each direction/packet type
* combination, so we will loop over the mask value, store the
* individual type, and clear it out in the input mask as it
* is found.
*/
while (promisc_mask) {
u8 *mac_addr;
pkt_type = 0;
is_tx_fltr = false;
if (promisc_mask & ICE_PROMISC_UCAST_RX) {
promisc_mask &= ~ICE_PROMISC_UCAST_RX;
pkt_type = UCAST_FLTR;
} else if (promisc_mask & ICE_PROMISC_UCAST_TX) {
promisc_mask &= ~ICE_PROMISC_UCAST_TX;
pkt_type = UCAST_FLTR;
is_tx_fltr = true;
} else if (promisc_mask & ICE_PROMISC_MCAST_RX) {
promisc_mask &= ~ICE_PROMISC_MCAST_RX;
pkt_type = MCAST_FLTR;
} else if (promisc_mask & ICE_PROMISC_MCAST_TX) {
promisc_mask &= ~ICE_PROMISC_MCAST_TX;
pkt_type = MCAST_FLTR;
is_tx_fltr = true;
} else if (promisc_mask & ICE_PROMISC_BCAST_RX) {
promisc_mask &= ~ICE_PROMISC_BCAST_RX;
pkt_type = BCAST_FLTR;
} else if (promisc_mask & ICE_PROMISC_BCAST_TX) {
promisc_mask &= ~ICE_PROMISC_BCAST_TX;
pkt_type = BCAST_FLTR;
is_tx_fltr = true;
}
/* Check for VLAN promiscuous flag */
if (promisc_mask & ICE_PROMISC_VLAN_RX) {
promisc_mask &= ~ICE_PROMISC_VLAN_RX;
} else if (promisc_mask & ICE_PROMISC_VLAN_TX) {
promisc_mask &= ~ICE_PROMISC_VLAN_TX;
is_tx_fltr = true;
}
/* Set filter DA based on packet type */
mac_addr = new_fltr.l_data.mac.mac_addr;
if (pkt_type == BCAST_FLTR) {
eth_broadcast_addr(mac_addr);
} else if (pkt_type == MCAST_FLTR ||
pkt_type == UCAST_FLTR) {
/* Use the dummy ether header DA */
ether_addr_copy(mac_addr, dummy_eth_header);
if (pkt_type == MCAST_FLTR)
mac_addr[0] |= 0x1; /* Set multicast bit */
}
/* Need to reset this to zero for all iterations */
new_fltr.flag = 0;
if (is_tx_fltr) {
new_fltr.flag |= ICE_FLTR_TX;
new_fltr.src = hw_vsi_id;
} else {
new_fltr.flag |= ICE_FLTR_RX;
new_fltr.src = hw->port_info->lport;
}
new_fltr.fltr_act = ICE_FWD_TO_VSI;
new_fltr.vsi_handle = vsi_handle;
new_fltr.fwd_id.hw_vsi_id = hw_vsi_id;
f_list_entry.fltr_info = new_fltr;
status = ice_add_rule_internal(hw, recipe_id, &f_list_entry);
if (status)
goto set_promisc_exit;
}
set_promisc_exit:
return status;
}
/**
* ice_set_vlan_vsi_promisc
* @hw: pointer to the hardware structure
* @vsi_handle: VSI handle to configure
* @promisc_mask: mask of promiscuous config bits
* @rm_vlan_promisc: Clear VLANs VSI promisc mode
*
* Configure VSI with all associated VLANs to given promiscuous mode(s)
*/
enum ice_status
ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
bool rm_vlan_promisc)
{
struct ice_switch_info *sw = hw->switch_info;
struct ice_fltr_list_entry *list_itr, *tmp;
struct list_head vsi_list_head;
struct list_head *vlan_head;
struct mutex *vlan_lock; /* Lock to protect filter rule list */
enum ice_status status;
u16 vlan_id;
INIT_LIST_HEAD(&vsi_list_head);
vlan_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
vlan_head = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rules;
mutex_lock(vlan_lock);
status = ice_add_to_vsi_fltr_list(hw, vsi_handle, vlan_head,
&vsi_list_head);
mutex_unlock(vlan_lock);
if (status)
goto free_fltr_list;
list_for_each_entry(list_itr, &vsi_list_head, list_entry) {
vlan_id = list_itr->fltr_info.l_data.vlan.vlan_id;
if (rm_vlan_promisc)
status = ice_clear_vsi_promisc(hw, vsi_handle,
promisc_mask, vlan_id);
else
status = ice_set_vsi_promisc(hw, vsi_handle,
promisc_mask, vlan_id);
if (status)
break;
}
free_fltr_list:
list_for_each_entry_safe(list_itr, tmp, &vsi_list_head, list_entry) {
list_del(&list_itr->list_entry);
devm_kfree(ice_hw_to_dev(hw), list_itr);
}
return status;
}
/** /**
* ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI * ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI
* @hw: pointer to the hardware structure * @hw: pointer to the hardware structure
...@@ -2224,12 +2509,14 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle, ...@@ -2224,12 +2509,14 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,
case ICE_SW_LKUP_VLAN: case ICE_SW_LKUP_VLAN:
ice_remove_vlan(hw, &remove_list_head); ice_remove_vlan(hw, &remove_list_head);
break; break;
case ICE_SW_LKUP_PROMISC:
case ICE_SW_LKUP_PROMISC_VLAN:
ice_remove_promisc(hw, lkup, &remove_list_head);
break;
case ICE_SW_LKUP_MAC_VLAN: case ICE_SW_LKUP_MAC_VLAN:
case ICE_SW_LKUP_ETHERTYPE: case ICE_SW_LKUP_ETHERTYPE:
case ICE_SW_LKUP_ETHERTYPE_MAC: case ICE_SW_LKUP_ETHERTYPE_MAC:
case ICE_SW_LKUP_PROMISC:
case ICE_SW_LKUP_DFLT: case ICE_SW_LKUP_DFLT:
case ICE_SW_LKUP_PROMISC_VLAN:
case ICE_SW_LKUP_LAST: case ICE_SW_LKUP_LAST:
default: default:
ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup); ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup);
......
...@@ -178,6 +178,17 @@ struct ice_fltr_mgmt_list_entry { ...@@ -178,6 +178,17 @@ struct ice_fltr_mgmt_list_entry {
u8 counter_index; u8 counter_index;
}; };
enum ice_promisc_flags {
ICE_PROMISC_UCAST_RX = 0x1,
ICE_PROMISC_UCAST_TX = 0x2,
ICE_PROMISC_MCAST_RX = 0x4,
ICE_PROMISC_MCAST_TX = 0x8,
ICE_PROMISC_BCAST_RX = 0x10,
ICE_PROMISC_BCAST_TX = 0x20,
ICE_PROMISC_VLAN_RX = 0x40,
ICE_PROMISC_VLAN_TX = 0x80,
};
/* VSI related commands */ /* VSI related commands */
enum ice_status enum ice_status
ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
...@@ -202,8 +213,19 @@ void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle); ...@@ -202,8 +213,19 @@ void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle);
enum ice_status enum ice_status
ice_add_vlan(struct ice_hw *hw, struct list_head *m_list); 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_remove_vlan(struct ice_hw *hw, struct list_head *v_list);
/* Promisc/defport setup for VSIs */
enum ice_status enum ice_status
ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction); ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction);
enum ice_status
ice_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
u16 vid);
enum ice_status
ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
u16 vid);
enum ice_status
ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
bool rm_vlan_promisc);
enum ice_status ice_init_def_sw_recp(struct ice_hw *hw); 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); u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle);
......
...@@ -771,6 +771,47 @@ static void ice_cleanup_and_realloc_vf(struct ice_vf *vf) ...@@ -771,6 +771,47 @@ static void ice_cleanup_and_realloc_vf(struct ice_vf *vf)
wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE); wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
} }
/**
* ice_vf_set_vsi_promisc - set given VF VSI to given promiscuous mode(s)
* @vf: pointer to the VF info
* @vsi: the VSI being configured
* @promisc_m: mask of promiscuous config bits
* @rm_promisc: promisc flag request from the VF to remove or add filter
*
* This function configures VF VSI promiscuous mode, based on the VF requests,
* for Unicast, Multicast and VLAN
*/
static enum ice_status
ice_vf_set_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m,
bool rm_promisc)
{
struct ice_pf *pf = vf->pf;
enum ice_status status = 0;
struct ice_hw *hw;
hw = &pf->hw;
if (vf->num_vlan) {
status = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_m,
rm_promisc);
} else if (vf->port_vlan_id) {
if (rm_promisc)
status = ice_clear_vsi_promisc(hw, vsi->idx, promisc_m,
vf->port_vlan_id);
else
status = ice_set_vsi_promisc(hw, vsi->idx, promisc_m,
vf->port_vlan_id);
} else {
if (rm_promisc)
status = ice_clear_vsi_promisc(hw, vsi->idx, promisc_m,
0);
else
status = ice_set_vsi_promisc(hw, vsi->idx, promisc_m,
0);
}
return status;
}
/** /**
* ice_reset_all_vfs - reset all allocated VFs in one go * ice_reset_all_vfs - reset all allocated VFs in one go
* @pf: pointer to the PF structure * @pf: pointer to the PF structure
...@@ -892,9 +933,10 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr) ...@@ -892,9 +933,10 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
{ {
struct ice_pf *pf = vf->pf; struct ice_pf *pf = vf->pf;
struct ice_hw *hw = &pf->hw;
struct ice_vsi *vsi; struct ice_vsi *vsi;
struct ice_hw *hw;
bool rsd = false; bool rsd = false;
u8 promisc_m;
u32 reg; u32 reg;
int i; int i;
...@@ -920,6 +962,7 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) ...@@ -920,6 +962,7 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
vf->vf_id, NULL); vf->vf_id, NULL);
} }
hw = &pf->hw;
/* poll VPGEN_VFRSTAT reg to make sure /* poll VPGEN_VFRSTAT reg to make sure
* that reset is complete * that reset is complete
*/ */
...@@ -945,6 +988,21 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) ...@@ -945,6 +988,21 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
usleep_range(10000, 20000); usleep_range(10000, 20000);
/* disable promiscuous modes in case they were enabled
* ignore any error if disabling process failed
*/
if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) ||
test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) {
if (vf->port_vlan_id || vf->num_vlan)
promisc_m = ICE_UCAST_VLAN_PROMISC_BITS;
else
promisc_m = ICE_UCAST_PROMISC_BITS;
vsi = pf->vsi[vf->lan_vsi_idx];
if (ice_vf_set_vsi_promisc(vf, vsi, promisc_m, true))
dev_err(&pf->pdev->dev, "disabling promiscuous mode failed\n");
}
/* free VF resources to begin resetting the VSI state */ /* free VF resources to begin resetting the VSI state */
ice_free_vf_res(vf); ice_free_vf_res(vf);
...@@ -2192,7 +2250,11 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) ...@@ -2192,7 +2250,11 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
(struct virtchnl_vlan_filter_list *)msg; (struct virtchnl_vlan_filter_list *)msg;
enum ice_status aq_ret = 0; enum ice_status aq_ret = 0;
struct ice_pf *pf = vf->pf; struct ice_pf *pf = vf->pf;
bool vlan_promisc = false;
struct ice_vsi *vsi; struct ice_vsi *vsi;
struct ice_hw *hw;
int status = 0;
u8 promisc_m;
int i; int i;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
...@@ -2209,7 +2271,9 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) ...@@ -2209,7 +2271,9 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
vf->num_vlan >= ICE_MAX_VLAN_PER_VF) { vf->num_vlan >= ICE_MAX_VLAN_PER_VF) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"VF is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n"); "VF is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n");
aq_ret = ICE_ERR_PARAM; /* There is no need to let VF know about being not trusted,
* so we can just return success message here
*/
goto error_param; goto error_param;
} }
...@@ -2222,6 +2286,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) ...@@ -2222,6 +2286,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
} }
} }
hw = &pf->hw;
vsi = ice_find_vsi_from_id(vf->pf, vfl->vsi_id); vsi = ice_find_vsi_from_id(vf->pf, vfl->vsi_id);
if (!vsi) { if (!vsi) {
aq_ret = ICE_ERR_PARAM; aq_ret = ICE_ERR_PARAM;
...@@ -2241,19 +2306,41 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) ...@@ -2241,19 +2306,41 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
goto error_param; goto error_param;
} }
if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) ||
test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))
vlan_promisc = true;
if (add_v) { if (add_v) {
for (i = 0; i < vfl->num_elements; i++) { for (i = 0; i < vfl->num_elements; i++) {
u16 vid = vfl->vlan_id[i]; u16 vid = vfl->vlan_id[i];
if (!ice_vsi_add_vlan(vsi, vid)) { if (ice_vsi_add_vlan(vsi, vid)) {
vf->num_vlan++; aq_ret = ICE_ERR_PARAM;
goto error_param;
}
/* Enable VLAN pruning when VLAN 0 is added */ vf->num_vlan++;
if (unlikely(!vid)) /* Enable VLAN pruning when VLAN is added */
if (ice_cfg_vlan_pruning(vsi, true)) if (!vlan_promisc) {
aq_ret = ICE_ERR_PARAM; status = ice_cfg_vlan_pruning(vsi, true, false);
if (status) {
aq_ret = ICE_ERR_PARAM;
dev_err(&pf->pdev->dev,
"Enable VLAN pruning on VLAN ID: %d failed error-%d\n",
vid, status);
goto error_param;
}
} else { } else {
aq_ret = ICE_ERR_PARAM; /* Enable Ucast/Mcast VLAN promiscuous mode */
promisc_m = ICE_PROMISC_VLAN_TX |
ICE_PROMISC_VLAN_RX;
status = ice_set_vsi_promisc(hw, vsi->idx,
promisc_m, vid);
if (status)
dev_err(&pf->pdev->dev,
"Enable Unicast/multicast promiscuous mode on VLAN ID:%d failed error-%d\n",
vid, status);
} }
} }
} else { } else {
...@@ -2263,12 +2350,22 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) ...@@ -2263,12 +2350,22 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
/* Make sure ice_vsi_kill_vlan is successful before /* Make sure ice_vsi_kill_vlan is successful before
* updating VLAN information * updating VLAN information
*/ */
if (!ice_vsi_kill_vlan(vsi, vid)) { if (ice_vsi_kill_vlan(vsi, vid)) {
vf->num_vlan--; aq_ret = ICE_ERR_PARAM;
goto error_param;
}
vf->num_vlan--;
/* Disable VLAN pruning when removing VLAN */
ice_cfg_vlan_pruning(vsi, false, false);
/* Disable Unicast/Multicast VLAN promiscuous mode */
if (vlan_promisc) {
promisc_m = ICE_PROMISC_VLAN_TX |
ICE_PROMISC_VLAN_RX;
/* Disable VLAN pruning when removing VLAN 0 */ ice_clear_vsi_promisc(hw, vsi->idx,
if (unlikely(!vid)) promisc_m, vid);
ice_cfg_vlan_pruning(vsi, false);
} }
} }
} }
......
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