Commit 995617dc authored by Ahmed Zaki's avatar Ahmed Zaki Committed by Tony Nguyen
Browse files

iavf: refactor add/del FDIR filters



In preparation for a second type of FDIR filters that can be added by
tc-u32, move the add/del of the FDIR logic to be entirely contained in
iavf_fdir.c.

The iavf_find_fdir_fltr_by_loc() is renamed to iavf_find_fdir_fltr()
to be more agnostic to the filter ID parameter (for now @loc, which is
relevant only to current FDIR filters added via ethtool).

The FDIR filter deletion is moved from iavf_del_fdir_ethtool() in
ethtool.c to iavf_fdir_del_fltr(). While at it, fix a minor bug where
the "fltr" is accessed out of the fdir_fltr_lock spinlock protection.

Reviewed-by: default avatarSridhar Samudrala <sridhar.samudrala@intel.com>
Reviewed-by: default avatarMarcin Szycik <marcin.szycik@linux.intel.com>
Signed-off-by: default avatarAhmed Zaki <ahmed.zaki@intel.com>
Tested-by: default avatarRafal Romanowski <rafal.romanowski@intel.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 99f419df
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -444,6 +444,11 @@ struct iavf_adapter {
	spinlock_t adv_rss_lock;	/* protect the RSS management list */
};

/* Must be called with fdir_fltr_lock lock held */
static inline bool iavf_fdir_max_reached(struct iavf_adapter *adapter)
{
	return adapter->fdir_active_fltr >= IAVF_MAX_FDIR_FILTERS;
}

/* Ethtool Private Flags */

+6 −50
Original line number Diff line number Diff line
@@ -927,7 +927,7 @@ iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter,

	spin_lock_bh(&adapter->fdir_fltr_lock);

	rule = iavf_find_fdir_fltr_by_loc(adapter, fsp->location);
	rule = iavf_find_fdir_fltr(adapter, fsp->location);
	if (!rule) {
		ret = -EINVAL;
		goto release_lock;
@@ -1263,15 +1263,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
		return -EINVAL;

	spin_lock_bh(&adapter->fdir_fltr_lock);
	if (adapter->fdir_active_fltr >= IAVF_MAX_FDIR_FILTERS) {
		spin_unlock_bh(&adapter->fdir_fltr_lock);
		dev_err(&adapter->pdev->dev,
			"Unable to add Flow Director filter because VF reached the limit of max allowed filters (%u)\n",
			IAVF_MAX_FDIR_FILTERS);
		return -ENOSPC;
	}

	if (iavf_find_fdir_fltr_by_loc(adapter, fsp->location)) {
	if (iavf_find_fdir_fltr(adapter, fsp->location)) {
		dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, it already exists\n");
		spin_unlock_bh(&adapter->fdir_fltr_lock);
		return -EEXIST;
@@ -1291,23 +1283,10 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
	}

	err = iavf_add_fdir_fltr_info(adapter, fsp, fltr);
	if (err)
		goto ret;

	spin_lock_bh(&adapter->fdir_fltr_lock);
	iavf_fdir_list_add_fltr(adapter, fltr);
	adapter->fdir_active_fltr++;

	if (adapter->link_up)
		fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
	else
		fltr->state = IAVF_FDIR_FLTR_INACTIVE;
	spin_unlock_bh(&adapter->fdir_fltr_lock);
	if (!err)
		err = iavf_fdir_add_fltr(adapter, fltr);

	if (adapter->link_up)
		iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER);
ret:
	if (err && fltr)
	if (err)
		kfree(fltr);

	mutex_unlock(&adapter->crit_lock);
@@ -1324,34 +1303,11 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd)
{
	struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
	struct iavf_fdir_fltr *fltr = NULL;
	int err = 0;

	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
		return -EOPNOTSUPP;

	spin_lock_bh(&adapter->fdir_fltr_lock);
	fltr = iavf_find_fdir_fltr_by_loc(adapter, fsp->location);
	if (fltr) {
		if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
			fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
		} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
			list_del(&fltr->list);
			kfree(fltr);
			adapter->fdir_active_fltr--;
			fltr = NULL;
		} else {
			err = -EBUSY;
		}
	} else if (adapter->fdir_active_fltr) {
		err = -EINVAL;
	}
	spin_unlock_bh(&adapter->fdir_fltr_lock);

	if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
		iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER);

	return err;
	return iavf_fdir_del_fltr(adapter, fsp->location);
}

