Commit 36fa2152 authored by Andre Guedes's avatar Andre Guedes Committed by Jeff Kirsher
Browse files

igc: Refactor igc_ethtool_update_nfc_rule()



Current implementation of igc_ethtool_update_nfc_rule() is a bit
convoluted since it handles too many things: rule lookup, deletion
and addition. This patch breaks it into three functions so we simplify
the code and improve code reuse.

Code related to rule lookup is refactored out to a new function called
igc_get_nfc_rule().

Code related to rule addition is refactored out to a new function called
igc_add_nfc_rule(). This function enables the rule in hardware and adds
it to the adapter's list.

Code related to rule deletion is refactored out to a new function called
igc_del_nfc_rule(). This function disables the rule in hardware, removes
it from adapter's list, and deletes it.

As a byproduct of this refactoring, igc_enable_nfc_rule() and
igc_disable_nfc_rule() are moved to igc_main.c since they are not used
in igc_ethtool.c anymore, and igc_restore_nfc_rules() and igc_nfc_rule_
exit() are moved around to avoid forward declaration.

Also, since this patch already touches igc_ethtool_get_nfc_rule(), it
takes the opportunity to remove the 'match_flags' check. Empty flags
are not allowed to be added so no need to check that.

Signed-off-by: default avatarAndre Guedes <andre.guedes@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent d957c601
Loading
Loading
Loading
Loading
+4 −14
Original line number Diff line number Diff line
@@ -232,16 +232,6 @@ void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
bool igc_has_link(struct igc_adapter *adapter);
void igc_reset(struct igc_adapter *adapter);
int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx);
int igc_add_mac_filter(struct igc_adapter *adapter,
		       enum igc_mac_filter_type type, const u8 *addr,
		       int queue);
int igc_del_mac_filter(struct igc_adapter *adapter,
		       enum igc_mac_filter_type type, const u8 *addr);
int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio,
			     int queue);
void igc_del_vlan_prio_filter(struct igc_adapter *adapter, int prio);
int igc_add_etype_filter(struct igc_adapter *adapter, u16 etype, int queue);
int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype);
void igc_update_stats(struct igc_adapter *adapter);

/* igc_dump declarations */
@@ -544,10 +534,10 @@ static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data)
}

void igc_reinit_locked(struct igc_adapter *);
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);
struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter,
				      u32 location);
int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);

void igc_ptp_init(struct igc_adapter *adapter);
void igc_ptp_reset(struct igc_adapter *adapter);
+19 −119
Original line number Diff line number Diff line
@@ -941,15 +941,8 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter,

	spin_lock(&adapter->nfc_rule_lock);

	list_for_each_entry(rule, &adapter->nfc_rule_list, list) {
		if (fsp->location <= rule->location)
			break;
	}

	if (!rule || fsp->location != rule->location)
		goto out;

	if (!rule->filter.match_flags)
	rule = igc_get_nfc_rule(adapter, fsp->location);
	if (!rule)
		goto out;

	fsp->flow_type = ETHER_FLOW;
@@ -1190,108 +1183,6 @@ static int igc_ethtool_set_rss_hash_opt(struct igc_adapter *adapter,
	return 0;
}

int igc_enable_nfc_rule(struct igc_adapter *adapter,
			const struct igc_nfc_rule *rule)
{
	int err = -EINVAL;

	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
		err = igc_add_etype_filter(adapter, rule->filter.etype,
					   rule->action);
		if (err)
			return err;
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
		err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC,
					 rule->filter.src_addr, rule->action);
		if (err)
			return err;
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
		err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST,
					 rule->filter.dst_addr, rule->action);
		if (err)
			return err;
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
		int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >>
			   VLAN_PRIO_SHIFT;

		err = igc_add_vlan_prio_filter(adapter, prio, rule->action);
		if (err)
			return err;
	}

	return 0;
}

int igc_disable_nfc_rule(struct igc_adapter *adapter,
			 const struct igc_nfc_rule *rule)
{
	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE)
		igc_del_etype_filter(adapter, rule->filter.etype);

	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
		int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >>
			   VLAN_PRIO_SHIFT;
		igc_del_vlan_prio_filter(adapter, prio);
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR)
		igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC,
				   rule->filter.src_addr);

	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR)
		igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST,
				   rule->filter.dst_addr);

	return 0;
}

static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter,
				       struct igc_nfc_rule *input,
				       u32 location)
{
	struct igc_nfc_rule *rule, *parent;
	int err = -EINVAL;

	parent = NULL;
	rule = NULL;

	list_for_each_entry(rule, &adapter->nfc_rule_list, list) {
		/* hash found, or no matching entry */
		if (rule->location >= location)
			break;
		parent = rule;
	}

	/* if there is an old rule occupying our place remove it */
	if (rule && rule->location == location) {
		err = igc_disable_nfc_rule(adapter, rule);

		list_del(&rule->list);
		kfree(rule);
		adapter->nfc_rule_count--;
	}

	/* If no input this was a delete, err should be 0 if a rule was
	 * successfully found and removed from the list else -EINVAL
	 */
	if (!input)
		return err;

	list_add(&input->list, parent ? &parent->list :
					&adapter->nfc_rule_list);

	/* update counts */
	adapter->nfc_rule_count++;

	return 0;
}

