Commit 03c3e507 authored by Dmitry Bogdanov's avatar Dmitry Bogdanov Committed by Greg Kroah-Hartman

net: aquantia: fix vlans not working over bridged network

[ Upstream commit 48dd73d0 ]

In configuration of vlan over bridge over aquantia device
it was found that vlan tagged traffic is dropped on chip.

The reason is that bridge device enables promisc mode,
but in atlantic chip vlan filters will still apply.
So we have to corellate promisc settings with vlan configuration.

The solution is to track in a separate state variable the
need of vlan forced promisc. And also consider generic
promisc configuration when doing vlan filter config.

Fixes: 7975d2af ("net: aquantia: add support of rx-vlan-filter offload")
Signed-off-by: default avatarDmitry Bogdanov <dmitry.bogdanov@aquantia.com>
Signed-off-by: default avatarIgor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9590d1d1
...@@ -843,9 +843,14 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic) ...@@ -843,9 +843,14 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
return err; return err;
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
if (hweight < AQ_VLAN_MAX_FILTERS) if (hweight < AQ_VLAN_MAX_FILTERS && hweight > 0) {
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, true); err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw,
!(aq_nic->packet_filter & IFF_PROMISC));
aq_nic->aq_nic_cfg.is_vlan_force_promisc = false;
} else {
/* otherwise left in promiscue mode */ /* otherwise left in promiscue mode */
aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
}
} }
return err; return err;
...@@ -866,6 +871,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic) ...@@ -866,6 +871,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl)) if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
return -EOPNOTSUPP; return -EOPNOTSUPP;
aq_nic->aq_nic_cfg.is_vlan_force_promisc = true;
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false); err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
if (err) if (err)
return err; return err;
......
...@@ -117,6 +117,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self) ...@@ -117,6 +117,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk; cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
cfg->features = cfg->aq_hw_caps->hw_features; cfg->features = cfg->aq_hw_caps->hw_features;
cfg->is_vlan_force_promisc = true;
} }
static int aq_nic_update_link_status(struct aq_nic_s *self) static int aq_nic_update_link_status(struct aq_nic_s *self)
......
...@@ -36,6 +36,7 @@ struct aq_nic_cfg_s { ...@@ -36,6 +36,7 @@ struct aq_nic_cfg_s {
u32 flow_control; u32 flow_control;
u32 link_speed_msk; u32 link_speed_msk;
u32 wol; u32 wol;
bool is_vlan_force_promisc;
u16 is_mc_list_enabled; u16 is_mc_list_enabled;
u16 mc_list_count; u16 mc_list_count;
bool is_autoneg; bool is_autoneg;
......
...@@ -771,8 +771,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, ...@@ -771,8 +771,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
unsigned int packet_filter) unsigned int packet_filter)
{ {
unsigned int i = 0U; unsigned int i = 0U;
struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
hw_atl_rpfl2promiscuous_mode_en_set(self,
IS_FILTER_ENABLED(IFF_PROMISC));
hw_atl_rpf_vlan_prom_mode_en_set(self,
IS_FILTER_ENABLED(IFF_PROMISC) ||
cfg->is_vlan_force_promisc);
hw_atl_rpfl2promiscuous_mode_en_set(self, IS_FILTER_ENABLED(IFF_PROMISC));
hw_atl_rpfl2multicast_flr_en_set(self, hw_atl_rpfl2multicast_flr_en_set(self,
IS_FILTER_ENABLED(IFF_ALLMULTI), 0); IS_FILTER_ENABLED(IFF_ALLMULTI), 0);
...@@ -781,12 +788,12 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, ...@@ -781,12 +788,12 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST)); hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST));
self->aq_nic_cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST); cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i) for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i)
hw_atl_rpfl2_uc_flr_en_set(self, hw_atl_rpfl2_uc_flr_en_set(self,
(self->aq_nic_cfg->is_mc_list_enabled && (cfg->is_mc_list_enabled &&
(i <= self->aq_nic_cfg->mc_list_count)) ? (i <= cfg->mc_list_count)) ?
1U : 0U, i); 1U : 0U, i);
return aq_hw_err_from_flags(self); return aq_hw_err_from_flags(self);
...@@ -1079,7 +1086,7 @@ static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self, ...@@ -1079,7 +1086,7 @@ static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self,
static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable) static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable)
{ {
/* set promisc in case of disabing the vland filter */ /* set promisc in case of disabing the vland filter */
hw_atl_rpf_vlan_prom_mode_en_set(self, !!!enable); hw_atl_rpf_vlan_prom_mode_en_set(self, !enable);
return aq_hw_err_from_flags(self); return aq_hw_err_from_flags(self);
} }
......
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