Skip to content

Commit 54bcb3d

Browse files
logostdavem330
authored andcommitted
net: aquantia: add vlan id to rx flow filters
The VLAN filter (VLAN id) is compared against 16 filters. VLAN id must be accompanied by mask 0xF000. That is to distinguish VLAN filter from L2 Ethertype filter with UserPriority since both User Priority and VLAN ID are passed in the same 'vlan' parameter. Flow type may be any as it is not matched for VLAN filter. Due to fixed order of the rules in the NIC, the location 0-15 are reserved for vlan filters. Example: To add a rule that directs packets from VLAN 2001 to queue 5: ethtool -N <ethX> flow-type ip4 vlan 2001 m 0xF000 action 5 loc 0 Signed-off-by: Dmitry Bogdanov <[email protected]> Signed-off-by: Igor Russkikh <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a6ed6f2 commit 54bcb3d

File tree

7 files changed

+151
-3
lines changed

7 files changed

+151
-3
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
#include <linux/etherdevice.h>
1616
#include <linux/pci.h>
17-
17+
#include <linux/if_vlan.h>
1818
#include "ver.h"
1919
#include "aq_cfg.h"
2020
#include "aq_utils.h"

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

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,29 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
119119
return 0;
120120
}
121121

122+
static int __must_check
123+
aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
124+
struct aq_hw_rx_fltrs_s *rx_fltrs,
125+
struct ethtool_rx_flow_spec *fsp)
126+
{
127+
if (fsp->location < AQ_RX_FIRST_LOC_FVLANID ||
128+
fsp->location > AQ_RX_LAST_LOC_FVLANID) {
129+
netdev_err(aq_nic->ndev,
130+
"ethtool: location must be in range [%d, %d]",
131+
AQ_RX_FIRST_LOC_FVLANID,
132+
AQ_RX_LAST_LOC_FVLANID);
133+
return -EINVAL;
134+
}
135+
136+
if (fsp->ring_cookie > aq_nic->aq_nic_cfg.num_rss_queues) {
137+
netdev_err(aq_nic->ndev,
138+
"ethtool: queue number must be in range [0, %d]",
139+
aq_nic->aq_nic_cfg.num_rss_queues - 1);
140+
return -EINVAL;
141+
}
142+
return 0;
143+
}
144+
122145
static int __must_check
123146
aq_check_filter(struct aq_nic_s *aq_nic,
124147
struct ethtool_rx_flow_spec *fsp)
@@ -127,7 +150,14 @@ aq_check_filter(struct aq_nic_s *aq_nic,
127150
struct aq_hw_rx_fltrs_s *rx_fltrs = aq_get_hw_rx_fltrs(aq_nic);
128151

129152
if (fsp->flow_type & FLOW_EXT) {
130-
err = -EOPNOTSUPP;
153+
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
154+
err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
155+
} else {
156+
netdev_err(aq_nic->ndev,
157+
"ethtool: invalid vlan mask 0x%x specified",
158+
be16_to_cpu(fsp->m_ext.vlan_tci));
159+
err = -EINVAL;
160+
}
131161
} else {
132162
switch (fsp->flow_type & ~FLOW_EXT) {
133163
case ETHER_FLOW:
@@ -229,6 +259,42 @@ aq_check_rule(struct aq_nic_s *aq_nic,
229259
return err;
230260
}
231261

262+
static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
263+
struct aq_rx_filter *aq_rx_fltr,
264+
struct aq_rx_filter_vlan *aq_vlans, bool add)
265+
{
266+
const struct ethtool_rx_flow_spec *fsp = &aq_rx_fltr->aq_fsp;
267+
int location = fsp->location - AQ_RX_FIRST_LOC_FVLANID;
268+
269+
memset(&aq_vlans[location], 0, sizeof(aq_vlans[location]));
270+
271+
if (!add)
272+
return 0;
273+
274+
aq_vlans[location].location = location;
275+
aq_vlans[location].vlan_id = be16_to_cpu(fsp->h_ext.vlan_tci)
276+
& VLAN_VID_MASK;
277+
aq_vlans[location].queue = fsp->ring_cookie & 0x1FU;
278+
aq_vlans[location].enable = 1U;
279+
return 0;
280+
}
281+
282+
static int aq_add_del_fvlan(struct aq_nic_s *aq_nic,
283+
struct aq_rx_filter *aq_rx_fltr, bool add)
284+
{
285+
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
286+
287+
if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
288+
return -EOPNOTSUPP;
289+
290+
aq_set_data_fvlan(aq_nic,
291+
aq_rx_fltr,
292+
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans,
293+
add);
294+
295+
return aq_filters_vlans_update(aq_nic);
296+
}
297+
232298
static int aq_set_data_fl3l4(struct aq_nic_s *aq_nic,
233299
struct aq_rx_filter *aq_rx_fltr,
234300
struct aq_rx_filter_l3l4 *data, bool add)
@@ -354,7 +420,13 @@ static int aq_add_del_rule(struct aq_nic_s *aq_nic,
354420
int err = -EINVAL;
355421

356422
if (aq_rx_fltr->aq_fsp.flow_type & FLOW_EXT) {
357-
err = -EOPNOTSUPP;
423+
if (be16_to_cpu(aq_rx_fltr->aq_fsp.m_ext.vlan_tci)
424+
== VLAN_VID_MASK) {
425+
aq_rx_fltr->type = aq_rx_filter_vlan;
426+
err = aq_add_del_fvlan(aq_nic, aq_rx_fltr, add);
427+
} else {
428+
err = -EINVAL;
429+
}
358430
} else {
359431
switch (aq_rx_fltr->aq_fsp.flow_type & ~FLOW_EXT) {
360432
case ETHER_FLOW:
@@ -573,3 +645,19 @@ int aq_reapply_rxnfc_all_rules(struct aq_nic_s *aq_nic)
573645
err_exit:
574646
return err;
575647
}
648+
649+
int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
650+
{
651+
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
652+
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
653+
int err = 0;
654+
655+
if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
656+
return -EOPNOTSUPP;
657+
658+
err = aq_hw_ops->hw_filter_vlan_set(aq_hw,
659+
aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans
660+
);
661+
662+
return err;
663+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "aq_nic.h"
1010

1111
enum aq_rx_filter_type {
12+
aq_rx_filter_vlan,
1213
aq_rx_filter_l3l4
1314
};
1415

@@ -27,5 +28,6 @@ int aq_get_rxnfc_all_rules(struct aq_nic_s *aq_nic, struct ethtool_rxnfc *cmd,
2728
u32 *rule_locs);
2829
int aq_clear_rxnfc_all_rules(struct aq_nic_s *aq_nic);
2930
int aq_reapply_rxnfc_all_rules(struct aq_nic_s *aq_nic);
31+
int aq_filters_vlans_update(struct aq_nic_s *aq_nic);
3032

3133
#endif /* AQ_FILTERS_H */

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@
1818
#include "aq_rss.h"
1919
#include "hw_atl/hw_atl_utils.h"
2020

21+
#define AQ_RX_FIRST_LOC_FVLANID 0U
22+
#define AQ_RX_LAST_LOC_FVLANID 15U
2123
#define AQ_RX_FIRST_LOC_FL3L4 32U
2224
#define AQ_RX_LAST_LOC_FL3L4 39U
2325
#define AQ_RX_MAX_RXNFC_LOC AQ_RX_LAST_LOC_FL3L4
26+
#define AQ_VLAN_MAX_FILTERS \
27+
(AQ_RX_LAST_LOC_FVLANID - AQ_RX_FIRST_LOC_FVLANID + 1U)
2428

2529
/* NIC H/W capabilities */
2630
struct aq_hw_caps_s {
@@ -194,6 +198,11 @@ struct aq_hw_ops {
194198
int (*hw_filter_l3l4_clear)(struct aq_hw_s *self,
195199
struct aq_rx_filter_l3l4 *data);
196200

201+
int (*hw_filter_vlan_set)(struct aq_hw_s *self,
202+
struct aq_rx_filter_vlan *aq_vlans);
203+
204+
int (*hw_filter_vlan_ctrl)(struct aq_hw_s *self, bool enable);
205+
197206
int (*hw_multicast_list_set)(struct aq_hw_s *self,
198207
u8 ar_mac[AQ_HW_MULTICAST_ADDRESS_MAX]
199208
[ETH_ALEN],

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ struct aq_nic_cfg_s {
6161
#define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
6262
((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
6363

64+
struct aq_hw_rx_fl2 {
65+
struct aq_rx_filter_vlan aq_vlans[AQ_VLAN_MAX_FILTERS];
66+
};
67+
6468
struct aq_hw_rx_fl3l4 {
6569
u8 active_ipv4;
6670
u8 active_ipv6:2;
@@ -70,6 +74,7 @@ struct aq_hw_rx_fl3l4 {
7074
struct aq_hw_rx_fltrs_s {
7175
struct hlist_head filter_list;
7276
u16 active_filters;
77+
struct aq_hw_rx_fl2 fl2;
7378
struct aq_hw_rx_fl3l4 fl3l4;
7479
};
7580

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,42 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self,
10031003
return aq_hw_err_from_flags(self);
10041004
}
10051005

1006+
/**
1007+
* @brief Set VLAN filter table
1008+
* @details Configure VLAN filter table to accept (and assign the queue) traffic
1009+
* for the particular vlan ids.
1010+
* Note: use this function under vlan promisc mode not to lost the traffic
1011+
*
1012+
* @param aq_hw_s
1013+
* @param aq_rx_filter_vlan VLAN filter configuration
1014+
* @return 0 - OK, <0 - error
1015+
*/
1016+
static int hw_atl_b0_hw_vlan_set(struct aq_hw_s *self,
1017+
struct aq_rx_filter_vlan *aq_vlans)
1018+
{
1019+
int i;
1020+
1021+
for (i = 0; i < AQ_VLAN_MAX_FILTERS; i++) {
1022+
hw_atl_rpf_vlan_flr_en_set(self, 0U, i);
1023+
hw_atl_rpf_vlan_rxq_en_flr_set(self, 0U, i);
1024+
if (aq_vlans[i].enable) {
1025+
hw_atl_rpf_vlan_id_flr_set(self,
1026+
aq_vlans[i].vlan_id,
1027+
i);
1028+
hw_atl_rpf_vlan_flr_act_set(self, 1U, i);
1029+
hw_atl_rpf_vlan_flr_en_set(self, 1U, i);
1030+
if (aq_vlans[i].queue != 0xFF) {
1031+
hw_atl_rpf_vlan_rxq_flr_set(self,
1032+
aq_vlans[i].queue,
1033+
i);
1034+
hw_atl_rpf_vlan_rxq_en_flr_set(self, 1U, i);
1035+
}
1036+
}
1037+
}
1038+
1039+
return aq_hw_err_from_flags(self);
1040+
}
1041+
10061042
const struct aq_hw_ops hw_atl_ops_b0 = {
10071043
.hw_set_mac_address = hw_atl_b0_hw_mac_addr_set,
10081044
.hw_init = hw_atl_b0_hw_init,
@@ -1028,6 +1064,7 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
10281064
.hw_ring_tx_init = hw_atl_b0_hw_ring_tx_init,
10291065
.hw_packet_filter_set = hw_atl_b0_hw_packet_filter_set,
10301066
.hw_filter_l3l4_set = hw_atl_b0_hw_fl3l4_set,
1067+
.hw_filter_vlan_set = hw_atl_b0_hw_vlan_set,
10311068
.hw_multicast_list_set = hw_atl_b0_hw_multicast_list_set,
10321069
.hw_interrupt_moderation_set = hw_atl_b0_hw_interrupt_moderation_set,
10331070
.hw_rss_set = hw_atl_b0_hw_rss_set,

drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,13 @@ enum hw_atl_rx_action_with_traffic {
245245
HW_ATL_RX_HOST,
246246
};
247247

248+
struct aq_rx_filter_vlan {
249+
u8 enable;
250+
u8 location;
251+
u16 vlan_id;
252+
u8 queue;
253+
};
254+
248255
struct aq_rx_filter_l3l4 {
249256
u32 cmd;
250257
u8 location;

0 commit comments

Comments
 (0)