static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule,
				      const struct ethtool_rx_flow_spec *fsp)
{
@@ -1376,7 +1267,7 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter,
	struct net_device *netdev = adapter->netdev;
	struct ethtool_rx_flow_spec *fsp =
		(struct ethtool_rx_flow_spec *)&cmd->fs;
	struct igc_nfc_rule *rule;
	struct igc_nfc_rule *rule, *old_rule;
	int err;

	if (!(netdev->hw_features & NETIF_F_NTUPLE)) {
@@ -1417,12 +1308,14 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter,
	if (err)
		goto err;

	err = igc_enable_nfc_rule(adapter, rule);
	old_rule = igc_get_nfc_rule(adapter, fsp->location);
	if (old_rule)
		igc_del_nfc_rule(adapter, old_rule);

	err = igc_add_nfc_rule(adapter, rule);
	if (err)
		goto err;

	igc_ethtool_update_nfc_rule(adapter, rule, rule->location);

	spin_unlock(&adapter->nfc_rule_lock);
	return 0;

@@ -1437,13 +1330,20 @@ static int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter,
{
	struct ethtool_rx_flow_spec *fsp =
		(struct ethtool_rx_flow_spec *)&cmd->fs;
	int err;
	struct igc_nfc_rule *rule;

	spin_lock(&adapter->nfc_rule_lock);
	err = igc_ethtool_update_nfc_rule(adapter, NULL, fsp->location);

	rule = igc_get_nfc_rule(adapter, fsp->location);
	if (!rule) {
		spin_unlock(&adapter->nfc_rule_lock);
		return -EINVAL;
	}

	return err;
	igc_del_nfc_rule(adapter, rule);

	spin_unlock(&adapter->nfc_rule_lock);
	return 0;
}

static int igc_ethtool_set_rxnfc(struct net_device *dev,
+172 −33
Original line number Diff line number Diff line
@@ -2174,18 +2174,6 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
	return !!budget;
}

static void igc_restore_nfc_rules(struct igc_adapter *adapter)
{
	struct igc_nfc_rule *rule;

	spin_lock(&adapter->nfc_rule_lock);

	list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list)
		igc_enable_nfc_rule(adapter, rule);

	spin_unlock(&adapter->nfc_rule_lock);
}

static int igc_find_mac_filter(struct igc_adapter *adapter,
			       enum igc_mac_filter_type type, const u8 *addr)
{
@@ -2242,7 +2230,7 @@ static int igc_get_avail_mac_filter_slot(struct igc_adapter *adapter)
 *
 * Return: 0 in case of success, negative errno code otherwise.
 */
int igc_add_mac_filter(struct igc_adapter *adapter,
static int igc_add_mac_filter(struct igc_adapter *adapter,
			      enum igc_mac_filter_type type, const u8 *addr,
			      int queue)
{
@@ -2274,7 +2262,7 @@ update_filter:
 *
 * Return: 0 in case of success, negative errno code otherwise.
 */
int igc_del_mac_filter(struct igc_adapter *adapter,
static int igc_del_mac_filter(struct igc_adapter *adapter,
			      enum igc_mac_filter_type type, const u8 *addr)
{
	struct net_device *dev = adapter->netdev;
@@ -2312,7 +2300,8 @@ int igc_del_mac_filter(struct igc_adapter *adapter,
 *
 * Return: 0 in case of success, negative errno code otherwise.
 */
int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio, int queue)
static int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio,
				    int queue)
{
	struct net_device *dev = adapter->netdev;
	struct igc_hw *hw = &adapter->hw;
@@ -2340,7 +2329,7 @@ int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio, int queue)
 * @adapter: Pointer to adapter where the filter should be deleted from
 * @prio: VLAN priority value
 */
void igc_del_vlan_prio_filter(struct igc_adapter *adapter, int prio)
static void igc_del_vlan_prio_filter(struct igc_adapter *adapter, int prio)
{
	struct igc_hw *hw = &adapter->hw;
	u32 vlanpqf;
@@ -2381,7 +2370,8 @@ static int igc_get_avail_etype_filter_slot(struct igc_adapter *adapter)
 *
 * Return: 0 in case of success, negative errno code otherwise.
 */
int igc_add_etype_filter(struct igc_adapter *adapter, u16 etype, int queue)
static int igc_add_etype_filter(struct igc_adapter *adapter, u16 etype,
				int queue)
{
	struct igc_hw *hw = &adapter->hw;
	int index;
@@ -2433,7 +2423,7 @@ static int igc_find_etype_filter(struct igc_adapter *adapter, u16 etype)
 *
 * Return: 0 in case of success, negative errno code otherwise.
 */
int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype)
static int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype)
{
	struct igc_hw *hw = &adapter->hw;
	int index;
@@ -2449,6 +2439,167 @@ int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype)
	return 0;
}

static int igc_enable_nfc_rule(struct igc_adapter *adapter,
			       const struct igc_nfc_rule *rule)
{
	int err;

	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
		err = igc_add_etype_filter(adapter, rule->filter.etype,
					   rule->action);
		if (err)
			return err;
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
		err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC,
					 rule->filter.src_addr, rule->action);
		if (err)
			return err;
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
		err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST,
					 rule->filter.dst_addr, rule->action);
		if (err)
			return err;
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
		int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >>
			   VLAN_PRIO_SHIFT;

		err = igc_add_vlan_prio_filter(adapter, prio, rule->action);
		if (err)
			return err;
	}

	return 0;
}

static int igc_disable_nfc_rule(struct igc_adapter *adapter,
				const struct igc_nfc_rule *rule)
{
	if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE)
		igc_del_etype_filter(adapter, rule->filter.etype);

	if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
		int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >>
			   VLAN_PRIO_SHIFT;

		igc_del_vlan_prio_filter(adapter, prio);
	}

	if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR)
		igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC,
				   rule->filter.src_addr);

	if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR)
		igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST,
				   rule->filter.dst_addr);

	return 0;
}

