Skip to content

Commit 7975d2a

Browse files
logostdavem330
authored andcommitted
net: aquantia: add support of rx-vlan-filter offload
Since it uses the same NIC table as rx flow vlan filter therefore rx-flow vlan filter accepts only vlans that present on the interface in case of rx-vlan-filter is on. Signed-off-by: Dmitry Bogdanov <[email protected]> Signed-off-by: Igor Russkikh <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9a8cac4 commit 7975d2a

File tree

7 files changed

+197
-18
lines changed

7 files changed

+197
-18
lines changed

drivers/net/ethernet/aquantia/atlantic/aq_filters.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
157157
return -EINVAL;
158158
}
159159

160+
if ((aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
161+
(!test_bit(be16_to_cpu(fsp->h_ext.vlan_tci),
162+
aq_nic->active_vlans))) {
163+
netdev_err(aq_nic->ndev,
164+
"ethtool: unknown vlan-id specified");
165+
return -EINVAL;
166+
}
167+
160168
if (fsp->ring_cookie > aq_nic->aq_nic_cfg.num_rss_queues) {
161169
netdev_err(aq_nic->ndev,
162170
"ethtool: queue number must be in range [0, %d]",
@@ -331,26 +339,108 @@ static int aq_add_del_fether(struct aq_nic_s *aq_nic,
331339
return aq_hw_ops->hw_filter_l2_clear(aq_hw, &data);
332340
}
333341

342+
static bool aq_fvlan_is_busy(struct aq_rx_filter_vlan *aq_vlans, int vlan)
343+
{
344+
int i;
345+
346+
for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
347+
if (aq_vlans[i].enable &&
348+
aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED &&
349+
aq_vlans[i].vlan_id == vlan) {
350+
return true;
351+
}
352+
}
353+
354+
return false;
355+
}
356+
357+
/* Function rebuilds array of vlan filters so that filters with assigned
358+
* queue have a precedence over just vlans on the interface.
359+
*/
360+
static void aq_fvlan_rebuild(struct aq_nic_s *aq_nic,
361+
unsigned long *active_vlans,
362+
struct aq_rx_filter_vlan *aq_vlans)
363+
{
364+
bool vlan_busy = false;
365+
int vlan = -1;
366+
int i;
367+
368+
for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
369+
if (aq_vlans[i].enable &&
370+
aq_vlans[i].queue != AQ_RX_QUEUE_NOT_ASSIGNED)
371+
continue;
372+
do {
373+
vlan = find_next_bit(active_vlans,
374+
VLAN_N_VID,
375+
vlan + 1);
376+
if (vlan == VLAN_N_VID) {
377+
aq_vlans[i].enable = 0U;
378+
aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
379+
aq_vlans[i].vlan_id = 0;
380+
continue;
381+
}
382+
383+
vlan_busy = aq_fvlan_is_busy(aq_vlans, vlan);
384+
if (!vlan_busy) {
385+
aq_vlans[i].enable = 1U;
386+
aq_vlans[i].queue = AQ_RX_QUEUE_NOT_ASSIGNED;
387+
aq_vlans[i].vlan_id = vlan;
388+
}
389+
} while (vlan_busy && vlan != VLAN_N_VID);
390+
}
391+
}
392+
334393
static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
335394
struct aq_rx_filter *aq_rx_fltr,
336395
struct aq_rx_filter_vlan *aq_vlans, bool add)
337396
{
338397
const struct ethtool_rx_flow_spec *fsp = &aq_rx_fltr->aq_fsp;
339398
int location = fsp->location - AQ_RX_FIRST_LOC_FVLANID;
399+
int i;
340400

341401
memset(&aq_vlans[location], 0, sizeof(aq_vlans[location]));
342402

343403
if (!add)
344404
return 0;
345405

406+
/* remove vlan if it was in table without queue assignment */
407+
for (i = 0; i < AQ_VLAN_MAX_FILTERS; ++i) {
408+
if (aq_vlans[i].vlan_id ==
409+
(be16_to_cpu(fsp->h_ext.vlan_tci) & VLAN_VID_MASK)) {
410+
aq_vlans[i].enable = false;
411+
}
412+
}
413+
346414
aq_vlans[location].location = location;
347415
aq_vlans[location].vlan_id = be16_to_cpu(fsp->h_ext.vlan_tci)
348416
& VLAN_VID_MASK;
349417
aq_vlans[location].queue = fsp->ring_cookie & 0x1FU;
350418
aq_vlans[location].enable = 1U;
419+
351420
return 0;
352421
}
353422