/**
+67 −5
Original line number Diff line number Diff line
@@ -815,13 +815,14 @@ bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *
}

/**
 * iavf_find_fdir_fltr_by_loc - find filter with location
 * iavf_find_fdir_fltr - find FDIR filter
 * @adapter: pointer to the VF adapter structure
 * @loc: location to find.
 *
 * Returns pointer to Flow Director filter if found or null
 * Returns: pointer to Flow Director filter if found or NULL. Lock must be held.
 */
struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc)
struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,
					   u32 loc)
{
	struct iavf_fdir_fltr *rule;

@@ -833,14 +834,26 @@ struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter,
}

/**
 * iavf_fdir_list_add_fltr - add a new node to the flow director filter list
 * iavf_fdir_add_fltr - add a new node to the flow director filter list
 * @adapter: pointer to the VF adapter structure
 * @fltr: filter node to add to structure
 *
 * Return: 0 on success or negative errno on failure.
 */
void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
		       struct iavf_fdir_fltr *fltr)
{
	struct iavf_fdir_fltr *rule, *parent = NULL;

	spin_lock_bh(&adapter->fdir_fltr_lock);
	if (iavf_fdir_max_reached(adapter)) {
		spin_unlock_bh(&adapter->fdir_fltr_lock);
		dev_err(&adapter->pdev->dev,
			"Unable to add Flow Director filter (limit (%u) reached)\n",
			IAVF_MAX_FDIR_FILTERS);
		return -ENOSPC;
	}

	list_for_each_entry(rule, &adapter->fdir_list_head, list) {
		if (rule->loc >= fltr->loc)
			break;
@@ -851,4 +864,53 @@ void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr
		list_add(&fltr->list, &parent->list);
	else
		list_add(&fltr->list, &adapter->fdir_list_head);
	adapter->fdir_active_fltr++;

	if (adapter->link_up)
		fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
	else
		fltr->state = IAVF_FDIR_FLTR_INACTIVE;
	spin_unlock_bh(&adapter->fdir_fltr_lock);

	if (adapter->link_up)
		iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER);

	return 0;
}

/**
 * iavf_fdir_del_fltr - delete a flow director filter from the list
 * @adapter: pointer to the VF adapter structure
 * @loc: location to delete.
 *
 * Return: 0 on success or negative errno on failure.
 */
int iavf_fdir_del_fltr(struct iavf_adapter *adapter, u32 loc)
{
	struct iavf_fdir_fltr *fltr = NULL;
	int err = 0;

	spin_lock_bh(&adapter->fdir_fltr_lock);
	fltr = iavf_find_fdir_fltr(adapter, loc);

	if (fltr) {
		if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
			fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
		} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
			list_del(&fltr->list);
			kfree(fltr);
			adapter->fdir_active_fltr--;
			fltr = NULL;
		} else {
			err = -EBUSY;
		}
	} else if (adapter->fdir_active_fltr) {
		err = -EINVAL;
	}

	if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
		iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER);

	spin_unlock_bh(&adapter->fdir_fltr_lock);
	return err;
}
+5 −2
Original line number Diff line number Diff line
@@ -128,6 +128,9 @@ int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc);
int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
		       struct iavf_fdir_fltr *fltr);
int iavf_fdir_del_fltr(struct iavf_adapter *adapter, u32 loc);
struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,
					   u32 loc);
#endif /* _IAVF_FDIR_H_ */