From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from dpdk.org (dpdk.org [92.243.14.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 73A4FA0526;
	Fri, 10 Jul 2020 04:50:40 +0200 (CEST)
Received: from [92.243.14.124] (localhost [127.0.0.1])
	by dpdk.org (Postfix) with ESMTP id 7CEE81DD2F;
	Fri, 10 Jul 2020 04:50:39 +0200 (CEST)
Received: from mga06.intel.com (mga06.intel.com [134.134.136.31])
 by dpdk.org (Postfix) with ESMTP id 5C89F1DD2E
 for <dev@dpdk.org>; Fri, 10 Jul 2020 04:50:36 +0200 (CEST)
IronPort-SDR: YHWikzIHoeXpDfPF7nCQ1+WqrMkRCaXupd5Asj49PXuBIM75sttXosoUuM56I33UPGuzvDd07I
 O6kqwwAaf9og==
X-IronPort-AV: E=McAfee;i="6000,8403,9677"; a="209671941"
X-IronPort-AV: E=Sophos;i="5.75,334,1589266800"; d="scan'208";a="209671941"
X-Amp-Result: SKIPPED(no attachment in message)
X-Amp-File-Uploaded: False
Received: from orsmga001.jf.intel.com ([10.7.209.18])
 by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
 09 Jul 2020 19:50:35 -0700
IronPort-SDR: 1nrdYGrOQx9oRcVVy0xx4HJ1xngZLZibTSIdLhVVbgkDLxNpTrpNCohC18l/ATXVf4yLpCSJOj
 TwaWg4eeFkAg==
X-ExtLoop1: 1
X-IronPort-AV: E=Sophos;i="5.75,334,1589266800"; d="scan'208";a="358645689"
Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201])
 by orsmga001.jf.intel.com with ESMTP; 09 Jul 2020 19:50:35 -0700
Received: from FMSMSX109.amr.corp.intel.com (10.18.116.9) by
 FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS)
 id 14.3.439.0; Thu, 9 Jul 2020 19:50:34 -0700
Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by
 fmsmsx109.amr.corp.intel.com (10.18.116.9) with Microsoft SMTP Server (TLS)
 id 14.3.439.0; Thu, 9 Jul 2020 19:50:34 -0700
Received: from shsmsx103.ccr.corp.intel.com ([169.254.4.22]) by
 SHSMSX151.ccr.corp.intel.com ([169.254.3.49]) with mapi id 14.03.0439.000;
 Fri, 10 Jul 2020 10:50:31 +0800
From: "Zhang, Qi Z" <qi.z.zhang@intel.com>
To: "Sun, Chenmin" <chenmin.sun@intel.com>, "Xing, Beilei"
 <beilei.xing@intel.com>, "Wu, Jingjing" <jingjing.wu@intel.com>, "Wang,
 Haiyue" <haiyue.wang@intel.com>
CC: "dev@dpdk.org" <dev@dpdk.org>
Thread-Topic: [PATCH V2] net/i40e: i40e FDIR update rate optimization
Thread-Index: AQHWVbPRQH11/Ue+OUmexMyQ6HjNHqkADk2w
Date: Fri, 10 Jul 2020 02:50:30 +0000
Message-ID: <039ED4275CED7440929022BC67E706115485A08F@SHSMSX103.ccr.corp.intel.com>
References: <20200612180015.14760-1-chenmin.sun@intel.com>
 <20200709143932.35806-1-chenmin.sun@intel.com>
In-Reply-To: <20200709143932.35806-1-chenmin.sun@intel.com>
Accept-Language: en-US
Content-Language: en-US
X-MS-Has-Attach: 
X-MS-TNEF-Correlator: 
dlp-product: dlpe-windows
dlp-version: 11.2.0.6
dlp-reaction: no-action
x-originating-ip: [10.239.127.40]
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
Subject: Re: [dpdk-dev] [PATCH V2] net/i40e: i40e FDIR update rate
	optimization
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org
Sender: "dev" <dev-bounces@dpdk.org>



> -----Original Message-----
> From: Sun, Chenmin <chenmin.sun@intel.com>
> Sent: Thursday, July 9, 2020 10:40 PM
> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Xing, Beilei <beilei.xing@intel.c=
om>;
> Wu, Jingjing <jingjing.wu@intel.com>; Wang, Haiyue
> <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Sun, Chenmin <chenmin.sun@intel.com>
> Subject: [PATCH V2] net/i40e: i40e FDIR update rate optimization
>=20
> From: Chenmin Sun <chenmin.sun@intel.com>
>=20
> This patch optimized the fdir update rate for i40e PF, by tracking whethe=
r the
> fdir rule being inserted into the guaranteed space or shared space.
> For the flows that are inserted to the guaranteed space, we assume that t=
he
> insertion will always succeed as the hardware only reports the "no enough
> space left" error. In this case, the software can directly return success=
 and no
> need to retrieve the result from the hardware. See the fdir programming
> status descriptor format in the datasheet for more details.
>=20
> This patch changes the global register GLQF_CTL. Therefore, when devarg
> ``support-multi-driver`` is set, the patch will not take effect to avoid =
affecting
> the normal behavior of other i40e drivers, e.g., Linux kernel driver.

Overall I think the patch is too big, is that possible to separate into 2 o=
r more patches?

For example:
1.) you introduce some new data structure to tack the flow
2) the optimization for flow programming.