423+
int aq_del_fvlan_by_vlan(struct aq_nic_s *aq_nic, u16 vlan_id)
424+
{
425+
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
426+
struct aq_rx_filter *rule = NULL;
427+
struct hlist_node *aq_node2;
428+
429+
hlist_for_each_entry_safe(rule, aq_node2,
430+
&rx_fltrs->filter_list, aq_node) {
431+
if (be16_to_cpu(rule->aq_fsp.h_ext.vlan_tci) == vlan_id)
432+
break;
433+
}
434+
if (rule && be16_to_cpu(rule->aq_fsp.h_ext.vlan_tci) == vlan_id) {
435+
struct ethtool_rxnfc cmd;
436+
437+
cmd.fs.location = rule->aq_fsp.location;
438+
return aq_del_rxnfc_rule(aq_nic, &cmd);
439+
}
440+
441+
return -ENOENT;
442+
}
443+
354444
static int aq_add_del_fvlan(struct aq_nic_s *aq_nic,
355445
struct aq_rx_filter *aq_rx_fltr, bool add)
356446
{
@@ -725,14 +815,62 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
725815
{
726816
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
727817
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
818+
int hweight = 0;
728819
int err = 0;
820+
int i;
729821

730822
if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
731823
return -EOPNOTSUPP;
824+
if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
825+
return -EOPNOTSUPP;
826+
827+
aq_fvlan_rebuild(aq_nic, aq_nic->active_vlans,
828+
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
829+
830+
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
831+
for (i = 0; i < BITS_TO_LONGS(VLAN_N_VID); i++)
832+
hweight += hweight_long(aq_nic->active_vlans[i]);
833+
834+
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
835+
if (err)
836+
return err;
837+
}
732838

733839
err = aq_hw_ops->hw_filter_vlan_set(aq_hw,
734840
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans
735841
);
842+
if (err)
843+
return err;
844+
845+
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
846+
if (hweight < AQ_VLAN_MAX_FILTERS)
847+
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, true);
848+
/* otherwise left in promiscue mode */
849+
}
850+
851+
return err;
852+
}
736853

854+
int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
855+
{
856+
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
857+
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
858+
int err = 0;
859+
860+
memset(aq_nic->active_vlans, 0, sizeof(aq_nic->active_vlans));
861+
aq_fvlan_rebuild(aq_nic, aq_nic->active_vlans,
862+
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
863+
864+
if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
865+
return -EOPNOTSUPP;
866+
if (unlikely(!aq_hw_ops->hw_filter_vlan_ctrl))
867+
return -EOPNOTSUPP;
868+
869+
err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
870+
if (err)
871+
return err;
872+
err = aq_hw_ops->hw_filter_vlan_set(aq_hw,
873+
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans
874+
);
737875
return err;
738876
}

drivers/net/ethernet/aquantia/atlantic/aq_filters.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ int aq_del_rxnfc_rule(struct aq_nic_s *aq_nic, const struct ethtool_rxnfc *cmd);
2727
int aq_get_rxnfc_rule(struct aq_nic_s *aq_nic, struct ethtool_rxnfc *cmd);
2828
int aq_get_rxnfc_all_rules(struct aq_nic_s *aq_nic, struct ethtool_rxnfc *cmd,
2929
u32 *rule_locs);
30+
int aq_del_fvlan_by_vlan(struct aq_nic_s *aq_nic, u16 vlan_id);
3031
int aq_clear_rxnfc_all_rules(struct aq_nic_s *aq_nic);
3132
int aq_reapply_rxnfc_all_rules(struct aq_nic_s *aq_nic);
3233
int aq_filters_vlans_update(struct aq_nic_s *aq_nic);
34+
int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic);
3335

