Blob Blame History Raw
From: Andre Guedes <andre.guedes@intel.com>
Date: Fri, 24 Apr 2020 13:16:10 -0700
Subject: igc: Align terms used in NFC support code
Patch-mainline: v5.8-rc1
Git-commit: 97700bc86d068442ee19ca6d31fc0a600cdbd672
References: jsc#SLE-13533

The Network Flow Classification (NFC) support code from IGC driver uses
terms such as 'rule', 'filter', 'entry', 'input' interchangeably when
referring to NFC rules, making it harder to follow the code. This patch
renames IGC's internal APIs, structs, and variables so we stick with the
term 'rule' since this is the term used in ethtool APIs. It also removes
some not applicable comments along the way. No functionality is changed
by this patch.

Signed-off-by: Andre Guedes <andre.guedes@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 drivers/net/ethernet/intel/igc/igc.h         |   29 ++--
 drivers/net/ethernet/intel/igc/igc_ethtool.c |  160 +++++++++++++--------------
 drivers/net/ethernet/intel/igc/igc_main.c    |   42 +++----
 3 files changed, 114 insertions(+), 117 deletions(-)

--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -187,12 +187,12 @@ struct igc_adapter {
 	u32 rss_queues;
 	u32 rss_indir_tbl_init;
 
-	/* RX network flow classification support */
-	struct hlist_head nfc_filter_list;
-	unsigned int nfc_filter_count;
-
-	/* lock for RX network flow classification filter */
-	spinlock_t nfc_lock;
+	/* Any access to elements in nfc_rule_list is protected by the
+	 * nfc_rule_lock.
+	 */
+	spinlock_t nfc_rule_lock;
+	struct hlist_head nfc_rule_list;
+	unsigned int nfc_rule_count;
 
 	u8 rss_indir_tbl[IGC_RETA_SIZE];
 
@@ -453,7 +453,7 @@ enum igc_filter_match_flags {
 };
 
 /* RX network flow classification data structure */
-struct igc_nfc_input {
+struct igc_nfc_filter {
 	/* Byte layout in order, all values with MSB first:
 	 * match_flags - 1 byte
 	 * etype - 2 bytes
@@ -466,14 +466,14 @@ struct igc_nfc_input {
 	u8 dst_addr[ETH_ALEN];
 };
 
-struct igc_nfc_filter {
+struct igc_nfc_rule {
 	struct hlist_node nfc_node;
-	struct igc_nfc_input filter;
+	struct igc_nfc_filter filter;
 	u16 sw_idx;
 	u16 action;
 };
 
-#define IGC_MAX_RXNFC_FILTERS		16
+#define IGC_MAX_RXNFC_RULES		16
 
 /* igc_desc_unused - calculate if we have unused descriptors */
 static inline u16 igc_desc_unused(const struct igc_ring *ring)
@@ -549,12 +549,11 @@ static inline s32 igc_read_phy_reg(struc
 	return 0;
 }
 
-/* forward declaration */
 void igc_reinit_locked(struct igc_adapter *);
-int igc_add_filter(struct igc_adapter *adapter,
-		   struct igc_nfc_filter *input);
-int igc_erase_filter(struct igc_adapter *adapter,
-		     struct igc_nfc_filter *input);
+int igc_enable_nfc_rule(struct igc_adapter *adapter,
+			const struct igc_nfc_rule *rule);
+int igc_disable_nfc_rule(struct igc_adapter *adapter,
+			 const struct igc_nfc_rule *rule);
 
 void igc_ptp_init(struct igc_adapter *adapter);
 void igc_ptp_reset(struct igc_adapter *adapter);
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -931,16 +931,15 @@ static int igc_ethtool_set_coalesce(stru
 }
 
 #define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
-static int igc_ethtool_get_nfc_entry(struct igc_adapter *adapter,
-				     struct ethtool_rxnfc *cmd)
+static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter,
+				    struct ethtool_rxnfc *cmd)
 {
 	struct ethtool_rx_flow_spec *fsp = &cmd->fs;
-	struct igc_nfc_filter *rule = NULL;
+	struct igc_nfc_rule *rule = NULL;
 
-	/* report total rule count */
-	cmd->data = IGC_MAX_RXNFC_FILTERS;
+	cmd->data = IGC_MAX_RXNFC_RULES;
 
-	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
+	hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) {
 		if (fsp->location <= rule->sw_idx)
 			break;
 	}
@@ -980,17 +979,16 @@ static int igc_ethtool_get_nfc_entry(str
 	return 0;
 }
 
-static int igc_ethtool_get_nfc_all(struct igc_adapter *adapter,
-				   struct ethtool_rxnfc *cmd,
-				   u32 *rule_locs)
+static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter,
+				     struct ethtool_rxnfc *cmd,
+				     u32 *rule_locs)
 {
-	struct igc_nfc_filter *rule;
+	struct igc_nfc_rule *rule;
 	int cnt = 0;
 
-	/* report total rule count */
-	cmd->data = IGC_MAX_RXNFC_FILTERS;
+	cmd->data = IGC_MAX_RXNFC_RULES;
 
-	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
+	hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) {
 		if (cnt == cmd->rule_cnt)
 			return -EMSGSIZE;
 		rule_locs[cnt] = rule->sw_idx;
@@ -1062,12 +1060,12 @@ static int igc_ethtool_get_rxnfc(struct
 		cmd->data = adapter->num_rx_queues;
 		return 0;
 	case ETHTOOL_GRXCLSRLCNT:
-		cmd->rule_cnt = adapter->nfc_filter_count;
+		cmd->rule_cnt = adapter->nfc_rule_count;
 		return 0;
 	case ETHTOOL_GRXCLSRULE:
-		return igc_ethtool_get_nfc_entry(adapter, cmd);
+		return igc_ethtool_get_nfc_rule(adapter, cmd);
 	case ETHTOOL_GRXCLSRLALL:
-		return igc_ethtool_get_nfc_all(adapter, cmd, rule_locs);
+		return igc_ethtool_get_nfc_rules(adapter, cmd, rule_locs);
 	case ETHTOOL_GRXFH:
 		return igc_ethtool_get_rss_hash_opts(adapter, cmd);
 	default:
@@ -1179,38 +1177,37 @@ static int igc_ethtool_set_rss_hash_opt(
 	return 0;
 }
 
-int igc_add_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input)
+int igc_enable_nfc_rule(struct igc_adapter *adapter,
+			const struct igc_nfc_rule *rule)
 {
 	int err = -EINVAL;
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
-		u16 etype = ntohs(input->filter.etype);
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
+		u16 etype = ntohs(rule->filter.etype);
 
-		err = igc_add_etype_filter(adapter, etype, input->action);
+		err = igc_add_etype_filter(adapter, etype, rule->action);
 		if (err)
 			return err;
 	}
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
 		err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC,
-					 input->filter.src_addr,
-					 input->action);
+					 rule->filter.src_addr, rule->action);
 		if (err)
 			return err;
 	}
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
 		err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST,