More comments inline.
>=20
> Signed-off-by: Chenmin Sun <chenmin.sun@intel.com>
> ---
>=20
> v2:
> * Refine commit message and code comments.
> * Refine code style.
> * Fixed several memory free bugs.
> * Replace the bin_serch() with rte_bsf64()
> ---
>  drivers/net/i40e/i40e_ethdev.c  | 136 ++++++++++++++++++++++-
> drivers/net/i40e/i40e_ethdev.h  |  63 ++++++++---
>  drivers/net/i40e/i40e_fdir.c    | 190 +++++++++++++++++++++-----------
>  drivers/net/i40e/i40e_flow.c    | 167 ++++++++++++++++++++++------
>  drivers/net/i40e/i40e_rxtx.c    |  15 ++-
>  drivers/net/i40e/rte_pmd_i40e.c |   2 +-
>  6 files changed, 455 insertions(+), 118 deletions(-)
>=20
> diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethde=
v.c
> index 3bc312c11..099f4c5e3 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -26,6 +26,7 @@
>  #include <rte_dev.h>
>  #include <rte_tailq.h>
>  #include <rte_hash_crc.h>
> +#include <rte_bitmap.h>
>=20
>  #include "i40e_logs.h"
>  #include "base/i40e_prototype.h"
> @@ -1045,8 +1046,17 @@ static int
>  i40e_init_fdir_filter_list(struct rte_eth_dev *dev)  {
>  	struct i40e_pf *pf =3D
> I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
> +	struct i40e_hw *hw =3D I40E_PF_TO_HW(pf);
>  	struct i40e_fdir_info *fdir_info =3D &pf->fdir;
>  	char fdir_hash_name[RTE_HASH_NAMESIZE];
> +	void *mem =3D NULL;
> +	uint32_t i =3D 0;
> +	uint32_t bmp_size;
> +	uint32_t alloc =3D 0;
> +	uint32_t best =3D 0;
> +	uint32_t pfqf_fdalloc =3D 0;
> +	uint32_t glqf_ctl_reg =3D 0;
> +	struct rte_bitmap *bmp =3D NULL;
>  	int ret;

Its better to follow RCT, and please apply on other functions.

>=20
>  	struct rte_hash_parameters fdir_hash_params =3D { @@ -1067,6 +1077,7
> @@ i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
>  		PMD_INIT_LOG(ERR, "Failed to create fdir hash table!");
>  		return -EINVAL;
>  	}
> +
>  	fdir_info->hash_map =3D rte_zmalloc("i40e_fdir_hash_map",
>  					  sizeof(struct i40e_fdir_filter *) *
>  					  I40E_MAX_FDIR_FILTER_NUM,
> @@ -1077,8 +1088,100 @@ i40e_init_fdir_filter_list(struct rte_eth_dev
> *dev)
>  		ret =3D -ENOMEM;
>  		goto err_fdir_hash_map_alloc;
>  	}
> +
> +	fdir_info->fdir_filter_array =3D rte_zmalloc("fdir_filter",
> +			sizeof(struct i40e_fdir_filter) *
> +			I40E_MAX_FDIR_FILTER_NUM,
> +			0);
> +
> +	if (!fdir_info->fdir_filter_array) {
> +		PMD_INIT_LOG(ERR,
> +			     "Failed to allocate memory for fdir filter array!");
> +		ret =3D -ENOMEM;
> +		goto err_fdir_filter_array_alloc;
> +	}
> +
> +	pfqf_fdalloc =3D i40e_read_rx_ctl(hw, I40E_PFQF_FDALLOC);
> +	alloc =3D ((pfqf_fdalloc & I40E_PFQF_FDALLOC_FDALLOC_MASK) >>
> +			I40E_PFQF_FDALLOC_FDALLOC_SHIFT);
> +	best =3D ((pfqf_fdalloc & I40E_PFQF_FDALLOC_FDBEST_MASK) >>
> +			I40E_PFQF_FDALLOC_FDBEST_SHIFT);
> +
> +	glqf_ctl_reg =3D i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
> +	if (!pf->support_multi_driver) {
> +		fdir_info->fdir_invalprio =3D 1;
> +		glqf_ctl_reg |=3D I40E_GLQF_CTL_INVALPRIO_MASK;
> +		PMD_DRV_LOG(INFO, "FDIR INVALPRIO set to guaranteed first");
> +	} else {
> +		if (glqf_ctl_reg | I40E_GLQF_CTL_INVALPRIO_MASK) {
> +			fdir_info->fdir_invalprio =3D 1;
> +			PMD_DRV_LOG(INFO, "FDIR INVALPRIO is: guaranteed first");
> +		} else {
> +			fdir_info->fdir_invalprio =3D 0;
> +			PMD_DRV_LOG(INFO, "FDIR INVALPRIO is: shared first");
> +		}
> +	}
> +
> +	i40e_write_rx_ctl(hw, I40E_GLQF_CTL, glqf_ctl_reg);
> +	PMD_DRV_LOG(INFO, "FDIR guarantee space: %u, best_effort
> space %u.",
> +		alloc * 32, best * 32);

I think *32 can be applied when you assign alloc and best.=20
Also its better to replace by macro with meaningful name and use bit shift =
<< but not *.
> +
> +	fdir_info->fdir_space_size =3D (alloc + best) * 32;
> +	fdir_info->fdir_actual_cnt =3D 0;
> +	fdir_info->fdir_guarantee_available_space =3D alloc * 32;
> +	fdir_info->fdir_guarantee_free_space =3D
> +		fdir_info->fdir_guarantee_available_space;
> +
> +	fdir_info->fdir_flow_bitmap.fdir_flow =3D
> +			rte_zmalloc("i40e_fdir_flows",
> +				sizeof(struct i40e_fdir_flows) *
> +				fdir_info->fdir_space_size,
> +				0);
> +
> +	if (!fdir_info->fdir_flow_bitmap.fdir_flow) {
> +		PMD_INIT_LOG(ERR,
> +			     "Failed to allocate memory for bitmap flow!");
> +		ret =3D -ENOMEM;
> +		goto err_fdir_bitmap_flow_alloc;
> +	}
> +
> +	for (i =3D 0; i < fdir_info->fdir_space_size; i++)
> +		fdir_info->fdir_flow_bitmap.fdir_flow[i].idx =3D i;
> +
> +	bmp_size =3D
> +		rte_bitmap_get_memory_footprint(fdir_info->fdir_space_size);
> +
> +	mem =3D rte_zmalloc("fdir_bmap", bmp_size, RTE_CACHE_LINE_SIZE);
> +	if (mem =3D=3D NULL) {
> +		PMD_INIT_LOG(ERR,
> +			     "Failed to allocate memory for fdir bitmap!");
> +		ret =3D -ENOMEM;
> +		goto err_fdir_mem_alloc;
> +	}
> +
> +	bmp =3D rte_bitmap_init(fdir_info->fdir_space_size, mem, bmp_size);
> +	if (bmp =3D=3D NULL) {
> +		PMD_INIT_LOG(ERR,
> +			     "Failed to initialization fdir bitmap!");
> +		ret =3D -ENOMEM;
> +		goto err_fdir_bmp_alloc;
> +	}
> +
> +	for (i =3D 0; i < fdir_info->fdir_space_size; i++)
> +		rte_bitmap_set(bmp, i);
> +
> +	fdir_info->fdir_flow_bitmap.b =3D bmp;
> +
>  	return 0;
>=20
> +err_fdir_bmp_alloc:
> +	rte_free(mem);
> +err_fdir_mem_alloc:
> +	rte_free(fdir_info->fdir_flow_bitmap.fdir_flow);
> +err_fdir_bitmap_flow_alloc:
> +	rte_free(fdir_info->fdir_filter_array);
> +err_fdir_filter_array_alloc:
> +	rte_free(fdir_info->hash_map);
>  err_fdir_hash_map_alloc:
>  	rte_hash_free(fdir_info->hash_table);
>=20
> @@ -1749,18 +1852,34 @@ i40e_rm_fdir_filter_list(struct i40e_pf *pf)
>  	struct i40e_fdir_info *fdir_info;
>=20
>  	fdir_info =3D &pf->fdir;
> -	/* Remove all flow director rules and hash */
> +
> +	/* Remove all flow director rules */
> +	while ((p_fdir =3D TAILQ_FIRST(&fdir_info->fdir_list)))
> +		TAILQ_REMOVE(&fdir_info->fdir_list, p_fdir, rules); }
> +
> +static void
> +i40e_fdir_memory_cleanup(struct i40e_pf *pf) {
> +	struct i40e_fdir_info *fdir_info;
> +
> +	fdir_info =3D &pf->fdir;
> +
> +	/* flow director memory cleanup */
>  	if (fdir_info->hash_map)
>  		rte_free(fdir_info->hash_map);
>  	if (fdir_info->hash_table)
>  		rte_hash_free(fdir_info->hash_table);
> +	if (fdir_info->fdir_flow_bitmap.b)
> +		rte_bitmap_free(fdir_info->fdir_flow_bitmap.b);
> +	if (fdir_info->fdir_flow_bitmap.fdir_flow)
> +		rte_free(fdir_info->fdir_flow_bitmap.fdir_flow);
> +	if (fdir_info->fdir_filter_array)
> +		rte_free(fdir_info->fdir_filter_array);
>=20
> -	while ((p_fdir =3D TAILQ_FIRST(&fdir_info->fdir_list))) {
> -		TAILQ_REMOVE(&fdir_info->fdir_list, p_fdir, rules);
> -		rte_free(p_fdir);
> -	}
>  }
>=20
> +
>  void i40e_flex_payload_reg_set_default(struct i40e_hw *hw)  {
>  	/*
> @@ -2618,9 +2737,14 @@ i40e_dev_close(struct rte_eth_dev *dev)
>  	/* Remove all flows */
>  	while ((p_flow =3D TAILQ_FIRST(&pf->flow_list))) {
>  		TAILQ_REMOVE(&pf->flow_list, p_flow, node);
> -		rte_free(p_flow);
> +		/* Do not free FDIR flows since they are static allocated */
> +		if (p_flow->filter_type !=3D RTE_ETH_FILTER_FDIR)
> +			rte_free(p_flow);
>  	}
>=20
> +	/* release the fdir static allocated memory */
> +	i40e_fdir_memory_cleanup(pf);
> +
>  	/* Remove all Traffic Manager configuration */
>  	i40e_tm_conf_uninit(dev);
>=20
> diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethde=
v.h
> index 31ca05de9..5861c358b 100644
> --- a/drivers/net/i40e/i40e_ethdev.h
> +++ b/drivers/net/i40e/i40e_ethdev.h
> @@ -264,6 +264,15 @@ enum i40e_flxpld_layer_idx {
>  #define I40E_DEFAULT_DCB_APP_NUM    1
>  #define I40E_DEFAULT_DCB_APP_PRIO   3
>=20
> +/*
> + * Struct to store flow created.
> + */
> +struct rte_flow {
> +	TAILQ_ENTRY(rte_flow) node;
> +	enum rte_filter_type filter_type;
> +	void *rule;
> +};
> +
>  /**
>   * The overhead from MTU to max frame size.
>   * Considering QinQ packet, the VLAN tag needs to be counted twice.
> @@ -674,17 +683,33 @@ struct i40e_fdir_filter {
>  	struct i40e_fdir_filter_conf fdir;
>  };
>=20
> +struct i40e_fdir_flows {

Why it be named as "flows"
Could you add more comment here, what's purpose of the data structure and e=
ach field?

> +	uint32_t idx;
> +	struct rte_flow flow;

Not sure if its better to move flow to the first field, so we cover between=
 a rte_flow point and a i40e_fdir_flow point directly.
> +};
> +
> +struct i40e_fdir_flow_bitmap {
> +	struct rte_bitmap *b;
> +	struct i40e_fdir_flows *fdir_flow;
> +};

Can we just add rte_bitmap into i40e_fdir_flow?

> +
> +#define FLOW_TO_FLOW_BITMAP(f) \
> +	container_of((f), struct i40e_fdir_flows, flow)
> +
>  TAILQ_HEAD(i40e_fdir_filter_list, i40e_fdir_filter);
>  /*
>   *  A structure used to define fields of a FDIR related info.
>   */
>  struct i40e_fdir_info {
> +#define PRG_PKT_CNT	128
> +
>  	struct i40e_vsi *fdir_vsi;     /* pointer to fdir VSI structure */
>  	uint16_t match_counter_index;  /* Statistic counter index used for
> fdir*/
>  	struct i40e_tx_queue *txq;
>  	struct i40e_rx_queue *rxq;
> -	void *prg_pkt;                 /* memory for fdir program packet */
> -	uint64_t dma_addr;             /* physic address of packet
> memory*/
> +	void *prg_pkt[PRG_PKT_CNT];     /* memory for fdir program packet
> */
> +	uint64_t dma_addr[PRG_PKT_CNT];	/* physic address of packet
> memory*/
> +
>  	/* input set bits for each pctype */
>  	uint64_t input_set[I40E_FILTER_PCTYPE_MAX];
>  	/*
> @@ -698,6 +723,27 @@ struct i40e_fdir_info {
>  	struct i40e_fdir_filter **hash_map;
>  	struct rte_hash *hash_table;
>=20
> +	struct i40e_fdir_filter *fdir_filter_array;
> +
> +	/*
> +	 * Priority ordering at filter invalidation(destroying a flow) between
> +	 * "best effort" space and "guaranteed" space.
> +	 *
> +	 * 0 =3D At filter invalidation, the hardware first tries to increment =
the
> +	 * "best effort" space. The "guaranteed" space is incremented only
> when
> +	 * the global "best effort" space is at it max value or the "best effor=
t"
> +	 * space of the PF is at its max value.
> +	 * 1 =3D At filter invalidation, the hardware first tries to increment =
its
> +	 * "guaranteed" space. The "best effort" space is incremented only
> when
> +	 * it is already at its max value.
> +	 */
> +	uint32_t fdir_invalprio;
> +	uint32_t fdir_space_size;
> +	uint32_t fdir_actual_cnt;
> +	uint32_t fdir_guarantee_available_space;
> +	uint32_t fdir_guarantee_free_space;
> +	struct i40e_fdir_flow_bitmap fdir_flow_bitmap;

What is the flow_bitmap usage? its free bitmap or alloc bitmap?
Better add more description here, or rename it with more clean purpose.

> +
>  	/* Mark if flex pit and mask is set */
>  	bool flex_pit_flag[I40E_MAX_FLXPLD_LAYER];
>  	bool flex_mask_flag[I40E_FILTER_PCTYPE_MAX];
> @@ -894,15 +940,6 @@ struct i40e_mirror_rule {
>=20
>  TAILQ_HEAD(i40e_mirror_rule_list, i40e_mirror_rule);
>=20
> -/*
> - * Struct to store flow created.
> - */
> -struct rte_flow {
> -	TAILQ_ENTRY(rte_flow) node;
> -	enum rte_filter_type filter_type;
> -	void *rule;
> -};
> -
>  TAILQ_HEAD(i40e_flow_list, rte_flow);
>=20
>  /* Struct to store Traffic Manager shaper profile. */ @@ -1335,8 +1372,8
> @@ int i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
>  			     const struct rte_eth_fdir_filter *filter,
>  			     bool add);
>  int i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
> -				  const struct i40e_fdir_filter_conf *filter,
> -				  bool add);
> +			      const struct i40e_fdir_filter_conf *filter,
> +			      bool add, bool wait_status);
>  int i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
>  			       struct rte_eth_tunnel_filter_conf *tunnel_filter,
>  			       uint8_t add);
> diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c =
index
> 4a778db4c..d7ba841d6 100644
> --- a/drivers/net/i40e/i40e_fdir.c
> +++ b/drivers/net/i40e/i40e_fdir.c
> @@ -99,7 +99,7 @@ static int
>  i40e_flow_fdir_filter_programming(struct i40e_pf *pf,
>  				  enum i40e_filter_pctype pctype,
>  				  const struct i40e_fdir_filter_conf *filter,
> -				  bool add);
> +				  bool add, bool wait_status);
>=20
>  static int
>  i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq) @@ -163,6 +163,7
> @@ i40e_fdir_setup(struct i40e_pf *pf)
>  	char z_name[RTE_MEMZONE_NAMESIZE];
>  	const struct rte_memzone *mz =3D NULL;
>  	struct rte_eth_dev *eth_dev =3D pf->adapter->eth_dev;
> +	uint16_t i;
>=20
>  	if ((pf->flags & I40E_FLAG_FDIR) =3D=3D 0) {
>  		PMD_INIT_LOG(ERR, "HW doesn't support FDIR"); @@ -179,6
> +180,7 @@ i40e_fdir_setup(struct i40e_pf *pf)
>  		PMD_DRV_LOG(INFO, "FDIR initialization has been done.");
>  		return I40E_SUCCESS;
>  	}
> +
>  	/* make new FDIR VSI */
>  	vsi =3D i40e_vsi_setup(pf, I40E_VSI_FDIR, pf->main_vsi, 0);
>  	if (!vsi) {
> @@ -233,17 +235,27 @@ i40e_fdir_setup(struct i40e_pf *pf)
>  			eth_dev->device->driver->name,
>  			I40E_FDIR_MZ_NAME,
>  			eth_dev->data->port_id);
> -	mz =3D i40e_memzone_reserve(z_name, I40E_FDIR_PKT_LEN,
> SOCKET_ID_ANY);
> +	mz =3D i40e_memzone_reserve(z_name, I40E_FDIR_PKT_LEN *
> PRG_PKT_CNT,
> +			SOCKET_ID_ANY);
>  	if (!mz) {
>  		PMD_DRV_LOG(ERR, "Cannot init memzone for "
>  				 "flow director program packet.");
>  		err =3D I40E_ERR_NO_MEMORY;
>  		goto fail_mem;
>  	}
> -	pf->fdir.prg_pkt =3D mz->addr;
> -	pf->fdir.dma_addr =3D mz->iova;
> +
> +	for (i =3D 0; i < PRG_PKT_CNT; i++) {
> +		pf->fdir.prg_pkt[i] =3D (uint8_t *)mz->addr + I40E_FDIR_PKT_LEN *
> +				(i % PRG_PKT_CNT);

The loop is from 0 to PRG_PKT_CNT, why "i % PKG_PTK_CNT"?

> +		pf->fdir.dma_addr[i] =3D mz->iova + I40E_FDIR_PKT_LEN *
> +				(i % PRG_PKT_CNT);
> +	}
>=20
>  	pf->fdir.match_counter_index =3D
> I40E_COUNTER_INDEX_FDIR(hw->pf_id);
> +	pf->fdir.fdir_actual_cnt =3D 0;
> +	pf->fdir.fdir_guarantee_free_space =3D
> +		pf->fdir.fdir_guarantee_available_space;
> +
>  	PMD_DRV_LOG(INFO, "FDIR setup successfully, with programming
> queue %u.",
>  		    vsi->base_queue);
>  	return I40E_SUCCESS;
> @@ -327,6 +339,7 @@ i40e_init_flx_pld(struct i40e_pf *pf)
>  		pf->fdir.flex_set[index].src_offset =3D 0;
>  		pf->fdir.flex_set[index].size =3D I40E_FDIR_MAX_FLEXWORD_NUM;
>  		pf->fdir.flex_set[index].dst_offset =3D 0;
> +
Dummy empty line.