3436
#endif /* AQ_FILTERS_H */

drivers/net/ethernet/aquantia/atlantic/aq_hw.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#define AQ_RX_MAX_RXNFC_LOC AQ_RX_LAST_LOC_FL3L4
2828
#define AQ_VLAN_MAX_FILTERS \
2929
(AQ_RX_LAST_LOC_FVLANID - AQ_RX_FIRST_LOC_FVLANID + 1U)
30+
#define AQ_RX_QUEUE_NOT_ASSIGNED 0xFFU
3031

3132
/* NIC H/W capabilities */
3233
struct aq_hw_caps_s {

drivers/net/ethernet/aquantia/atlantic/aq_main.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ static int aq_ndev_set_features(struct net_device *ndev,
114114
goto err_exit;
115115
}
116116
}
117+
if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
118+
if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
119+
err = aq_filters_vlan_offload_off(aq_nic);
120+
if (unlikely(err))
121+
goto err_exit;
122+
}
123+
}
117124

118125
aq_cfg->features = features;
119126

@@ -162,12 +169,43 @@ static void aq_ndev_set_multicast_settings(struct net_device *ndev)
162169
aq_nic_set_multicast_list(aq_nic, ndev);
163170
}
164171

172+
static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto,
173+
u16 vid)
174+
{
175+
struct aq_nic_s *aq_nic = netdev_priv(ndev);
176+
177+
if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
178+
return -EOPNOTSUPP;
179+
180+
set_bit(vid, aq_nic->active_vlans);
181+
182+
return aq_filters_vlans_update(aq_nic);
183+
}
184+
185+
static int aq_ndo_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto,
186+
u16 vid)
187+
{
188+
struct aq_nic_s *aq_nic = netdev_priv(ndev);
189+
190+
if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
191+
return -EOPNOTSUPP;
192+
193+
clear_bit(vid, aq_nic->active_vlans);
194+
195+
if (-ENOENT == aq_del_fvlan_by_vlan(aq_nic, vid))
196+
return aq_filters_vlans_update(aq_nic);
197+
198+
return 0;
199+
}
200+
165201
static const struct net_device_ops aq_ndev_ops = {
166202
.ndo_open = aq_ndev_open,
167203
.ndo_stop = aq_ndev_close,
168204
.ndo_start_xmit = aq_ndev_start_xmit,
169205
.ndo_set_rx_mode = aq_ndev_set_multicast_settings,
170206
.ndo_change_mtu = aq_ndev_change_mtu,
171207
.ndo_set_mac_address = aq_ndev_set_mac_address,
172-
.ndo_set_features = aq_ndev_set_features
208+
.ndo_set_features = aq_ndev_set_features,
209+
.ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid,
210+
.ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid,
173211
};

drivers/net/ethernet/aquantia/atlantic/aq_nic.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
8484

8585
cfg->is_lro = AQ_CFG_IS_LRO_DEF;
8686

87-
cfg->vlan_id = 0U;
88-
8987
aq_nic_rss_init(self, cfg->num_rss_queues);
9088

9189
/*descriptors */