-					 input->filter.dst_addr,
-					 input->action);
+					 rule->filter.dst_addr, rule->action);
 		if (err)
 			return err;
 	}
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
-		int prio = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK) >>
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
+		int prio = (ntohs(rule->filter.vlan_tci) & VLAN_PRIO_MASK) >>
 			   VLAN_PRIO_SHIFT;
-		err = igc_add_vlan_prio_filter(adapter, prio, input->action);
+		err = igc_add_vlan_prio_filter(adapter, prio, rule->action);
 		if (err)
 			return err;
 	}
@@ -1218,42 +1215,43 @@ int igc_add_filter(struct igc_adapter *a
 	return 0;
 }
 
-int igc_erase_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input)
+int igc_disable_nfc_rule(struct igc_adapter *adapter,
+			 const struct igc_nfc_rule *rule)
 {
-	if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
-		u16 etype = ntohs(input->filter.etype);
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
+		u16 etype = ntohs(rule->filter.etype);
 
 		igc_del_etype_filter(adapter, etype);
 	}
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
-		int prio = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK) >>
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
+		int prio = (ntohs(rule->filter.vlan_tci) & VLAN_PRIO_MASK) >>
 			   VLAN_PRIO_SHIFT;
 		igc_del_vlan_prio_filter(adapter, prio);
 	}
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR)
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR)
 		igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC,
