Skip to content

Commit 9a8cac4

Browse files
logostdavem330
authored andcommitted
net: aquantia: add ethertype and PCP to rx flow filters
L2 EtherType filters allows to filter packet by EtherType field or both EtherType and User Priority (PCP) field of 802.1Q. UserPriority (vlan) parameter must be accompanied by mask 0x1FFF. 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. Example: To add a filter that directs IP4 packess of priority 3 to queue 3: ethtool -N <ethX> flow-type ether proto 0x800 vlan 0x600 m 0x1FFF \ action 3 loc 16 Signed-off-by: Dmitry Bogdanov <[email protected]> Signed-off-by: Igor Russkikh <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 54bcb3d commit 9a8cac4

File tree

5 files changed

+133
-4
lines changed

5 files changed

+133
-4
lines changed

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

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,30 @@ 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_fl2(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_FETHERT ||
128+
fsp->location > AQ_RX_LAST_LOC_FETHERT) {
129+
netdev_err(aq_nic->ndev,
130+
"ethtool: location must be in range [%d, %d]",
131+
AQ_RX_FIRST_LOC_FETHERT,
132+
AQ_RX_LAST_LOC_FETHERT);
133+
return -EINVAL;
134+
}
135+
136+
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK &&
137+
fsp->m_u.ether_spec.h_proto == 0U) {
138+
netdev_err(aq_nic->ndev,
139+
"ethtool: proto (ether_type) parameter must be specfied");
140+
return -EINVAL;
141+
}
142+
143+
return 0;
144+
}
145+
122146
static int __must_check
123147
aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
124148
struct aq_hw_rx_fltrs_s *rx_fltrs,
@@ -152,6 +176,8 @@ aq_check_filter(struct aq_nic_s *aq_nic,
152176
if (fsp->flow_type & FLOW_EXT) {
153177
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
154178
err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
179+
} else if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK) {
180+
err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
155181
} else {
156182
netdev_err(aq_nic->ndev,
157183
"ethtool: invalid vlan mask 0x%x specified",
@@ -161,7 +187,7 @@ aq_check_filter(struct aq_nic_s *aq_nic,
161187
} else {
162188
switch (fsp->flow_type & ~FLOW_EXT) {
163189
case ETHER_FLOW:
164-
err = -EOPNOTSUPP;
190+
err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
165191
break;
166192
case TCP_V4_FLOW:
167193
case UDP_V4_FLOW:
@@ -210,6 +236,10 @@ aq_rule_is_not_support(struct aq_nic_s *aq_nic,
210236
netdev_err(aq_nic->ndev,
211237
"ethtool: The specified tos tclass are not supported\n");
212238
rule_is_not_support = true;
239+
} else if (fsp->flow_type & FLOW_MAC_EXT) {
240+
netdev_err(aq_nic->ndev,
241+
"ethtool: MAC_EXT is not supported");
242+
rule_is_not_support = true;
213243
}
214244

215245
return rule_is_not_support;
@@ -259,6 +289,48 @@ aq_check_rule(struct aq_nic_s *aq_nic,
259289
return err;
260290
}
261291

292+
static void aq_set_data_fl2(struct aq_nic_s *aq_nic,
293+
struct aq_rx_filter *aq_rx_fltr,
294+
struct aq_rx_filter_l2 *data, bool add)
295+
{
296+
const struct ethtool_rx_flow_spec *fsp = &aq_rx_fltr->aq_fsp;
297+
298+
memset(data, 0, sizeof(*data));
299+
300+
data->location = fsp->location - AQ_RX_FIRST_LOC_FETHERT;
301+
302+
if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
303+
data->queue = fsp->ring_cookie;
304+
else
305+
data->queue = -1;
306+
307+
data->ethertype = be16_to_cpu(fsp->h_u.ether_spec.h_proto);
308+
data->user_priority_en = be16_to_cpu(fsp->m_ext.vlan_tci)
309+
== VLAN_PRIO_MASK;
310+
data->user_priority = (be16_to_cpu(fsp->h_ext.vlan_tci)
311+
& VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
312+
}
313+
314+
static int aq_add_del_fether(struct aq_nic_s *aq_nic,
315+
struct aq_rx_filter *aq_rx_fltr, bool add)
316+
{
317+
struct aq_rx_filter_l2 data;
318+
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
319+
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;
320+
321+
aq_set_data_fl2(aq_nic, aq_rx_fltr, &data, add);
322+
323+
if (unlikely(!aq_hw_ops->hw_filter_l2_set))
324+
return -EOPNOTSUPP;
325+
if (unlikely(!aq_hw_ops->hw_filter_l2_clear))
326+
return -EOPNOTSUPP;
327+
328+
if (add)
329+
return aq_hw_ops->hw_filter_l2_set(aq_hw, &data);
330+
else
331+
return aq_hw_ops->hw_filter_l2_clear(aq_hw, &data);
332+
}
333+
262334
static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
263335
struct aq_rx_filter *aq_rx_fltr,
264336
struct aq_rx_filter_vlan *aq_vlans, bool add)
@@ -424,13 +496,16 @@ static int aq_add_del_rule(struct aq_nic_s *aq_nic,
424496
== VLAN_VID_MASK) {
425497
aq_rx_fltr->type = aq_rx_filter_vlan;
426498
err = aq_add_del_fvlan(aq_nic, aq_rx_fltr, add);
427-
} else {
428-
err = -EINVAL;
499+
} else if (be16_to_cpu(aq_rx_fltr->aq_fsp.m_ext.vlan_tci)
500+
== VLAN_PRIO_MASK) {
501+
aq_rx_fltr->type = aq_rx_filter_ethertype;
502+
err = aq_add_del_fether(aq_nic, aq_rx_fltr, add);
429503
}
430504
} else {
431505
switch (aq_rx_fltr->aq_fsp.flow_type & ~FLOW_EXT) {
432506
case ETHER_FLOW:
433-
err = -EOPNOTSUPP;
507+
aq_rx_fltr->type = aq_rx_filter_ethertype;
508+
err = aq_add_del_fether(aq_nic, aq_rx_fltr, add);
434509
break;
435510
case TCP_V4_FLOW:
436511
case UDP_V4_FLOW:

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

Lines changed: 1 addition & 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_ethertype,
1213
aq_rx_filter_vlan,
1314
aq_rx_filter_l3l4
1415
};

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#define AQ_RX_FIRST_LOC_FVLANID 0U
2222
#define AQ_RX_LAST_LOC_FVLANID 15U
23+
#define AQ_RX_FIRST_LOC_FETHERT 16U
24+
#define AQ_RX_LAST_LOC_FETHERT 31U
2325
#define AQ_RX_FIRST_LOC_FL3L4 32U
2426
#define AQ_RX_LAST_LOC_FL3L4 39U
2527
#define AQ_RX_MAX_RXNFC_LOC AQ_RX_LAST_LOC_FL3L4
@@ -198,6 +200,12 @@ struct aq_hw_ops {
198200
int (*hw_filter_l3l4_clear)(struct aq_hw_s *self,
199201
struct aq_rx_filter_l3l4 *data);
200202

203+
int (*hw_filter_l2_set)(struct aq_hw_s *self,
204+
struct aq_rx_filter_l2 *data);
205+
206+
int (*hw_filter_l2_clear)(struct aq_hw_s *self,
207+
struct aq_rx_filter_l2 *data);
208+
201209
int (*hw_filter_vlan_set)(struct aq_hw_s *self,
202210
struct aq_rx_filter_vlan *aq_vlans);
203211

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,41 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self,
10031003
return aq_hw_err_from_flags(self);
10041004
}
10051005

1006+
static int hw_atl_b0_hw_fl2_set(struct aq_hw_s *self,
1007+
struct aq_rx_filter_l2 *data)
1008+
{
1009+
hw_atl_rpf_etht_flr_en_set(self, 1U, data->location);
1010+
hw_atl_rpf_etht_flr_set(self, data->ethertype, data->location);
1011+
hw_atl_rpf_etht_user_priority_en_set(self,
1012+
!!data->user_priority_en,
1013+
data->location);
1014+
if (data->user_priority_en)
1015+
hw_atl_rpf_etht_user_priority_set(self,
1016+
data->user_priority,
1017+
data->location);
1018+
1019+
if (data->queue < 0) {
1020+
hw_atl_rpf_etht_flr_act_set(self, 0U, data->location);
1021+
hw_atl_rpf_etht_rx_queue_en_set(self, 0U, data->location);
1022+
} else {
1023+
hw_atl_rpf_etht_flr_act_set(self, 1U, data->location);
1024+
hw_atl_rpf_etht_rx_queue_en_set(self, 1U, data->location);
1025+
hw_atl_rpf_etht_rx_queue_set(self, data->queue, data->location);
1026+
}
1027+
1028+
return aq_hw_err_from_flags(self);
1029+
}
1030+
1031+
static int hw_atl_b0_hw_fl2_clear(struct aq_hw_s *self,
1032+
struct aq_rx_filter_l2 *data)
1033+
{
1034+
hw_atl_rpf_etht_flr_en_set(self, 0U, data->location);
1035+
hw_atl_rpf_etht_flr_set(self, 0U, data->location);
1036+
hw_atl_rpf_etht_user_priority_en_set(self, 0U, data->location);
1037+
1038+
return aq_hw_err_from_flags(self);
1039+
}
1040+
10061041
/**
10071042
* @brief Set VLAN filter table
10081043
* @details Configure VLAN filter table to accept (and assign the queue) traffic
@@ -1063,6 +1098,8 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
10631098
.hw_ring_rx_init = hw_atl_b0_hw_ring_rx_init,
10641099
.hw_ring_tx_init = hw_atl_b0_hw_ring_tx_init,
10651100
.hw_packet_filter_set = hw_atl_b0_hw_packet_filter_set,
1101+
.hw_filter_l2_set = hw_atl_b0_hw_fl2_set,
1102+
.hw_filter_l2_clear = hw_atl_b0_hw_fl2_clear,
10661103
.hw_filter_l3l4_set = hw_atl_b0_hw_fl3l4_set,
10671104
.hw_filter_vlan_set = hw_atl_b0_hw_vlan_set,
10681105
.hw_multicast_list_set = hw_atl_b0_hw_multicast_list_set,

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,14 @@ struct aq_rx_filter_vlan {
252252
u8 queue;
253253
};
254254

255+
struct aq_rx_filter_l2 {
256+
s8 queue;
257+
u8 location;
258+
u8 user_priority_en;
259+
u8 user_priority;
260+
u16 ethertype;
261+
};
262+
255263
struct aq_rx_filter_l3l4 {
256264
u32 cmd;
257265
u8 location;

0 commit comments

Comments
 (0)