Skip to content

Commit

Permalink
net: aquantia: add ethertype and PCP to rx flow filters
Browse files Browse the repository at this point in the history
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 <dmitry.bogdanov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Dmitry Bogdanov authored and David S. Miller committed Nov 14, 2018
1 parent 54bcb3d commit 9a8cac4
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 4 deletions.
83 changes: 79 additions & 4 deletions drivers/net/ethernet/aquantia/atlantic/aq_filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,30 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
return 0;
}

static int __must_check
aq_check_approve_fl2(struct aq_nic_s *aq_nic,
struct aq_hw_rx_fltrs_s *rx_fltrs,
struct ethtool_rx_flow_spec *fsp)
{
if (fsp->location < AQ_RX_FIRST_LOC_FETHERT ||
fsp->location > AQ_RX_LAST_LOC_FETHERT) {
netdev_err(aq_nic->ndev,
"ethtool: location must be in range [%d, %d]",
AQ_RX_FIRST_LOC_FETHERT,
AQ_RX_LAST_LOC_FETHERT);
return -EINVAL;
}

if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK &&
fsp->m_u.ether_spec.h_proto == 0U) {
netdev_err(aq_nic->ndev,
"ethtool: proto (ether_type) parameter must be specfied");
return -EINVAL;
}

return 0;
}