-				   input->filter.src_addr);
+				   rule->filter.src_addr);
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR)
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR)
 		igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST,
-				   input->filter.dst_addr);
+				   rule->filter.dst_addr);
 
 	return 0;
 }
 
-static int igc_ethtool_update_nfc_entry(struct igc_adapter *adapter,
-					struct igc_nfc_filter *input,
-					u16 sw_idx)
+static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter,
+				       struct igc_nfc_rule *input,
+				       u16 sw_idx)
 {
-	struct igc_nfc_filter *rule, *parent;
+	struct igc_nfc_rule *rule, *parent;
 	int err = -EINVAL;
 
 	parent = NULL;
 	rule = NULL;
 
-	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
+	hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) {
 		/* hash found, or no matching entry */
 		if (rule->sw_idx >= sw_idx)
 			break;
@@ -1263,11 +1261,11 @@ static int igc_ethtool_update_nfc_entry(
 	/* if there is an old rule occupying our place remove it */
 	if (rule && rule->sw_idx == sw_idx) {
 		if (!input)
-			err = igc_erase_filter(adapter, rule);
+			err = igc_disable_nfc_rule(adapter, rule);
 
 		hlist_del(&rule->nfc_node);
 		kfree(rule);
-		adapter->nfc_filter_count--;
+		adapter->nfc_rule_count--;
 	}
 
 	/* If no input this was a delete, err should be 0 if a rule was
@@ -1283,21 +1281,21 @@ static int igc_ethtool_update_nfc_entry(
 	if (parent)
 		hlist_add_behind(&input->nfc_node, &parent->nfc_node);
 	else
-		hlist_add_head(&input->nfc_node, &adapter->nfc_filter_list);
+		hlist_add_head(&input->nfc_node, &adapter->nfc_rule_list);
 
 	/* update counts */
-	adapter->nfc_filter_count++;
+	adapter->nfc_rule_count++;
 
 	return 0;
 }
 
-static int igc_ethtool_add_nfc_entry(struct igc_adapter *adapter,
-				     struct ethtool_rxnfc *cmd)
+static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter,
+				    struct ethtool_rxnfc *cmd)
 {
 	struct net_device *netdev = adapter->netdev;
 	struct ethtool_rx_flow_spec *fsp =
 		(struct ethtool_rx_flow_spec *)&cmd->fs;
-	struct igc_nfc_filter *input, *rule;
+	struct igc_nfc_rule *rule, *tmp;
 	int err = 0;
 
 	if (!(netdev->hw_features & NETIF_F_NTUPLE))
@@ -1314,7 +1312,7 @@ static int igc_ethtool_add_nfc_entry(str
 	}
 
 	/* Don't allow indexes to exist outside of available space */
-	if (fsp->location >= IGC_MAX_RXNFC_FILTERS) {
+	if (fsp->location >= IGC_MAX_RXNFC_RULES) {
 		netdev_err(netdev, "Location out of range\n");
 		return -EINVAL;
 	}
@@ -1322,32 +1320,32 @@ static int igc_ethtool_add_nfc_entry(str
 	if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW)
 		return -EINVAL;
 
-	input = kzalloc(sizeof(*input), GFP_KERNEL);
-	if (!input)
+	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+	if (!rule)
 		return -ENOMEM;
 
 	if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) {
-		input->filter.etype = fsp->h_u.ether_spec.h_proto;
-		input->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE;
+		rule->filter.etype = fsp->h_u.ether_spec.h_proto;
+		rule->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE;
 	}
 
 	/* Both source and destination address filters only support the full
 	 * mask.
 	 */
 	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) {
-		input->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR;
-		ether_addr_copy(input->filter.src_addr,
+		rule->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR;
+		ether_addr_copy(rule->filter.src_addr,
 				fsp->h_u.ether_spec.h_source);
 	}
 
 	if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) {
-		input->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR;
-		ether_addr_copy(input->filter.dst_addr,
+		rule->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR;
+		ether_addr_copy(rule->filter.dst_addr,
 				fsp->h_u.ether_spec.h_dest);
 	}
 
-	if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR &&
-	    input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
+	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR &&
+	    rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
 		netdev_dbg(netdev, "Filters with both dst and src are not supported\n");
 		err = -EOPNOTSUPP;
 		goto err_out;
@@ -1359,18 +1357,18 @@ static int igc_ethtool_add_nfc_entry(str
 			err = -EOPNOTSUPP;
 			goto err_out;
 		}
-		input->filter.vlan_tci = fsp->h_ext.vlan_tci;
-		input->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI;
+		rule->filter.vlan_tci = fsp->h_ext.vlan_tci;
+		rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI;
 	}
 