>  		I40E_WRITE_REG(hw, I40E_PRTQF_FLX_PIT(index), 0x0000C900);
>  		I40E_WRITE_REG(hw,
>  			I40E_PRTQF_FLX_PIT(index + 1), 0x0000FC29);/*non-used*/
> @@ -1557,11 +1570,11 @@ i40e_sw_fdir_filter_lookup(struct
> i40e_fdir_info *fdir_info,
>  	return fdir_info->hash_map[ret];
>  }
>=20
> -/* Add a flow director filter into the SW list */  static int
> i40e_sw_fdir_filter_insert(struct i40e_pf *pf, struct i40e_fdir_filter *f=
ilter)
> {
>  	struct i40e_fdir_info *fdir_info =3D &pf->fdir;
> +	struct i40e_fdir_filter *hash_filter;
>  	int ret;
>=20
>  	if (filter->fdir.input.flow_ext.pkt_template)
> @@ -1577,9 +1590,14 @@ i40e_sw_fdir_filter_insert(struct i40e_pf *pf,
> struct i40e_fdir_filter *filter)
>  			    ret);
>  		return ret;
>  	}
> -	fdir_info->hash_map[ret] =3D filter;
>=20
> -	TAILQ_INSERT_TAIL(&fdir_info->fdir_list, filter, rules);
> +	if (fdir_info->hash_map[ret])
> +		return -1;
> +
> +	hash_filter =3D &fdir_info->fdir_filter_array[ret];
> +	rte_memcpy(hash_filter, filter, sizeof(*filter));
> +	fdir_info->hash_map[ret] =3D hash_filter;
> +	TAILQ_INSERT_TAIL(&fdir_info->fdir_list, hash_filter, rules);
>=20
>  	return 0;
>  }
> @@ -1608,7 +1626,6 @@ i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct
> i40e_fdir_input *input)
>  	fdir_info->hash_map[ret] =3D NULL;
>=20
>  	TAILQ_REMOVE(&fdir_info->fdir_list, filter, rules);
> -	rte_free(filter);
>=20
>  	return 0;
>  }
> @@ -1675,23 +1692,50 @@ i40e_add_del_fdir_filter(struct rte_eth_dev
> *dev,
>  	return ret;
>  }
>=20
> +static inline unsigned char *
> +i40e_find_available_buffer(struct rte_eth_dev *dev) {
> +	struct i40e_pf *pf =3D
> I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
> +	struct i40e_fdir_info *fdir_info =3D &pf->fdir;
> +	struct i40e_tx_queue *txq =3D pf->fdir.txq;
> +	volatile struct i40e_tx_desc *txdp =3D &txq->tx_ring[txq->tx_tail + 1];
> +	uint32_t i;
> +
> +	/* wait until the tx descriptor is ready */
> +	for (i =3D 0; i < I40E_FDIR_MAX_WAIT_US; i++) {
> +		if ((txdp->cmd_type_offset_bsz &
> +			rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) =3D=3D
> +			rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))
> +			break;
> +		rte_delay_us(1);
> +	}
> +	if (i >=3D I40E_FDIR_MAX_WAIT_US) {
> +		PMD_DRV_LOG(ERR,
> +		    "Failed to program FDIR filter: time out to get DD on tx
> queue.");
> +		return NULL;
> +	}
> +
> +	return (unsigned char *)fdir_info->prg_pkt[txq->tx_tail / 2]; }