static int __must_check
aq_check_approve_fvlan(struct aq_nic_s *aq_nic,
struct aq_hw_rx_fltrs_s *rx_fltrs,
Expand Down Expand Up @@ -152,6 +176,8 @@ aq_check_filter(struct aq_nic_s *aq_nic,
if (fsp->flow_type & FLOW_EXT) {
if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_VID_MASK) {
err = aq_check_approve_fvlan(aq_nic, rx_fltrs, fsp);
} else if (be16_to_cpu(fsp->m_ext.vlan_tci) == VLAN_PRIO_MASK) {
err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
} else {
netdev_err(aq_nic->ndev,
"ethtool: invalid vlan mask 0x%x specified",
Expand All @@ -161,7 +187,7 @@ aq_check_filter(struct aq_nic_s *aq_nic,
} else {
switch (fsp->flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
err = -EOPNOTSUPP;
err = aq_check_approve_fl2(aq_nic, rx_fltrs, fsp);
break;
case TCP_V4_FLOW:
case UDP_V4_FLOW:
Expand Down Expand Up @@ -210,6 +236,10 @@ aq_rule_is_not_support(struct aq_nic_s *aq_nic,
netdev_err(aq_nic->ndev,
"ethtool: The specified tos tclass are not supported\n");
rule_is_not_support = true;
} else if (fsp->flow_type & FLOW_MAC_EXT) {
netdev_err(aq_nic->ndev,
"ethtool: MAC_EXT is not supported");
rule_is_not_support = true;
}

return rule_is_not_support;
Expand Down Expand Up @@ -259,6 +289,48 @@ aq_check_rule(struct aq_nic_s *aq_nic,
return err;
}

static void aq_set_data_fl2(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr,
struct aq_rx_filter_l2 *data, bool add)
{
const struct ethtool_rx_flow_spec *fsp = &aq_rx_fltr->aq_fsp;

memset(data, 0, sizeof(*data));

data->location = fsp->location - AQ_RX_FIRST_LOC_FETHERT;

if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
data->queue = fsp->ring_cookie;
else
data->queue = -1;

data->ethertype = be16_to_cpu(fsp->h_u.ether_spec.h_proto);
data->user_priority_en = be16_to_cpu(fsp->m_ext.vlan_tci)
== VLAN_PRIO_MASK;
data->user_priority = (be16_to_cpu(fsp->h_ext.vlan_tci)
& VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
}

static int aq_add_del_fether(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr, bool add)
{
struct aq_rx_filter_l2 data;
struct aq_hw_s *aq_hw = aq_nic->aq_hw;
const struct aq_hw_ops *aq_hw_ops = aq_nic->aq_hw_ops;

aq_set_data_fl2(aq_nic, aq_rx_fltr, &data, add);

if (unlikely(!aq_hw_ops->hw_filter_l2_set))
return -EOPNOTSUPP;
if (unlikely(!aq_hw_ops->hw_filter_l2_clear))
return -EOPNOTSUPP;

if (add)
return aq_hw_ops->hw_filter_l2_set(aq_hw, &data);
else
return aq_hw_ops->hw_filter_l2_clear(aq_hw, &data);
}

static int aq_set_data_fvlan(struct aq_nic_s *aq_nic,
struct aq_rx_filter *aq_rx_fltr,
struct aq_rx_filter_vlan *aq_vlans, bool add)
Expand Down Expand Up @@ -424,13 +496,16 @@ static int aq_add_del_rule(struct aq_nic_s *aq_nic,
== VLAN_VID_MASK) {
aq_rx_fltr->type = aq_rx_filter_vlan;
err = aq_add_del_fvlan(aq_nic, aq_rx_fltr, add);
} else {
err = -EINVAL;
} else if (be16_to_cpu(aq_rx_fltr->aq_fsp.m_ext.vlan_tci)
== VLAN_PRIO_MASK) {
aq_rx_fltr->type = aq_rx_filter_ethertype;
err = aq_add_del_fether(aq_nic, aq_rx_fltr, add);
}
} else {
switch (aq_rx_fltr->aq_fsp.flow_type & ~FLOW_EXT) {
case ETHER_FLOW:
err = -EOPNOTSUPP;
aq_rx_fltr->type = aq_rx_filter_ethertype;
err = aq_add_del_fether(aq_nic, aq_rx_fltr, add);
break;
case TCP_V4_FLOW:
case UDP_V4_FLOW:
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_filters.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "aq_nic.h"

enum aq_rx_filter_type {
aq_rx_filter_ethertype,
aq_rx_filter_vlan,
aq_rx_filter_l3l4
};
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#define AQ_RX_FIRST_LOC_FVLANID 0U
#define AQ_RX_LAST_LOC_FVLANID 15U
#define AQ_RX_FIRST_LOC_FETHERT 16U
#define AQ_RX_LAST_LOC_FETHERT 31U
#define AQ_RX_FIRST_LOC_FL3L4 32U
#define AQ_RX_LAST_LOC_FL3L4 39U
#define AQ_RX_MAX_RXNFC_LOC AQ_RX_LAST_LOC_FL3L4
Expand Down Expand Up @@ -198,6 +200,12 @@ struct aq_hw_ops {
int (*hw_filter_l3l4_clear)(struct aq_hw_s *self,
struct aq_rx_filter_l3l4 *data);

int (*hw_filter_l2_set)(struct aq_hw_s *self,
struct aq_rx_filter_l2 *data);

int (*hw_filter_l2_clear)(struct aq_hw_s *self,
struct aq_rx_filter_l2 *data);

int (*hw_filter_vlan_set)(struct aq_hw_s *self,
struct aq_rx_filter_vlan *aq_vlans);

Expand Down
37 changes: 37 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,41 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self,
return aq_hw_err_from_flags(self);
}

static int hw_atl_b0_hw_fl2_set(struct aq_hw_s *self,
struct aq_rx_filter_l2 *data)
{
hw_atl_rpf_etht_flr_en_set(self, 1U, data->location);
hw_atl_rpf_etht_flr_set(self, data->ethertype, data->location);
hw_atl_rpf_etht_user_priority_en_set(self,
!!data->user_priority_en,
data->location);
if (data->user_priority_en)
hw_atl_rpf_etht_user_priority_set(self,
data->user_priority,
data->location);

if (data->queue < 0) {
hw_atl_rpf_etht_flr_act_set(self, 0U, data->location);
hw_atl_rpf_etht_rx_queue_en_set(self, 0U, data->location);
} else {
hw_atl_rpf_etht_flr_act_set(self, 1U, data->location);
hw_atl_rpf_etht_rx_queue_en_set(self, 1U, data->location);
hw_atl_rpf_etht_rx_queue_set(self, data->queue, data->location);
}

return aq_hw_err_from_flags(self);
}

static int hw_atl_b0_hw_fl2_clear(struct aq_hw_s *self,
struct aq_rx_filter_l2 *data)
{
hw_atl_rpf_etht_flr_en_set(self, 0U, data->location);
hw_atl_rpf_etht_flr_set(self, 0U, data->location);
hw_atl_rpf_etht_user_priority_en_set(self, 0U, data->location);

return aq_hw_err_from_flags(self);
}

/**
* @brief Set VLAN filter table
* @details Configure VLAN filter table to accept (and assign the queue) traffic
Expand Down Expand Up @@ -1063,6 +1098,8 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_ring_rx_init = hw_atl_b0_hw_ring_rx_init,
.hw_ring_tx_init = hw_atl_b0_hw_ring_tx_init,
.hw_packet_filter_set = hw_atl_b0_hw_packet_filter_set,
.hw_filter_l2_set = hw_atl_b0_hw_fl2_set,
.hw_filter_l2_clear = hw_atl_b0_hw_fl2_clear,
.hw_filter_l3l4_set = hw_atl_b0_hw_fl3l4_set,
.hw_filter_vlan_set = hw_atl_b0_hw_vlan_set,
.hw_multicast_list_set = hw_atl_b0_hw_multicast_list_set,
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@ struct aq_rx_filter_vlan {
u8 queue;
};

struct aq_rx_filter_l2 {
s8 queue;
u8 location;
u8 user_priority_en;
u8 user_priority;
u16 ethertype;
};

struct aq_rx_filter_l3l4 {
u32 cmd;
u8 location;
Expand Down

0 comments on commit 9a8cac4

Please sign in to comment.