/**
 * igc_get_nfc_rule() - Get NFC rule
 * @adapter: Pointer to adapter
 * @location: Rule location
 *
 * Context: Expects adapter->nfc_rule_lock to be held by caller.
 *
 * Return: Pointer to NFC rule at @location. If not found, NULL.
 */
struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter,
				      u32 location)
{
	struct igc_nfc_rule *rule;

	list_for_each_entry(rule, &adapter->nfc_rule_list, list) {
		if (rule->location == location)
			return rule;
		if (rule->location > location)
			break;
	}

	return NULL;
}

/**
 * igc_del_nfc_rule() - Delete NFC rule
 * @adapter: Pointer to adapter
 * @rule: Pointer to rule to be deleted
 *
 * Disable NFC rule in hardware and delete it from adapter.
 *
 * Context: Expects adapter->nfc_rule_lock to be held by caller.
 */
void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule)
{
	igc_disable_nfc_rule(adapter, rule);

	list_del(&rule->list);
	adapter->nfc_rule_count--;

	kfree(rule);
}

/**
 * igc_add_nfc_rule() - Add NFC rule
 * @adapter: Pointer to adapter
 * @rule: Pointer to rule to be added
 *
 * Enable NFC rule in hardware and add it to adapter.
 *
 * Context: Expects adapter->nfc_rule_lock to be held by caller.
 *
 * Return: 0 on success, negative errno on failure.
 */
int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule)
{
	struct igc_nfc_rule *pred, *cur;
	int err;

	err = igc_enable_nfc_rule(adapter, rule);
	if (err)
		return err;

	pred = NULL;
	list_for_each_entry(cur, &adapter->nfc_rule_list, list) {
		if (cur->location >= rule->location)
			break;
		pred = cur;
	}

	list_add(&rule->list, pred ? &pred->list : &adapter->nfc_rule_list);
	adapter->nfc_rule_count++;
	return 0;
}

static void igc_restore_nfc_rules(struct igc_adapter *adapter)
{
	struct igc_nfc_rule *rule;

	spin_lock(&adapter->nfc_rule_lock);

	list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list)
		igc_enable_nfc_rule(adapter, rule);

	spin_unlock(&adapter->nfc_rule_lock);
}

static void igc_nfc_rule_exit(struct igc_adapter *adapter)
{
	struct igc_nfc_rule *rule;

	spin_lock(&adapter->nfc_rule_lock);

	list_for_each_entry(rule, &adapter->nfc_rule_list, list)
		igc_disable_nfc_rule(adapter, rule);

	spin_unlock(&adapter->nfc_rule_lock);
}

static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr)
{
	struct igc_adapter *adapter = netdev_priv(netdev);
@@ -3648,18 +3799,6 @@ void igc_update_stats(struct igc_adapter *adapter)
	adapter->stats.mgpdc += rd32(IGC_MGTPDC);
}

static void igc_nfc_rule_exit(struct igc_adapter *adapter)
{
	struct igc_nfc_rule *rule;

	spin_lock(&adapter->nfc_rule_lock);

	list_for_each_entry(rule, &adapter->nfc_rule_list, list)
		igc_disable_nfc_rule(adapter, rule);

	spin_unlock(&adapter->nfc_rule_lock);
}

/**
 * igc_down - Close the interface
 * @adapter: board private structure