why tx_tail / 2, better some add some description here, and use " >> 1" if =
its word / byte conversion.

> +
>  /**
>   * i40e_flow_add_del_fdir_filter - add or remove a flow director filter.
>   * @pf: board private structure
>   * @filter: fdir filter entry
>   * @add: 0 - delete, 1 - add
>   */
> +
>  int
>  i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
>  			      const struct i40e_fdir_filter_conf *filter,
> -			      bool add)
> +			      bool add, bool wait_status)
>  {
>  	struct i40e_hw *hw =3D
> I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
>  	struct i40e_pf *pf =3D
> I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
> -	unsigned char *pkt =3D (unsigned char *)pf->fdir.prg_pkt;
> +	unsigned char *pkt =3D NULL;
>  	enum i40e_filter_pctype pctype;
>  	struct i40e_fdir_info *fdir_info =3D &pf->fdir;
> -	struct i40e_fdir_filter *fdir_filter, *node;
> +	struct i40e_fdir_filter *node;
>  	struct i40e_fdir_filter check_filter; /* Check if the filter exists */
>  	int ret =3D 0;
>=20
> @@ -1724,25 +1768,41 @@ i40e_flow_add_del_fdir_filter(struct
> rte_eth_dev *dev,
>  	/* Check if there is the filter in SW list */
>  	memset(&check_filter, 0, sizeof(check_filter));
>  	i40e_fdir_filter_convert(filter, &check_filter);
> -	node =3D i40e_sw_fdir_filter_lookup(fdir_info, &check_filter.fdir.input=
);
> -	if (add && node) {
> -		PMD_DRV_LOG(ERR,
> -			    "Conflict with existing flow director rules!");
> -		return -EINVAL;
> -	}
>=20
> -	if (!add && !node) {
> -		PMD_DRV_LOG(ERR,
> -			    "There's no corresponding flow firector filter!");
> -		return -EINVAL;
> +	if (add) {
> +		ret =3D i40e_sw_fdir_filter_insert(pf, &check_filter);
> +		if (ret < 0) {
> +			PMD_DRV_LOG(ERR,
> +				    "Conflict with existing flow director rules!");
> +			return -EINVAL;
> +		}
> +	} else {
> +		node =3D i40e_sw_fdir_filter_lookup(fdir_info,
> +				&check_filter.fdir.input);
> +		if (!node) {
> +			PMD_DRV_LOG(ERR,
> +				    "There's no corresponding flow firector filter!");
> +			return -EINVAL;
> +		}
> +
> +		ret =3D i40e_sw_fdir_filter_del(pf, &node->fdir.input);
> +		if (ret < 0) {
> +			PMD_DRV_LOG(ERR,
> +					"Error deleting fdir rule from hash table!");
> +			return -EINVAL;
> +		}
>  	}
>=20
> -	memset(pkt, 0, I40E_FDIR_PKT_LEN);
> +	/* find a buffer to store the pkt */
> +	pkt =3D i40e_find_available_buffer(dev);
> +	if (pkt =3D=3D NULL)
> +		goto error_op;
>=20
> +	memset(pkt, 0, I40E_FDIR_PKT_LEN);
>  	ret =3D i40e_flow_fdir_construct_pkt(pf, &filter->input, pkt);
>  	if (ret < 0) {
>  		PMD_DRV_LOG(ERR, "construct packet for fdir fails.");
> -		return ret;
> +		goto error_op;
>  	}
>=20
>  	if (hw->mac.type =3D=3D I40E_MAC_X722) {
> @@ -1751,28 +1811,22 @@ i40e_flow_add_del_fdir_filter(struct
> rte_eth_dev *dev,
>  			hw, I40E_GLQF_FD_PCTYPES((int)pctype));
>  	}
>=20
> -	ret =3D i40e_flow_fdir_filter_programming(pf, pctype, filter, add);
> +	ret =3D i40e_flow_fdir_filter_programming(pf, pctype, filter, add,
> +			wait_status);
>  	if (ret < 0) {
>  		PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).",
>  			    pctype);
> -		return ret;
> +		goto error_op;
>  	}
>=20
> -	if (add) {
> -		fdir_filter =3D rte_zmalloc("fdir_filter",
> -					  sizeof(*fdir_filter), 0);
> -		if (fdir_filter =3D=3D NULL) {
> -			PMD_DRV_LOG(ERR, "Failed to alloc memory.");
> -			return -ENOMEM;
> -		}
> +	return ret;
>=20
> -		rte_memcpy(fdir_filter, &check_filter, sizeof(check_filter));
> -		ret =3D i40e_sw_fdir_filter_insert(pf, fdir_filter);
> -		if (ret < 0)
> -			rte_free(fdir_filter);
> -	} else {
> -		ret =3D i40e_sw_fdir_filter_del(pf, &node->fdir.input);
> -	}
> +error_op:
> +	/* roll back */
> +	if (add)
> +		i40e_sw_fdir_filter_del(pf, &check_filter.fdir.input);
> +	else
> +		i40e_sw_fdir_filter_insert(pf, &check_filter);
>=20
>  	return ret;
>  }
> @@ -1875,7 +1929,7 @@ i40e_fdir_filter_programming(struct i40e_pf *pf,
>=20
>  	PMD_DRV_LOG(INFO, "filling transmit descriptor.");
>  	txdp =3D &(txq->tx_ring[txq->tx_tail + 1]);
> -	txdp->buffer_addr =3D rte_cpu_to_le_64(pf->fdir.dma_addr);
> +	txdp->buffer_addr =3D rte_cpu_to_le_64(pf->fdir.dma_addr[0]);
>  	td_cmd =3D I40E_TX_DESC_CMD_EOP |
>  		 I40E_TX_DESC_CMD_RS  |
>  		 I40E_TX_DESC_CMD_DUMMY;
> @@ -1925,7 +1979,7 @@ static int
>  i40e_flow_fdir_filter_programming(struct i40e_pf *pf,
>  				  enum i40e_filter_pctype pctype,
>  				  const struct i40e_fdir_filter_conf *filter,
> -				  bool add)
> +				  bool add, bool wait_status)
>  {
>  	struct i40e_tx_queue *txq =3D pf->fdir.txq;
>  	struct i40e_rx_queue *rxq =3D pf->fdir.rxq; @@ -1933,8 +1987,10 @@
> i40e_flow_fdir_filter_programming(struct i40e_pf *pf,
>  	volatile struct i40e_tx_desc *txdp;
>  	volatile struct i40e_filter_program_desc *fdirdp;
>  	uint32_t td_cmd;
> -	uint16_t vsi_id, i;
> +	uint16_t vsi_id;
>  	uint8_t dest;
> +	uint32_t i;
> +	uint8_t retry_count =3D 0;
>=20
>  	PMD_DRV_LOG(INFO, "filling filter programming descriptor.");
>  	fdirdp =3D (volatile struct i40e_filter_program_desc *) @@ -2009,7
> +2065,8 @@ i40e_flow_fdir_filter_programming(struct i40e_pf *pf,
>=20
>  	PMD_DRV_LOG(INFO, "filling transmit descriptor.");
>  	txdp =3D &txq->tx_ring[txq->tx_tail + 1];
> -	txdp->buffer_addr =3D rte_cpu_to_le_64(pf->fdir.dma_addr);
> +	txdp->buffer_addr =3D rte_cpu_to_le_64(pf->fdir.dma_addr[txq->tx_tail /
> +2]);
> +
>  	td_cmd =3D I40E_TX_DESC_CMD_EOP |
>  		 I40E_TX_DESC_CMD_RS  |
>  		 I40E_TX_DESC_CMD_DUMMY;
> @@ -2022,25 +2079,34 @@ i40e_flow_fdir_filter_programming(struct
> i40e_pf *pf,
>  		txq->tx_tail =3D 0;
>  	/* Update the tx tail register */
>  	rte_wmb();
> +
> +	/* capture the previous error report(if any) from rx ring */
> +	while ((i40e_check_fdir_programming_status(rxq) < 0) &&
> +		(++retry_count < 100))
> +		PMD_DRV_LOG(INFO, "previous error report captured.");
> +
>  	I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail);
> -	for (i =3D 0; i < I40E_FDIR_MAX_WAIT_US; i++) {
> -		if ((txdp->cmd_type_offset_bsz &
> -				rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) =3D=3D
> -				rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))
> -			break;
> -		rte_delay_us(1);
> -	}
> -	if (i >=3D I40E_FDIR_MAX_WAIT_US) {
> -		PMD_DRV_LOG(ERR,
> -		    "Failed to program FDIR filter: time out to get DD on tx
> queue.");
> -		return -ETIMEDOUT;
> -	}
> -	/* totally delay 10 ms to check programming status*/
> -	rte_delay_us(I40E_FDIR_MAX_WAIT_US);
> -	if (i40e_check_fdir_programming_status(rxq) < 0) {
> -		PMD_DRV_LOG(ERR,
> -		    "Failed to program FDIR filter: programming status
> reported.");
> -		return -ETIMEDOUT;
> +
> +	if (wait_status) {
> +		for (i =3D 0; i < I40E_FDIR_MAX_WAIT_US; i++) {
> +			if ((txdp->cmd_type_offset_bsz &
> +					rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK))
> =3D=3D
> +
> 	rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))
> +				break;
> +			rte_delay_us(1);
> +		}
> +		if (i >=3D I40E_FDIR_MAX_WAIT_US) {
> +			PMD_DRV_LOG(ERR,
> +			    "Failed to program FDIR filter: time out to get DD on tx
> queue.");
> +			return -ETIMEDOUT;
> +		}
> +		/* totally delay 10 ms to check programming status*/
> +		rte_delay_us(I40E_FDIR_MAX_WAIT_US);
> +		if (i40e_check_fdir_programming_status(rxq) < 0) {
> +			PMD_DRV_LOG(ERR,
> +			    "Failed to program FDIR filter: programming status
> reported.");
> +			return -ETIMEDOUT;
> +		}
>  	}
>=20
>  	return 0;
> @@ -2324,7 +2390,7 @@ i40e_fdir_filter_restore(struct i40e_pf *pf)
>  	uint32_t best_cnt;     /**< Number of filters in best effort spaces. */
>=20
>  	TAILQ_FOREACH(f, fdir_list, rules)
> -		i40e_flow_add_del_fdir_filter(dev, &f->fdir, TRUE);
> +		i40e_flow_add_del_fdir_filter(dev, &f->fdir, TRUE, TRUE);
>=20
>  	fdstat =3D I40E_READ_REG(hw, I40E_PFQF_FDSTAT);
>  	guarant_cnt =3D
> diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
> index 7cd537340..260e58dc1 100644
> --- a/drivers/net/i40e/i40e_flow.c
> +++ b/drivers/net/i40e/i40e_flow.c
> @@ -17,6 +17,7 @@
>  #include <rte_malloc.h>
>  #include <rte_tailq.h>
>  #include <rte_flow_driver.h>
> +#include <rte_bitmap.h>
>=20
>  #include "i40e_logs.h"
>  #include "base/i40e_type.h"
> @@ -144,6 +145,8 @@ const struct rte_flow_ops i40e_flow_ops =3D {
>=20
>  static union i40e_filter_t cons_filter;  static enum rte_filter_type
> cons_filter_type =3D RTE_ETH_FILTER_NONE;
> +/* internal pattern w/o VOID items */
> +struct rte_flow_item g_items[32];
>=20
>  /* Pattern matched ethertype filter */
>  static enum rte_flow_item_type pattern_ethertype[] =3D { @@ -2044,9
> +2047,6 @@ i40e_flow_parse_ethertype_pattern(struct rte_eth_dev *dev,
>  	const struct rte_flow_item_eth *eth_spec;
>  	const struct rte_flow_item_eth *eth_mask;
>  	enum rte_flow_item_type item_type;
> -	uint16_t outer_tpid;
> -
> -	outer_tpid =3D i40e_get_outer_vlan(dev);
>=20
>  	for (; item->type !=3D RTE_FLOW_ITEM_TYPE_END; item++) {
>  		if (item->last) {
> @@ -2106,7 +2106,7 @@ i40e_flow_parse_ethertype_pattern(struct
> rte_eth_dev *dev,
>  			if (filter->ether_type =3D=3D RTE_ETHER_TYPE_IPV4 ||
>  			    filter->ether_type =3D=3D RTE_ETHER_TYPE_IPV6 ||
>  			    filter->ether_type =3D=3D RTE_ETHER_TYPE_LLDP ||
> -			    filter->ether_type =3D=3D outer_tpid) {
> +			    filter->ether_type =3D=3D i40e_get_outer_vlan(dev)) {
>  				rte_flow_error_set(error, EINVAL,
>  						   RTE_FLOW_ERROR_TYPE_ITEM,
>  						   item,
> @@ -2349,6 +2349,7 @@ i40e_flow_set_fdir_flex_pit(struct i40e_pf *pf,
>  		field_idx =3D layer_idx * I40E_MAX_FLXPLD_FIED + i;
>  		flx_pit =3D MK_FLX_PIT(min_next_off, NONUSE_FLX_PIT_FSIZE,
>  				     NONUSE_FLX_PIT_DEST_OFF);
> +
>  		I40E_WRITE_REG(hw, I40E_PRTQF_FLX_PIT(field_idx), flx_pit);
>  		min_next_off++;
>  	}
> @@ -2608,7 +2609,6 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev
> *dev,
>  	uint16_t flex_size;
>  	bool cfg_flex_pit =3D true;
>  	bool cfg_flex_msk =3D true;
> -	uint16_t outer_tpid;
>  	uint16_t ether_type;
>  	uint32_t vtc_flow_cpu;
>  	bool outer_ip =3D true;
> @@ -2617,7 +2617,6 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev
> *dev,
>  	memset(off_arr, 0, sizeof(off_arr));
>  	memset(len_arr, 0, sizeof(len_arr));
>  	memset(flex_mask, 0, I40E_FDIR_MAX_FLEX_LEN);
> -	outer_tpid =3D i40e_get_outer_vlan(dev);
>  	filter->input.flow_ext.customized_pctype =3D false;
>  	for (; item->type !=3D RTE_FLOW_ITEM_TYPE_END; item++) {
>  		if (item->last) {
> @@ -2685,7 +2684,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev
> *dev,
>  				if (next_type =3D=3D RTE_FLOW_ITEM_TYPE_VLAN ||
>  				    ether_type =3D=3D RTE_ETHER_TYPE_IPV4 ||
>  				    ether_type =3D=3D RTE_ETHER_TYPE_IPV6 ||
> -				    ether_type =3D=3D outer_tpid) {
> +				    ether_type =3D=3D i40e_get_outer_vlan(dev)) {
>  					rte_flow_error_set(error, EINVAL,
>  						     RTE_FLOW_ERROR_TYPE_ITEM,
>  						     item,
> @@ -2729,7 +2728,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev
> *dev,
>=20
>  				if (ether_type =3D=3D RTE_ETHER_TYPE_IPV4 ||
>  				    ether_type =3D=3D RTE_ETHER_TYPE_IPV6 ||
> -				    ether_type =3D=3D outer_tpid) {
> +				    ether_type =3D=3D i40e_get_outer_vlan(dev)) {
>  					rte_flow_error_set(error, EINVAL,
>  						     RTE_FLOW_ERROR_TYPE_ITEM,
>  						     item,
> @@ -5263,7 +5262,6 @@ i40e_flow_validate(struct rte_eth_dev *dev,
>  				   NULL, "NULL attribute.");
>  		return -rte_errno;
>  	}
> -
>  	memset(&cons_filter, 0, sizeof(cons_filter));
>=20
>  	/* Get the non-void item of action */
> @@ -5285,12 +5283,18 @@ i40e_flow_validate(struct rte_eth_dev *dev,
>  	}
>  	item_num++;
>=20
> -	items =3D rte_zmalloc("i40e_pattern",
> -			    item_num * sizeof(struct rte_flow_item), 0);
> -	if (!items) {
> -		rte_flow_error_set(error, ENOMEM,
> RTE_FLOW_ERROR_TYPE_ITEM_NUM,
> -				   NULL, "No memory for PMD internal items.");
> -		return -ENOMEM;
> +	if (item_num <=3D ARRAY_SIZE(g_items)) {
> +		items =3D g_items;
> +	} else {
> +		items =3D rte_zmalloc("i40e_pattern",
> +				    item_num * sizeof(struct rte_flow_item), 0);
> +		if (!items) {
> +			rte_flow_error_set(error, ENOMEM,
> +					RTE_FLOW_ERROR_TYPE_ITEM_NUM,
> +					NULL,
> +					"No memory for PMD internal items.");
> +			return -ENOMEM;
> +		}
>  	}
>=20
>  	i40e_pattern_skip_void_item(items, pattern); @@ -5298,20 +5302,26
> @@ i40e_flow_validate(struct rte_eth_dev *dev,
>  	i =3D 0;
>  	do {
>  		parse_filter =3D i40e_find_parse_filter_func(items, &i);
> +
>  		if (!parse_filter && !flag) {
>  			rte_flow_error_set(error, EINVAL,
>  					   RTE_FLOW_ERROR_TYPE_ITEM,
>  					   pattern, "Unsupported pattern");
> -			rte_free(items);
> +
> +			if (items !=3D g_items)
> +				rte_free(items);
>  			return -rte_errno;
>  		}
> +
>  		if (parse_filter)
>  			ret =3D parse_filter(dev, attr, items, actions,
>  					   error, &cons_filter);
> +
>  		flag =3D true;
>  	} while ((ret < 0) && (i < RTE_DIM(i40e_supported_patterns)));
>=20
> -	rte_free(items);
> +	if (items !=3D g_items)
> +		rte_free(items);
>=20
>  	return ret;
>  }
> @@ -5324,21 +5334,67 @@ i40e_flow_create(struct rte_eth_dev *dev,
>  		 struct rte_flow_error *error)
>  {
>  	struct i40e_pf *pf =3D
> I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
> -	struct rte_flow *flow;
> +	struct rte_flow *flow =3D NULL;
> +	struct i40e_fdir_info *fdir_info =3D &pf->fdir;
> +	uint32_t i =3D 0;
> +	uint32_t pos =3D 0;
> +	uint64_t slab =3D 0;
> +	bool wait_for_status =3D true;
>  	int ret;
>=20
> -	flow =3D rte_zmalloc("i40e_flow", sizeof(struct rte_flow), 0);
> -	if (!flow) {
> -		rte_flow_error_set(error, ENOMEM,
> -				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
> -				   "Failed to allocate memory");
> -		return flow;
> -	}
> -
>  	ret =3D i40e_flow_validate(dev, attr, pattern, actions, error);
>  	if (ret < 0)
>  		return NULL;
>=20
> +	if (cons_filter_type =3D=3D RTE_ETH_FILTER_FDIR) {
> +		if (fdir_info->fdir_actual_cnt >=3D
> +				fdir_info->fdir_space_size) {
> +			rte_flow_error_set(error, ENOMEM,
> +					   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
> +					   "Fdir space full");
> +			return NULL;
> +		}
> +
> +		ret =3D rte_bitmap_scan(fdir_info->fdir_flow_bitmap.b, &pos,
> +				&slab);
> +
> +		/* normally this won't happen as the fdir_actual_cnt should be
> +		 * same with the number of the set bits in fdir_flow_bitmap,
> +		 * but anyway handle this error condition here for safe
> +		 */
> +		if (ret =3D=3D 0) {
> +			PMD_DRV_LOG(ERR, "fdir_actual_cnt out of sync");
> +			rte_flow_error_set(error, ENOMEM,
> +					   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
> +					   "Fdir space full");
> +			return NULL;
> +		}
> +
> +		i =3D rte_bsf64(slab);
> +		pos +=3D i;
> +		rte_bitmap_clear(fdir_info->fdir_flow_bitmap.b, pos);
> +		flow =3D &fdir_info->fdir_flow_bitmap.fdir_flow[pos].flow;
> +		memset(flow, 0, sizeof(struct rte_flow));
> +
> +		if (fdir_info->fdir_invalprio =3D=3D 1) {
> +			if (fdir_info->fdir_guarantee_free_space > 0) {
> +				fdir_info->fdir_guarantee_free_space--;
> +				wait_for_status =3D false;
> +			}
> +		}
> +
> +		fdir_info->fdir_actual_cnt++;
> +
> +	} else {
> +		flow =3D rte_zmalloc("i40e_flow", sizeof(struct rte_flow), 0);
> +		if (!flow) {
> +			rte_flow_error_set(error, ENOMEM,
> +					   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
> +					   "Failed to allocate memory");
> +			return flow;
> +		}
> +	}
> +
>  	switch (cons_filter_type) {
>  	case RTE_ETH_FILTER_ETHERTYPE:
>  		ret =3D i40e_ethertype_filter_set(pf,
> @@ -5350,9 +5406,17 @@ i40e_flow_create(struct rte_eth_dev *dev,
>  		break;
>  	case RTE_ETH_FILTER_FDIR:
>  		ret =3D i40e_flow_add_del_fdir_filter(dev,
> -				       &cons_filter.fdir_filter, 1);
> -		if (ret)
> +			       &cons_filter.fdir_filter, 1,
> +			       wait_for_status);
> +		if (ret) {
> +			rte_bitmap_set(fdir_info->fdir_flow_bitmap.b, pos);
> +			fdir_info->fdir_actual_cnt--;
> +			if (fdir_info->fdir_invalprio =3D=3D 1)
> +				fdir_info->fdir_guarantee_free_space++;
> +
>  			goto free_flow;
> +		}
> +
>  		flow->rule =3D TAILQ_LAST(&pf->fdir.fdir_list,
>  					i40e_fdir_filter_list);
>  		break;
> @@ -5384,7 +5448,10 @@ i40e_flow_create(struct rte_eth_dev *dev,
>  	rte_flow_error_set(error, -ret,
>  			   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
>  			   "Failed to create flow.");
> -	rte_free(flow);
> +
> +	if (cons_filter_type !=3D RTE_ETH_FILTER_FDIR)
> +		rte_free(flow);
> +
>  	return NULL;
>  }
>=20
> @@ -5394,7 +5461,9 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
>  		  struct rte_flow_error *error)
>  {
>  	struct i40e_pf *pf =3D
> I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
> +	struct i40e_fdir_info *fdir_info =3D &pf->fdir;
>  	enum rte_filter_type filter_type =3D flow->filter_type;
> +	struct i40e_fdir_flows *f;
>  	int ret =3D 0;
>=20
>  	switch (filter_type) {
> @@ -5408,7 +5477,8 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
>  		break;
>  	case RTE_ETH_FILTER_FDIR:
>  		ret =3D i40e_flow_add_del_fdir_filter(dev,
> -		       &((struct i40e_fdir_filter *)flow->rule)->fdir, 0);
> +				&((struct i40e_fdir_filter *)flow->rule)->fdir,
> +				0, false);
>=20
>  		/* If the last flow is destroyed, disable fdir. */
>  		if (!ret && TAILQ_EMPTY(&pf->fdir.fdir_list)) { @@ -5428,11
> +5498,27 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
>=20
>  	if (!ret) {
>  		TAILQ_REMOVE(&pf->flow_list, flow, node);
> -		rte_free(flow);
> -	} else
> +		if (filter_type =3D=3D RTE_ETH_FILTER_FDIR) {
> +			f =3D FLOW_TO_FLOW_BITMAP(flow);
> +			rte_bitmap_set(fdir_info->fdir_flow_bitmap.b, f->idx);
> +			fdir_info->fdir_actual_cnt--;
> +
> +			if (fdir_info->fdir_invalprio =3D=3D 1)
> +				/* check if the budget will be gained back to
> +				 * guaranteed space
> +				 */
> +				if (fdir_info->fdir_guarantee_free_space <
> +					fdir_info->fdir_guarantee_available_space)
> +					fdir_info->fdir_guarantee_free_space++;
> +		} else {
> +			rte_free(flow);
> +		}
> +
> +	} else {
>  		rte_flow_error_set(error, -ret,
>  				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
>  				   "Failed to destroy flow.");
> +	}
>=20
>  	return ret;
>  }
> @@ -5582,6 +5668,7 @@ i40e_flow_flush_fdir_filter(struct i40e_pf *pf)
>  	struct rte_flow *flow;
>  	void *temp;
>  	int ret;
> +	uint32_t i =3D 0;
>=20
>  	ret =3D i40e_fdir_flush(dev);
>  	if (!ret) {
> @@ -5597,10 +5684,24 @@ i40e_flow_flush_fdir_filter(struct i40e_pf *pf)
>  		TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) {
>  			if (flow->filter_type =3D=3D RTE_ETH_FILTER_FDIR) {
>  				TAILQ_REMOVE(&pf->flow_list, flow, node);
> -				rte_free(flow);
>  			}
>  		}
>=20
> +		/* clear bitmap */
> +		rte_bitmap_reset(fdir_info->fdir_flow_bitmap.b);
> +		for (i =3D 0; i < fdir_info->fdir_space_size; i++) {
> +			fdir_info->fdir_flow_bitmap.fdir_flow[i].idx =3D i;
> +			rte_bitmap_set(fdir_info->fdir_flow_bitmap.b, i);
> +		}
> +
> +		fdir_info->fdir_actual_cnt =3D 0;
> +		fdir_info->fdir_guarantee_free_space =3D
> +			fdir_info->fdir_guarantee_available_space;
> +		memset(fdir_info->fdir_filter_array,
> +			0,
> +			sizeof(struct i40e_fdir_filter) *
> +			I40E_MAX_FDIR_FILTER_NUM);
> +
>  		for (pctype =3D I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
>  		     pctype <=3D I40E_FILTER_PCTYPE_L2_PAYLOAD; pctype++)
>  			pf->fdir.inset_flag[pctype] =3D 0;
> diff --git a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c =
index
> 840b6f387..f5235864d 100644
> --- a/drivers/net/i40e/i40e_rxtx.c
> +++ b/drivers/net/i40e/i40e_rxtx.c
> @@ -2938,16 +2938,17 @@ i40e_dev_free_queues(struct rte_eth_dev
> *dev)
>  	}
>  }
>=20
> -#define I40E_FDIR_NUM_TX_DESC  I40E_MIN_RING_DESC -#define
> I40E_FDIR_NUM_RX_DESC  I40E_MIN_RING_DESC
> +#define I40E_FDIR_NUM_TX_DESC  256
> +#define I40E_FDIR_NUM_RX_DESC  256
>=20
>  enum i40e_status_code
>  i40e_fdir_setup_tx_resources(struct i40e_pf *pf)  {
>  	struct i40e_tx_queue *txq;
>  	const struct rte_memzone *tz =3D NULL;
> -	uint32_t ring_size;
> +	uint32_t ring_size, i;
>  	struct rte_eth_dev *dev;
> +	volatile struct i40e_tx_desc *txdp;
>=20
>  	if (!pf) {
>  		PMD_DRV_LOG(ERR, "PF is not available"); @@ -2987,6 +2988,14
> @@ i40e_fdir_setup_tx_resources(struct i40e_pf *pf)
>=20
>  	txq->tx_ring_phys_addr =3D tz->iova;
>  	txq->tx_ring =3D (struct i40e_tx_desc *)tz->addr;
> +
> +	/* Set all the DD flags to 1 */
> +	for (i =3D 0; i < I40E_FDIR_NUM_TX_DESC; i +=3D 2) {
> +		txdp =3D &txq->tx_ring[i + 1];
> +		txdp->cmd_type_offset_bsz |=3D
> I40E_TX_DESC_DTYPE_DESC_DONE;
> +		txdp->buffer_addr =3D rte_cpu_to_le_64(pf->fdir.dma_addr[i / 2]);
> +	}

DD bits are assume to be reported by hardware, why we initialize them to 1 =
?

> +
>  	/*
>  	 * don't need to allocate software ring and reset for the fdir
>  	 * program queue just set the queue has been configured.
> diff --git a/drivers/net/i40e/rte_pmd_i40e.c
> b/drivers/net/i40e/rte_pmd_i40e.c index e216e6783..c52a5af2e 100644
> --- a/drivers/net/i40e/rte_pmd_i40e.c
> +++ b/drivers/net/i40e/rte_pmd_i40e.c
> @@ -3060,7 +3060,7 @@ int
> rte_pmd_i40e_flow_add_del_packet_template(
>  		(enum i40e_fdir_status)conf->action.report_status;
>  	filter_conf.action.flex_off =3D conf->action.flex_off;
>=20
> -	return i40e_flow_add_del_fdir_filter(dev, &filter_conf, add);
> +	return i40e_flow_add_del_fdir_filter(dev, &filter_conf, add, true);
>  }
>=20
>  int
> --
> 2.17.1