From mboxrd@z Thu Jan 1 00:00:00 1970 From: Gangfeng Date: Wed, 24 Feb 2016 17:06:22 +0800 Subject: [Intel-wired-lan] [PATCH 2/3] igb: add support of ethertype RX filters In-Reply-To: <1456304783-15019-1-git-send-email-gangfeng.huang@ni.com> References: <1456304783-15019-1-git-send-email-gangfeng.huang@ni.com> Message-ID: <1456304783-15019-2-git-send-email-gangfeng.huang@ni.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: intel-wired-lan@osuosl.org List-ID: From: Gangfeng Huang This patch is meant to allow for nfc 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: Ruhao Gao Signed-off-by: Gangfeng Huang --- drivers/net/ethernet/intel/igb/e1000_82575.h | 5 ++ drivers/net/ethernet/intel/igb/igb.h | 20 ++++++- drivers/net/ethernet/intel/igb/igb_ethtool.c | 77 +++++++++++++++++++++++++- drivers/net/ethernet/intel/igb/igb_ptp.c | 4 +- 4 files changed, 102 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index de8805a..6992f63 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -187,7 +187,12 @@ struct e1000_adv_tx_context_desc { /* ETQF register bit definitions */ #define E1000_ETQF_FILTER_ENABLE (1 << 26) +#define E1000_ETQF_IMM_INT (1 << 29) #define E1000_ETQF_1588 (1 << 30) +#define E1000_ETQF_QUEUE_ENABLE (1 << 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 diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 32ddf43..204cffc 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -347,13 +347,27 @@ 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: + * 1588 (0x88f7): 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 @@ -361,8 +375,10 @@ 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; }; /* board specific private data structure */ @@ -498,11 +514,13 @@ struct igb_adapter { unsigned int nfc_filter_count; /* lock for nfc filter */ spinlock_t nfc_lock; + bool etype_bitmap[MAX_ETYPE_FILTER]; }; struct igb_nfc_filter { struct hlist_node nfc_node; struct igb_nfc_input filter; + u16 etype_reg_index; u16 sw_idx; u16 action; }; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 1dd29f8..a30506c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2607,6 +2607,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) { @@ -2624,6 +2625,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; } @@ -2826,13 +2834,75 @@ static int igb_set_rss_hash_opt(struct igb_adapter *adapter, return 0; } +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) { - return -EINVAL; + 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; } @@ -2914,10 +2984,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; diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 22a8a29..e92c57d 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -941,12 +941,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) { -- 1.7.9.5