-	input->action = fsp->ring_cookie;
-	input->sw_idx = fsp->location;
+	rule->action = fsp->ring_cookie;
+	rule->sw_idx = fsp->location;
 
-	spin_lock(&adapter->nfc_lock);
+	spin_lock(&adapter->nfc_rule_lock);
 
-	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
-		if (!memcmp(&input->filter, &rule->filter,
-			    sizeof(input->filter))) {
+	hlist_for_each_entry(tmp, &adapter->nfc_rule_list, nfc_node) {
+		if (!memcmp(&rule->filter, &tmp->filter,
+			    sizeof(rule->filter))) {
 			err = -EEXIST;
 			netdev_err(netdev,
 				   "ethtool: this filter is already set\n");
@@ -1378,32 +1376,32 @@ static int igc_ethtool_add_nfc_entry(str
 		}
 	}
 
-	err = igc_add_filter(adapter, input);
+	err = igc_enable_nfc_rule(adapter, rule);
 	if (err)
 		goto err_out_w_lock;
 
-	igc_ethtool_update_nfc_entry(adapter, input, input->sw_idx);
+	igc_ethtool_update_nfc_rule(adapter, rule, rule->sw_idx);
 
-	spin_unlock(&adapter->nfc_lock);
+	spin_unlock(&adapter->nfc_rule_lock);
 	return 0;
 
 err_out_w_lock:
-	spin_unlock(&adapter->nfc_lock);
+	spin_unlock(&adapter->nfc_rule_lock);
 err_out:
-	kfree(input);
+	kfree(rule);
 	return err;
 }
 
-static int igc_ethtool_del_nfc_entry(struct igc_adapter *adapter,
-				     struct ethtool_rxnfc *cmd)
+static int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter,
+				    struct ethtool_rxnfc *cmd)
 {
 	struct ethtool_rx_flow_spec *fsp =
 		(struct ethtool_rx_flow_spec *)&cmd->fs;
 	int err;
 
-	spin_lock(&adapter->nfc_lock);
-	err = igc_ethtool_update_nfc_entry(adapter, NULL, fsp->location);
-	spin_unlock(&adapter->nfc_lock);
+	spin_lock(&adapter->nfc_rule_lock);
+	err = igc_ethtool_update_nfc_rule(adapter, NULL, fsp->location);
+	spin_unlock(&adapter->nfc_rule_lock);
 
 	return err;
 }
@@ -1417,9 +1415,9 @@ static int igc_ethtool_set_rxnfc(struct
 	case ETHTOOL_SRXFH:
 		return igc_ethtool_set_rss_hash_opt(adapter, cmd);
 	case ETHTOOL_SRXCLSRLINS:
-		return igc_ethtool_add_nfc_entry(adapter, cmd);
+		return igc_ethtool_add_nfc_rule(adapter, cmd);
 	case ETHTOOL_SRXCLSRLDEL:
-		return igc_ethtool_del_nfc_entry(adapter, cmd);
+		return igc_ethtool_del_nfc_rule(adapter, cmd);
 	default:
 		return -EOPNOTSUPP;
 	}
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -2174,16 +2174,16 @@ static bool igc_clean_tx_irq(struct igc_
 	return !!budget;
 }
 