drivers/net/ethernet/aquantia/atlantic/aq_nic.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ struct aq_nic_cfg_s {
3535
u32 mtu;
3636
u32 flow_control;
3737
u32 link_speed_msk;
38-
u32 vlan_id;
3938
u32 wol;
4039
u16 is_mc_list_enabled;
4140
u16 mc_list_count;
@@ -98,6 +97,8 @@ struct aq_nic_s {
9897
u32 count;
9998
u8 ar[AQ_HW_MULTICAST_ADDRESS_MAX][ETH_ALEN];
10099
} mc_list;
100+
/* Bitmask of currently assigned vlans from linux */
101+
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
101102

102103
struct pci_dev *pdev;
103104
unsigned int msix_entry_mask;

drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
NETIF_F_SG | \
4343
NETIF_F_TSO | \
4444
NETIF_F_LRO | \
45-
NETIF_F_NTUPLE, \
45+
NETIF_F_NTUPLE | \
46+
NETIF_F_HW_VLAN_CTAG_FILTER, \
4647
.hw_priv_flags = IFF_UNICAST_FLT, \
4748
.flow_control = true, \
4849
.mtu = HW_ATL_B0_MTU_JUMBO, \
@@ -320,20 +321,11 @@ static int hw_atl_b0_hw_init_rx_path(struct aq_hw_s *self)
320321
hw_atl_rpf_vlan_outer_etht_set(self, 0x88A8U);
321322
hw_atl_rpf_vlan_inner_etht_set(self, 0x8100U);
322323

323-
if (cfg->vlan_id) {
324-
hw_atl_rpf_vlan_flr_act_set(self, 1U, 0U);
325-
hw_atl_rpf_vlan_id_flr_set(self, 0U, 0U);
326-
hw_atl_rpf_vlan_flr_en_set(self, 0U, 0U);
324+
hw_atl_rpf_vlan_prom_mode_en_set(self, 1);
327325

328-
hw_atl_rpf_vlan_accept_untagged_packets_set(self, 1U);
329-
hw_atl_rpf_vlan_untagged_act_set(self, 1U);
330-
331-
hw_atl_rpf_vlan_flr_act_set(self, 1U, 1U);
332-
hw_atl_rpf_vlan_id_flr_set(self, cfg->vlan_id, 0U);
333-
hw_atl_rpf_vlan_flr_en_set(self, 1U, 1U);
334-
} else {
335-
hw_atl_rpf_vlan_prom_mode_en_set(self, 1);
336-
}
326+
// Always accept untagged packets
327+
hw_atl_rpf_vlan_accept_untagged_packets_set(self, 1U);
328+
hw_atl_rpf_vlan_untagged_act_set(self, 1U);
337329

338330
/* Rx Interrupts */
339331
hw_atl_rdm_rx_desc_wr_wb_irq_en_set(self, 1U);
@@ -1074,6 +1066,14 @@ static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self,
10741066
return aq_hw_err_from_flags(self);
10751067
}
10761068

1069+
static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable)
1070+
{
1071+
/* set promisc in case of disabing the vland filter */
1072+
hw_atl_rpf_vlan_prom_mode_en_set(self, !!!enable);
1073+
1074+
return aq_hw_err_from_flags(self);
1075+
}
1076+
10771077
const struct aq_hw_ops hw_atl_ops_b0 = {
10781078
.hw_set_mac_address = hw_atl_b0_hw_mac_addr_set,
10791079
.hw_init = hw_atl_b0_hw_init,
@@ -1102,6 +1102,7 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
11021102
.hw_filter_l2_clear = hw_atl_b0_hw_fl2_clear,
11031103
.hw_filter_l3l4_set = hw_atl_b0_hw_fl3l4_set,
11041104
.hw_filter_vlan_set = hw_atl_b0_hw_vlan_set,
1105+
.hw_filter_vlan_ctrl = hw_atl_b0_hw_vlan_ctrl,
11051106
.hw_multicast_list_set = hw_atl_b0_hw_multicast_list_set,
11061107
.hw_interrupt_moderation_set = hw_atl_b0_hw_interrupt_moderation_set,
11071108
.hw_rss_set = hw_atl_b0_hw_rss_set,

0 commit comments

Comments
 (0)