Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64c75d41 authored by Gangfeng Huang's avatar Gangfeng Huang Committed by Jeff Kirsher
Browse files

igb: support RX flow classification by ethertype



This patch is meant to allow for RX network flow classification to insert
and remove ethertype filter by ethtool

Example:
Add an ethertype filter:
$ ethtool -N eth0 flow-type ether proto 0x88F8 action 2

Show all filters:
$ ethtool -n eth0
4 RX rings available
Total 1 rules

Filter: 15
	Flow Type: Raw Ethernet
	Src MAC addr: 00:00:00:00:00:00 mask: FF:FF:FF:FF:FF:FF
	Dest MAC addr: 00:00:00:00:00:00 mask: FF:FF:FF:FF:FF:FF
	Ethertype: 0x88F8 mask: 0x0
	Action: Direct to queue 2

Delete the filter by location:
$ ethtool -N delete 15

Signed-off-by: default avatarRuhao Gao <ruhao.gao@ni.com>
Signed-off-by: default avatarGangfeng Huang <gangfeng.huang@ni.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 0e71def2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -188,6 +188,11 @@ struct e1000_adv_tx_context_desc {
/* ETQF register bit definitions */
#define E1000_ETQF_FILTER_ENABLE   BIT(26)
#define E1000_ETQF_1588            BIT(30)
#define E1000_ETQF_IMM_INT         BIT(29)
#define E1000_ETQF_QUEUE_ENABLE    BIT(31)
#define E1000_ETQF_QUEUE_SHIFT     16
#define E1000_ETQF_QUEUE_MASK      0x00070000
#define E1000_ETQF_ETYPE_MASK      0x0000FFFF

/* FTQF register bit definitions */
#define E1000_FTQF_VF_BP               0x00008000
+18 −3
Original line number Diff line number Diff line
@@ -350,13 +350,24 @@ struct hwmon_buff {
	};
#endif

/* The number of L2 ether-type filter registers, Index 3 is reserved
 * for PTP 1588 timestamp
 */
#define MAX_ETYPE_FILTER	(4 - 1)
/* ETQF filter list: one static filter per filter consumer. This is
 * to avoid filter collisions later. Add new filters here!!
 *
 * Current filters:		Filter 3
 */
#define IGB_ETQF_FILTER_1588	3

#define IGB_N_EXTTS	2
#define IGB_N_PEROUT	2
#define IGB_N_SDP	4
#define IGB_RETA_SIZE	128

enum igb_filter_match_flags {
	IGB_FILTER_FLAG_NONE = 0x0,
	IGB_FILTER_FLAG_ETHER_TYPE = 0x1,
};

#define IGB_MAX_RXNFC_FILTERS 16
@@ -365,13 +376,16 @@ enum igb_filter_match_flags {
struct igb_nfc_input {
	/* Byte layout in order, all values with MSB first:
	 * match_flags - 1 byte
	 * etype - 2 bytes
	 */
	u8 match_flags;
	__be16 etype;
};

struct igb_nfc_filter {
	struct hlist_node nfc_node;
	struct igb_nfc_input filter;
	u16 etype_reg_index;
	u16 sw_idx;
	u16 action;
};
@@ -500,6 +514,7 @@ struct igb_adapter {
	unsigned int nfc_filter_count;
	/* lock for RX network flow classification filter */
	spinlock_t nfc_lock;
	bool etype_bitmap[MAX_ETYPE_FILTER];
};

/* flags controlling PTP/1588 function */
+76 −1
Original line number Diff line number Diff line
@@ -2431,6 +2431,7 @@ static int igb_get_ts_info(struct net_device *dev,
	}
}

#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
static int igb_get_ethtool_nfc_entry(struct igb_adapter *adapter,
				     struct ethtool_rxnfc *cmd)
{
@@ -2448,6 +2449,13 @@ static int igb_get_ethtool_nfc_entry(struct igb_adapter *adapter,
	if (!rule || fsp->location != rule->sw_idx)
		return -EINVAL;

	if (rule->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE) {
		fsp->flow_type = ETHER_FLOW;
		fsp->ring_cookie = rule->action;
		fsp->h_u.ether_spec.h_proto = rule->filter.etype;
		fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK;
		return 0;
	}
	return -EINVAL;
}

@@ -2650,13 +2658,75 @@ static int igb_set_rss_hash_opt(struct igb_adapter *adapter,
	return 0;
}

int igb_add_filter(struct igb_adapter *adapter, struct igb_nfc_filter *input)
static int igb_rxnfc_write_etype_filter(struct igb_adapter *adapter,
					struct igb_nfc_filter *input)
{
	struct e1000_hw *hw = &adapter->hw;
	u8 i;
	u32 etqf;
	u16 etype;

	/* find an empty etype filter register */
	for (i = 0; i < MAX_ETYPE_FILTER; ++i) {
		if (!adapter->etype_bitmap[i])
			break;
	}
	if (i == MAX_ETYPE_FILTER) {
		dev_err(&adapter->pdev->dev, "ethtool -N: etype filters are all used.\n");
		return -EINVAL;
	}

	adapter->etype_bitmap[i] = true;

	etqf = rd32(E1000_ETQF(i));
	etype = ntohs(input->filter.etype & ETHER_TYPE_FULL_MASK);

	etqf |= E1000_ETQF_FILTER_ENABLE;
	etqf &= ~E1000_ETQF_ETYPE_MASK;
	etqf |= (etype & E1000_ETQF_ETYPE_MASK);

	etqf &= ~E1000_ETQF_QUEUE_MASK;
	etqf |= ((input->action << E1000_ETQF_QUEUE_SHIFT)
		& E1000_ETQF_QUEUE_MASK);
	etqf |= E1000_ETQF_QUEUE_ENABLE;

	wr32(E1000_ETQF(i), etqf);

	input->etype_reg_index = i;

	return 0;
}

int igb_add_filter(struct igb_adapter *adapter, struct igb_nfc_filter *input)
{
	int err = -EINVAL;

	if (input->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE)
		err = igb_rxnfc_write_etype_filter(adapter, input);

	return err;
}

static void igb_clear_etype_filter_regs(struct igb_adapter *adapter,
					u16 reg_index)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 etqf = rd32(E1000_ETQF(reg_index));

	etqf &= ~E1000_ETQF_QUEUE_ENABLE;
	etqf &= ~E1000_ETQF_QUEUE_MASK;
	etqf &= ~E1000_ETQF_FILTER_ENABLE;

	wr32(E1000_ETQF(reg_index), etqf);

	adapter->etype_bitmap[reg_index] = false;
}

int igb_erase_filter(struct igb_adapter *adapter, struct igb_nfc_filter *input)
{
	if (input->filter.match_flags & IGB_FILTER_FLAG_ETHER_TYPE)
		igb_clear_etype_filter_regs(adapter,
					    input->etype_reg_index);
	return 0;
}

@@ -2738,10 +2808,15 @@ static int igb_add_ethtool_nfc_entry(struct igb_adapter *adapter,
	if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW)
		return -EINVAL;

	if (fsp->m_u.ether_spec.h_proto != ETHER_TYPE_FULL_MASK)
		return -EINVAL;

	input = kzalloc(sizeof(*input), GFP_KERNEL);
	if (!input)
		return -ENOMEM;

	input->filter.etype = fsp->h_u.ether_spec.h_proto;
	input->filter.match_flags = IGB_FILTER_FLAG_ETHER_TYPE;
	input->action = fsp->ring_cookie;
	input->sw_idx = fsp->location;

+2 −2
Original line number Diff line number Diff line
@@ -998,12 +998,12 @@ static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter,

	/* define ethertype filter for timestamped packets */
	if (is_l2)
		wr32(E1000_ETQF(3),
		wr32(E1000_ETQF(IGB_ETQF_FILTER_1588),
		     (E1000_ETQF_FILTER_ENABLE | /* enable filter */
		      E1000_ETQF_1588 | /* enable timestamping */
		      ETH_P_1588));     /* 1588 eth protocol type */
	else
		wr32(E1000_ETQF(3), 0);
		wr32(E1000_ETQF(IGB_ETQF_FILTER_1588), 0);

	/* L4 Queue Filter[3]: filter by destination port and protocol */
	if (is_l4) {