-static void igc_nfc_filter_restore(struct igc_adapter *adapter)
+static void igc_restore_nfc_rules(struct igc_adapter *adapter)
 {
-	struct igc_nfc_filter *rule;
+	struct igc_nfc_rule *rule;
 
-	spin_lock(&adapter->nfc_lock);
+	spin_lock(&adapter->nfc_rule_lock);
 
-	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node)
-		igc_add_filter(adapter, rule);
+	hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node)
+		igc_enable_nfc_rule(adapter, rule);
 
-	spin_unlock(&adapter->nfc_lock);
+	spin_unlock(&adapter->nfc_rule_lock);
 }
 
 static int igc_find_mac_filter(struct igc_adapter *adapter,
@@ -2537,7 +2537,7 @@ static void igc_configure(struct igc_ada
 	igc_setup_rctl(adapter);
 
 	igc_set_default_mac_filter(adapter);
-	igc_nfc_filter_restore(adapter);
+	igc_restore_nfc_rules(adapter);
 
 	igc_configure_tx(adapter);
 	igc_configure_rx(adapter);
@@ -3424,7 +3424,7 @@ static int igc_sw_init(struct igc_adapte
 				VLAN_HLEN;
 	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
-	spin_lock_init(&adapter->nfc_lock);
+	spin_lock_init(&adapter->nfc_rule_lock);
 	spin_lock_init(&adapter->stats64_lock);
 	/* Assume MSI-X interrupts, will be checked during IRQ allocation */
 	adapter->flags |= IGC_FLAG_HAS_MSIX;
@@ -3651,16 +3651,16 @@ void igc_update_stats(struct igc_adapter
 	adapter->stats.mgpdc += rd32(IGC_MGTPDC);
 }
 
-static void igc_nfc_filter_exit(struct igc_adapter *adapter)
+static void igc_nfc_rule_exit(struct igc_adapter *adapter)
 {
-	struct igc_nfc_filter *rule;
+	struct igc_nfc_rule *rule;
 
-	spin_lock(&adapter->nfc_lock);
+	spin_lock(&adapter->nfc_rule_lock);
 
-	hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node)
-		igc_erase_filter(adapter, rule);
+	hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node)
+		igc_disable_nfc_rule(adapter, rule);
 
-	spin_unlock(&adapter->nfc_lock);
+	spin_unlock(&adapter->nfc_rule_lock);
 }
 
 /**
@@ -3681,7 +3681,7 @@ void igc_down(struct igc_adapter *adapte
 	wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
 	/* flush and sleep below */
 
-	igc_nfc_filter_exit(adapter);
+	igc_nfc_rule_exit(adapter);
 
 	/* set trans_start so we don't get spurious watchdogs during reset */
 	netif_trans_update(netdev);
@@ -3833,17 +3833,17 @@ static int igc_set_features(struct net_d
 
 	if (!(features & NETIF_F_NTUPLE)) {
 		struct hlist_node *node2;
-		struct igc_nfc_filter *rule;
+		struct igc_nfc_rule *rule;
 
-		spin_lock(&adapter->nfc_lock);
+		spin_lock(&adapter->nfc_rule_lock);
 		hlist_for_each_entry_safe(rule, node2,
-					  &adapter->nfc_filter_list, nfc_node) {
-			igc_erase_filter(adapter, rule);
+					  &adapter->nfc_rule_list, nfc_node) {
+			igc_disable_nfc_rule(adapter, rule);
 			hlist_del(&rule->nfc_node);
 			kfree(rule);
 		}
-		spin_unlock(&adapter->nfc_lock);
-		adapter->nfc_filter_count = 0;
+		spin_unlock(&adapter->nfc_rule_lock);
+		adapter->nfc_rule_count = 0;
 	}
 
 	netdev->features = features;