DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2] drivers: advertise kmod dependencies in pmdinfo
From: Adrien Mazarguil @ 2016-11-22 10:27 UTC (permalink / raw)
  To: Olivier Matz; +Cc: dev, nhorman, thomas.monjalon, vido, fiona.trahe, stephen
In-Reply-To: <1479808257-8725-1-git-send-email-olivier.matz@6wind.com>

Hi Olivier,

Neither mlx4 nor mlx5 depend on igb/uio/vfio modules, please see below.

On Tue, Nov 22, 2016 at 10:50:57AM +0100, Olivier Matz wrote:
> Add a new macro RTE_PMD_REGISTER_KMOD_DEP() that allows a driver to
> declare the list of kernel modules required to run properly.
> 
> Today, most PCI drivers require uio/vfio.
> 
> Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
> Acked-by: Fiona Trahe <fiona.trahe@intel.com>
> ---
[...]
> diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
> index da61a85..a0065bf 100644
> --- a/drivers/net/mlx4/mlx4.c
> +++ b/drivers/net/mlx4/mlx4.c
> @@ -5937,3 +5937,4 @@ rte_mlx4_pmd_init(void)
>  
>  RTE_PMD_EXPORT_NAME(net_mlx4, __COUNTER__);
>  RTE_PMD_REGISTER_PCI_TABLE(net_mlx4, mlx4_pci_id_map);
> +RTE_PMD_REGISTER_KMOD_DEP(net_mlx4, "* igb_uio | uio_pci_generic | vfio");

RTE_PMD_REGISTER_KMOD_DEP(net_mlx4, "* ib_uverbs & mlx4_en & mlx4_core & mlx4_ib");

> diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
> index 90cc35e..b0343f3 100644
> --- a/drivers/net/mlx5/mlx5.c
> +++ b/drivers/net/mlx5/mlx5.c
> @@ -759,3 +759,4 @@ rte_mlx5_pmd_init(void)
> 
>  RTE_PMD_EXPORT_NAME(net_mlx5, __COUNTER__);
>  RTE_PMD_REGISTER_PCI_TABLE(net_mlx5, mlx5_pci_id_map);
> +RTE_PMD_REGISTER_KMOD_DEP(net_mlx5, "* igb_uio | uio_pci_generic | vfio");

RTE_PMD_REGISTER_KMOD_DEP(net_mlx5, "* ib_uverbs & mlx5_core & mlx5_ib");

-- 
Adrien Mazarguil
6WIND

^ permalink raw reply

* Re: [PATCH v2 1/8] eal: define container_of macro
From: Thomas Monjalon @ 2016-11-22 10:19 UTC (permalink / raw)
  To: Shreyansh Jain, Jan Blunck; +Cc: dev, david.marchand, Jan Viktorin
In-Reply-To: <f22c697c-e49f-1e81-fa0f-cea50b031092@nxp.com>

2016-11-22 15:33, Shreyansh Jain:
> On Monday 21 November 2016 10:25 PM, Jan Blunck wrote:
> > This macro is based on Jan Viktorin's original patch but also checks the
> > type of the passed pointer against the type of the member.
> >
> > Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
> > Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> > [jblunck@infradead.org: add type checking and __extension__]
> > Signed-off-by: Jan Blunck <jblunck@infradead.org>
> 
> I will start using this in my patchset.
> 
> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

It is a bit strange to have this patch in a series which do
not use it. I am in favor of getting it when it is used
(and included) in another series.

^ permalink raw reply

* [PATCH] mempool: fix Api documentation
From: Olivier Matz @ 2016-11-22 10:04 UTC (permalink / raw)
  To: dev; +Cc: keith.wiles

A previous commit changed the local_cache table into a
pointer, reducing the size of the rte_mempool structure.

Fix the API comment of rte_mempool_create() related to
this modification.

Fixes: 213af31e0960 ("mempool: reduce structure size if no cache needed")

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_mempool/rte_mempool.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/librte_mempool/rte_mempool.h b/lib/librte_mempool/rte_mempool.h
index 440f3b1..956ce04 100644
--- a/lib/librte_mempool/rte_mempool.h
+++ b/lib/librte_mempool/rte_mempool.h
@@ -610,9 +610,7 @@ typedef void (rte_mempool_ctor_t)(struct rte_mempool *, void *);
  *   never be used. The access to the per-lcore table is of course
  *   faster than the multi-producer/consumer pool. The cache can be
  *   disabled if the cache_size argument is set to 0; it can be useful to
- *   avoid losing objects in cache. Note that even if not used, the
- *   memory space for cache is always reserved in a mempool structure,
- *   except if CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE is set to 0.
+ *   avoid losing objects in cache.
  * @param private_data_size
  *   The size of the private data appended after the mempool
  *   structure. This is useful for storing some private data after the
-- 
2.8.1

^ permalink raw reply related

* Re: [PATCH v2 1/8] eal: define container_of macro
From: Shreyansh Jain @ 2016-11-22 10:03 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev, david.marchand, Jan Viktorin
In-Reply-To: <1479747322-5774-1-git-send-email-jblunck@infradead.org>

On Monday 21 November 2016 10:25 PM, Jan Blunck wrote:
> This macro is based on Jan Viktorin's original patch but also checks the
> type of the passed pointer against the type of the member.
>
> Signed-off-by: Jan Viktorin <viktorin@rehivetech.com>
> Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> [jblunck@infradead.org: add type checking and __extension__]
> Signed-off-by: Jan Blunck <jblunck@infradead.org>
> ---
>  lib/librte_eal/common/include/rte_common.h | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
>
> diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> index db5ac91..8dda3e2 100644
> --- a/lib/librte_eal/common/include/rte_common.h
> +++ b/lib/librte_eal/common/include/rte_common.h
> @@ -331,6 +331,26 @@ rte_bsf32(uint32_t v)
>  #define offsetof(TYPE, MEMBER)  __builtin_offsetof (TYPE, MEMBER)
>  #endif
>
> +/**
> + * Return pointer to the wrapping struct instance.
> + *
> + * Example:
> + *
> + *  struct wrapper {
> + *      ...
> + *      struct child c;
> + *      ...
> + *  };
> + *
> + *  struct child *x = obtain(...);
> + *  struct wrapper *w = container_of(x, struct wrapper, c);
> + */
> +#ifndef container_of
> +#define container_of(ptr, type, member)	__extension__ ({		\
> +			typeof(((type *)0)->member) *_ptr = (ptr);	\
> +			(type *)(((char *)_ptr) - offsetof(type, member)); })
> +#endif
> +
>  #define _RTE_STR(x) #x
>  /** Take a macro value and get a string version of it */
>  #define RTE_STR(x) _RTE_STR(x)
>

I will start using this in my patchset.

Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

^ permalink raw reply

* Re: [PATCH] virtio: tx with can_push when VERSION_1 is set
From: Pierre Pfister (ppfister) @ 2016-11-22  9:54 UTC (permalink / raw)
  To: Maxime Coquelin; +Cc: Yuanhan Liu, dev@dpdk.org
In-Reply-To: <5c99bc35-839b-84b8-1df9-db80f288d7b7@redhat.com>

Hello Maxime,

> Le 9 nov. 2016 à 15:51, Maxime Coquelin <maxime.coquelin@redhat.com> a écrit :
> 
> Hi Pierre,
> 
> On 11/09/2016 01:42 PM, Pierre Pfister (ppfister) wrote:
>> Hello Maxime,
>> 
>> Sorry for the late reply.
>> 
>> 
>>> Le 8 nov. 2016 à 10:44, Maxime Coquelin <maxime.coquelin@redhat.com> a écrit :
>>> 
>>> Hi Pierre,
>>> 
>>> On 11/08/2016 10:31 AM, Pierre Pfister (ppfister) wrote:
>>>> Current virtio driver advertises VERSION_1 support,
>>>> but does not handle device's VERSION_1 support when
>>>> sending packets (it looks for ANY_LAYOUT feature,
>>>> which is absent).
>>>> 
>>>> This patch enables 'can_push' in tx path when VERSION_1
>>>> is advertised by the device.
>>>> 
>>>> This significantly improves small packets forwarding rate
>>>> towards devices advertising VERSION_1 feature.
>>> I think it depends whether offloading is enabled or not.
>>> If no offloading enabled, I measured significant drop.
>>> Indeed, when no offloading is enabled, the Tx path in Virtio
>>> does not access the virtio header before your patch, as the header is memset to zero at device init time.
>>> With your patch, it gets memset to zero at every transmit in the hot
>>> path.
>> 
>> Right. On the virtio side that is true, but on the device side, we have to access the header anyway.
> No more now, if no offload features have been negotiated.
> I have done a patch that landed in v16.11 to skip header parsing in
> this case.
> That said, we still have to access its descriptor.
> 
>> And accessing two descriptors (with the address resolution and memory fetch which comes with it)
>> is a costy operation compared to a single one.
>> In the case indirect descriptors are used, this is 1 desc access instead or 3.
> I agree this is far from being optimal.
> 
>> And in the case chained descriptors are used, this doubles the number of packets that you can put in your queue.
>> 
>> Those are the results in my PHY -> VM (testpmd) -> PHY setup
>> Traffic is flowing bidirectionally. Numbers are for lossless-rates.
>> 
>> When chained buffers are used for dpdk's TX: 2x2.13Mpps
>> When indirect descriptors are used for dpdk's TX: 2x2.38Mpps
>> When shallow buffers are used for dpdk's TX (with this patch): 2x2.42Mpps
> When I tried it, I also did PVP 0% benchmark, and I got opposite results. Chained and indirect cases were significantly better.
> 
> My PVP setup was using a single NIC and single Virtio PMD, and NIC2VM
> forwarding was IO mode done with testpmd on host, and Rx->Tx forwarding
> was macswap mode on guest side.
> 
> I also saw some perf regression when running simple tespmd test on both
> ends.
> 
> Yuanhan, did you run some benchmark with your series enabling
> ANY_LAYOUT?

It was enabled. But the specs specify that VERSION_1 includes ANY_LAYOUT.
Therefor, Qemu removes ANY_LAYOUT when VERSION_1 is set.

We can keep arguing about which is fastest. I guess we have different setups and different results, so we probably are deadlocked here.
But in any case, the current code is inconsistent, as it uses single descriptor when ANY_LAYOUT is set, but not when VERSION_1 is set.

I believe it makes sense to use single-descriptor any time it is possible, but you are free to think otherwise.
Please make a call and make the code consistent (removes single-descriptors all together, or use them when VERSION_1 is set too). Otherwise it just creates yet-another testing headache. 

Thanks,

- Pierre 

> 
>> 
>> I must also note that qemu 2.5 does not seem to deal with VERSION_1 and ANY_LAYOUT correctly.
>> The patch I am proposing here works for qemu 2.7, but with qemu 2.5, testpmd still behaves as if ANY_LAYOUT (or VERSION_1) was not available. This is not catastrophic. But just note that you will not see performance in some cases with qemu 2.5.
> 
> Thanks for the info.
> 
> Regards,
> Maxime


^ permalink raw reply

* [PATCH v2] drivers: advertise kmod dependencies in pmdinfo
From: Olivier Matz @ 2016-11-22  9:50 UTC (permalink / raw)
  To: dev; +Cc: nhorman, thomas.monjalon, vido, fiona.trahe, stephen
In-Reply-To: <1473949355-6787-1-git-send-email-olivier.matz@6wind.com>

Add a new macro RTE_PMD_REGISTER_KMOD_DEP() that allows a driver to
declare the list of kernel modules required to run properly.

Today, most PCI drivers require uio/vfio.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
Acked-by: Fiona Trahe <fiona.trahe@intel.com>
---

v1 -> v2:                                                                                                
- do not advertise uio_pci_generic for vf drivers
- rebase on top of head: use new driver names and prefix
  macro with RTE_                                                                                       

rfc -> v1:
- the kmod information can be per-device using a modalias-like
  pattern
- change syntax to use '&' and '|' instead of ',' and ':'
- remove useless prerequisites in kmod lis: no need to
  specify both uio and uio_pci_generic, only the latter is
  required
- update kmod list in szedata2 driver
- remove kmod list in qat driver: it requires more than just loading
  a kmod, which is described in documentation


 buildtools/pmdinfogen/pmdinfogen.c      |  1 +
 buildtools/pmdinfogen/pmdinfogen.h      |  1 +
 drivers/net/bnx2x/bnx2x_ethdev.c        |  2 ++
 drivers/net/bnxt/bnxt_ethdev.c          |  1 +
 drivers/net/cxgbe/cxgbe_ethdev.c        |  1 +
 drivers/net/e1000/em_ethdev.c           |  1 +
 drivers/net/e1000/igb_ethdev.c          |  2 ++
 drivers/net/ena/ena_ethdev.c            |  1 +
 drivers/net/enic/enic_ethdev.c          |  1 +
 drivers/net/fm10k/fm10k_ethdev.c        |  1 +
 drivers/net/i40e/i40e_ethdev.c          |  1 +
 drivers/net/i40e/i40e_ethdev_vf.c       |  1 +
 drivers/net/ixgbe/ixgbe_ethdev.c        |  2 ++
 drivers/net/mlx4/mlx4.c                 |  1 +
 drivers/net/mlx5/mlx5.c                 |  1 +
 drivers/net/nfp/nfp_net.c               |  1 +
 drivers/net/qede/qede_ethdev.c          |  2 ++
 drivers/net/szedata2/rte_eth_szedata2.c |  2 ++
 drivers/net/thunderx/nicvf_ethdev.c     |  1 +
 drivers/net/virtio/virtio_ethdev.c      |  1 +
 drivers/net/vmxnet3/vmxnet3_ethdev.c    |  1 +
 lib/librte_eal/common/include/rte_dev.h | 25 +++++++++++++++++++++++++
 tools/dpdk-pmdinfo.py                   |  5 ++++-
 23 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/buildtools/pmdinfogen/pmdinfogen.c b/buildtools/pmdinfogen/pmdinfogen.c
index 59ab956..5129c57 100644
--- a/buildtools/pmdinfogen/pmdinfogen.c
+++ b/buildtools/pmdinfogen/pmdinfogen.c
@@ -269,6 +269,7 @@ struct opt_tag {
 
 static const struct opt_tag opt_tags[] = {
 	{"_param_string_export", "params"},
+	{"_kmod_dep_export", "kmod"},
 };
 
 static int complete_pmd_entry(struct elf_info *info, struct pmd_driver *drv)
diff --git a/buildtools/pmdinfogen/pmdinfogen.h b/buildtools/pmdinfogen/pmdinfogen.h
index 1da2966..2fab2aa 100644
--- a/buildtools/pmdinfogen/pmdinfogen.h
+++ b/buildtools/pmdinfogen/pmdinfogen.h
@@ -85,6 +85,7 @@ else \
 
 enum opt_params {
 	PMD_PARAM_STRING = 0,
+	PMD_KMOD_DEP,
 	PMD_OPT_MAX
 };
 
diff --git a/drivers/net/bnx2x/bnx2x_ethdev.c b/drivers/net/bnx2x/bnx2x_ethdev.c
index 0eae433..0f1e4a2 100644
--- a/drivers/net/bnx2x/bnx2x_ethdev.c
+++ b/drivers/net/bnx2x/bnx2x_ethdev.c
@@ -643,5 +643,7 @@ static struct eth_driver rte_bnx2xvf_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_bnx2x, rte_bnx2x_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_bnx2x, pci_id_bnx2x_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_bnx2x, "* igb_uio | uio_pci_generic | vfio");
 RTE_PMD_REGISTER_PCI(net_bnx2xvf, rte_bnx2xvf_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_bnx2xvf, pci_id_bnx2xvf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_bnx2xvf, "* igb_uio | vfio");
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 035fe07..a24e153 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -1173,3 +1173,4 @@ static struct eth_driver bnxt_rte_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_bnxt, bnxt_rte_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_bnxt, bnxt_pci_id_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_bnxt, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index b7f28eb..317598d 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -1050,3 +1050,4 @@ static struct eth_driver rte_cxgbe_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_cxgbe, rte_cxgbe_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_cxgbe, cxgb4_pci_tbl);
+RTE_PMD_REGISTER_KMOD_DEP(net_cxgbe, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index aee3d34..866a5cf 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -1807,3 +1807,4 @@ eth_em_set_mc_addr_list(struct rte_eth_dev *dev,
 
 RTE_PMD_REGISTER_PCI(net_e1000_em, rte_em_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_e1000_em, pci_id_em_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_e1000_em, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index 2fddf0c..08f2a68 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -5240,5 +5240,7 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
 
 RTE_PMD_REGISTER_PCI(net_e1000_igb, rte_igb_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_e1000_igb, pci_id_igb_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_e1000_igb, "* igb_uio | uio_pci_generic | vfio");
 RTE_PMD_REGISTER_PCI(net_e1000_igb_vf, rte_igbvf_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_e1000_igb_vf, pci_id_igbvf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_e1000_igb_vf, "* igb_uio | vfio");
diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index ab9a178..555fb31 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -1716,3 +1716,4 @@ static struct eth_driver rte_ena_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_ena, rte_ena_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_ena, pci_id_ena_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ena, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index 2b154ec..f997302 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -645,3 +645,4 @@ static struct eth_driver rte_enic_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_enic, rte_enic_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_enic, pci_id_enic_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_enic, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index 923690c..fe74f6d 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -3074,3 +3074,4 @@ static struct eth_driver rte_pmd_fm10k = {
 
 RTE_PMD_REGISTER_PCI(net_fm10k, rte_pmd_fm10k.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_fm10k, pci_id_fm10k_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_fm10k, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67778ba..b0c0fbf 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -711,6 +711,7 @@ rte_i40e_dev_atomic_write_link_status(struct rte_eth_dev *dev,
 
 RTE_PMD_REGISTER_PCI(net_i40e, rte_i40e_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_i40e, pci_id_i40e_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_i40e, "* igb_uio | uio_pci_generic | vfio");
 
 #ifndef I40E_GLQF_ORT
 #define I40E_GLQF_ORT(_i)    (0x00268900 + ((_i) * 4))
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index aa306d6..7869b9b 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -1539,6 +1539,7 @@ static struct eth_driver rte_i40evf_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_i40e_vf, rte_i40evf_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_i40e_vf, pci_id_i40evf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_i40e_vf, "* igb_uio | vfio");
 
 static int
 i40evf_dev_configure(struct rte_eth_dev *dev)
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index edc9b22..baffc71 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -7594,5 +7594,7 @@ ixgbevf_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
 
 RTE_PMD_REGISTER_PCI(net_ixgbe, rte_ixgbe_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_ixgbe, pci_id_ixgbe_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ixgbe, "* igb_uio | uio_pci_generic | vfio");
 RTE_PMD_REGISTER_PCI(net_ixgbe_vf, rte_ixgbevf_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_ixgbe_vf, pci_id_ixgbevf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ixgbe_vf, "* igb_uio | vfio");
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index da61a85..a0065bf 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -5937,3 +5937,4 @@ rte_mlx4_pmd_init(void)
 
 RTE_PMD_EXPORT_NAME(net_mlx4, __COUNTER__);
 RTE_PMD_REGISTER_PCI_TABLE(net_mlx4, mlx4_pci_id_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_mlx4, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 90cc35e..b0343f3 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -759,3 +759,4 @@ rte_mlx5_pmd_init(void)
 
 RTE_PMD_EXPORT_NAME(net_mlx5, __COUNTER__);
 RTE_PMD_REGISTER_PCI_TABLE(net_mlx5, mlx5_pci_id_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_mlx5, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index c6b1587..707be8b 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -2481,6 +2481,7 @@ static struct eth_driver rte_nfp_net_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_nfp, rte_nfp_net_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_nfp, pci_id_nfp_net_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_nfp, "* igb_uio | uio_pci_generic | vfio");
 
 /*
  * Local variables:
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index d106dd0..001166a 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -1668,5 +1668,7 @@ static struct eth_driver rte_qede_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_qede, rte_qede_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_qede, pci_id_qede_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_qede, "* igb_uio | uio_pci_generic | vfio");
 RTE_PMD_REGISTER_PCI(net_qede_vf, rte_qedevf_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_qede_vf, pci_id_qedevf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_qede_vf, "* igb_uio | vfio");
diff --git a/drivers/net/szedata2/rte_eth_szedata2.c b/drivers/net/szedata2/rte_eth_szedata2.c
index f3cd52d..677ba9f 100644
--- a/drivers/net/szedata2/rte_eth_szedata2.c
+++ b/drivers/net/szedata2/rte_eth_szedata2.c
@@ -1583,3 +1583,5 @@ static struct eth_driver szedata2_eth_driver = {
 
 RTE_PMD_REGISTER_PCI(RTE_SZEDATA2_DRIVER_NAME, szedata2_eth_driver.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(RTE_SZEDATA2_DRIVER_NAME, rte_szedata2_pci_id_table);
+RTE_PMD_REGISTER_KMOD_DEP(RTE_SZEDATA2_DRIVER_NAME,
+	"* combo6core & combov3 & szedata2 & szedata2_cv3");
diff --git a/drivers/net/thunderx/nicvf_ethdev.c b/drivers/net/thunderx/nicvf_ethdev.c
index 466e49c..db03fa8 100644
--- a/drivers/net/thunderx/nicvf_ethdev.c
+++ b/drivers/net/thunderx/nicvf_ethdev.c
@@ -2121,3 +2121,4 @@ static struct eth_driver rte_nicvf_pmd = {
 
 RTE_PMD_REGISTER_PCI(net_thunderx, rte_nicvf_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_thunderx, pci_id_nicvf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_thunderx, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 079fd6c..1bd60e9 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1669,3 +1669,4 @@ __rte_unused uint8_t is_rx)
 
 RTE_PMD_EXPORT_NAME(net_virtio, __COUNTER__);
 RTE_PMD_REGISTER_PCI_TABLE(net_virtio, pci_id_virtio_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_virtio, "* igb_uio | uio_pci_generic | vfio");
diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c b/drivers/net/vmxnet3/vmxnet3_ethdev.c
index 8bb13e5..93c9ac9 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -962,3 +962,4 @@ vmxnet3_process_events(struct vmxnet3_hw *hw)
 
 RTE_PMD_REGISTER_PCI(net_vmxnet3, rte_vmxnet3_pmd.pci_drv);
 RTE_PMD_REGISTER_PCI_TABLE(net_vmxnet3, pci_id_vmxnet3_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_vmxnet3, "* igb_uio | uio_pci_generic | vfio");
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 8840380..1708244 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -239,6 +239,31 @@ RTE_STR(table)
 static const char DRV_EXP_TAG(name, param_string_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Advertise the list of kernel modules required to run this driver
+ *
+ * This string lists the kernel modules required for the devices
+ * associated to a PMD. The format of each line of the string is:
+ * "<device-pattern> <kmod-expression>".
+ *
+ * The possible formats for the device pattern are:
+ *   "*"                     all devices supported by this driver
+ *   "pci:*"                 all PCI devices supported by this driver
+ *   "pci:v8086:d*:sv*:sd*"  all PCI devices supported by this driver
+ *                           whose vendor id is 0x8086.
+ *
+ * The format of the kernel modules list is a parenthesed expression
+ * containing logical-and (&) and logical-or (|).
+ *
+ * The device pattern and the kmod expression are separated by a space.
+ *
+ * Example:
+ * - "* igb_uio | uio_pci_generic | vfio"
+ */
+#define RTE_PMD_REGISTER_KMOD_DEP(name, str) \
+static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
+__attribute__((used)) = str
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/tools/dpdk-pmdinfo.py b/tools/dpdk-pmdinfo.py
index 3db9819..17bfed4 100755
--- a/tools/dpdk-pmdinfo.py
+++ b/tools/dpdk-pmdinfo.py
@@ -312,7 +312,10 @@ def parse_pmd_info_string(self, mystring):
         global raw_output
         global pcidb
 
-        optional_pmd_info = [{'id': 'params', 'tag': 'PMD PARAMETERS'}]
+        optional_pmd_info = [
+            {'id': 'params', 'tag': 'PMD PARAMETERS'},
+            {'id': 'kmod', 'tag': 'PMD KMOD DEPENDENCIES'}
+        ]
 
         i = mystring.index("=")
         mystring = mystring[i + 2:]
--
2.8.1

^ permalink raw reply related

* Re: [PATCH] mk: remove make target for examples
From: Thomas Monjalon @ 2016-11-22  9:38 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev
In-Reply-To: <bebe9fe0-3ef7-8800-1a5b-66e8d3b2f21a@intel.com>

2016-11-22 00:34, Ferruh Yigit:
> On 11/21/2016 11:47 PM, Thomas Monjalon wrote:
> > The command
> >   make examples
> > works only if target directories have the exact name of configs.
> > 
> > It is more flexible to use
> >   make -C examples RTE_SDK=$(pwd) RTE_TARGET=build
> > 
> > Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
> 
> Instead of removing examples & examples_clean targets, what do you think
> keeping them as wrapper to suggested usage, for backward compatibility.
> 
> Something like:
> "
> BUILDING_RTE_SDK :=
> export BUILDING_RTE_SDK
> 
> # Build directory is given with O=
> O ?= $(RTE_SDK)/examples
> 
> # Target for which examples should be built.
> T ?= build
> 
> .PHONY: examples
> examples:
>         @echo ================== Build examples for $(T)
>         $(MAKE) -C examples O=$(abspath $(O)) RTE_TARGET=$(T);
> 
> .PHONY: examples_clean
> examples_clean:
>         @echo ================== Clean examples for $(T)
>         $(MAKE) -C examples O=$(abspath $(O)) RTE_TARGET=$(T) clean;
> "

What is the benefit of this makefile? Just remove -C ?
It is not compatible with the old behaviour, so I'm afraid it would be
confusing for no real benefit.

^ permalink raw reply

* Re: [PATCH v3 2/2] mempool: pktmbuf pool default fallback for mempool ops error
From: Olivier Matz @ 2016-11-22  9:24 UTC (permalink / raw)
  To: Hemant Agrawal
  Cc: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
	david.hunt@intel.com
In-Reply-To: <DB5PR04MB1605536D6161F072AD24346489A70@DB5PR04MB1605.eurprd04.prod.outlook.com>

Hi Hemant,

Back on this topic, please see some comments below.

On 11/07/2016 01:30 PM, Hemant Agrawal wrote:
> Hi Olivier,
> 	
>> -----Original Message-----
>> From: Olivier Matz [mailto:olivier.matz@6wind.com]
>> Sent: Friday, October 14, 2016 5:41 PM
>>> On 9/22/2016 6:42 PM, Hemant Agrawal wrote:
>>>> Hi Olivier
>>>>
>>>> On 9/19/2016 7:27 PM, Olivier Matz wrote:
>>>>> Hi Hemant,
>>>>>
>>>>> On 09/16/2016 06:46 PM, Hemant Agrawal wrote:
>>>>>> In the rte_pktmbuf_pool_create, if the default external mempool is
>>>>>> not available, the implementation can default to "ring_mp_mc",
>>>>>> which is an software implementation.
>>>>>>
>>>>>> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
>>>>>> ---
>>>>>> Changes in V3:
>>>>>> * adding warning message to say that falling back to default sw
>>>>>> pool
>>>>>> ---
>>>>>>  lib/librte_mbuf/rte_mbuf.c | 8 ++++++++
>>>>>>  1 file changed, 8 insertions(+)
>>>>>>
>>>>>> diff --git a/lib/librte_mbuf/rte_mbuf.c
>>>>>> b/lib/librte_mbuf/rte_mbuf.c index 4846b89..8ab0eb1 100644
>>>>>> --- a/lib/librte_mbuf/rte_mbuf.c
>>>>>> +++ b/lib/librte_mbuf/rte_mbuf.c
>>>>>> @@ -176,6 +176,14 @@ rte_pktmbuf_pool_create(const char *name,
>>>>>> unsigned n,
>>>>>>
>>>>>>      rte_errno = rte_mempool_set_ops_byname(mp,
>>>>>>              RTE_MBUF_DEFAULT_MEMPOOL_OPS, NULL);
>>>>>> +
>>>>>> +    /* on error, try falling back to the software based default
>>>>>> pool */
>>>>>> +    if (rte_errno == -EOPNOTSUPP) {
>>>>>> +        RTE_LOG(WARNING, MBUF, "Default HW Mempool not supported. "
>>>>>> +            "falling back to sw mempool \"ring_mp_mc\"");
>>>>>> +        rte_errno = rte_mempool_set_ops_byname(mp, "ring_mp_mc",
>>>>>> NULL);
>>>>>> +    }
>>>>>> +
>>>>>>      if (rte_errno != 0) {
>>>>>>          RTE_LOG(ERR, MBUF, "error setting mempool handler\n");
>>>>>>          return NULL;
>>>>>>
>>>>>
>>>>> Without adding a new method ".supported()", the first call to
>>>>> rte_mempool_populate() could return the same error ENOTSUP. In this
>>>>> case, it is still possible to fallback.
>>>>>
>>>> It will be bit late.
>>>>
>>>> On failure, than we have to set the default ops and do a goto before
>>>> rte_pktmbuf_pool_init(mp, &mbp_priv);
>>
>> I still think we can do the job without adding the .supported() method.
>> The following code is just an (untested) example:
>>
>> struct rte_mempool *
>> rte_pktmbuf_pool_create(const char *name, unsigned n,
>>     unsigned cache_size, uint16_t priv_size, uint16_t data_room_size,
>>     int socket_id)
>> {
>>     struct rte_mempool *mp;
>>     struct rte_pktmbuf_pool_private mbp_priv;
>>     unsigned elt_size;
>>     int ret;
>>     const char *ops[] = {
>>         RTE_MBUF_DEFAULT_MEMPOOL_OPS, "ring_mp_mc", NULL,
>>     };
>>     const char **op;
>>
>>     if (RTE_ALIGN(priv_size, RTE_MBUF_PRIV_ALIGN) != priv_size) {
>>         RTE_LOG(ERR, MBUF, "mbuf priv_size=%u is not aligned\n",
>>             priv_size);
>>         rte_errno = EINVAL;
>>         return NULL;
>>     }
>>     elt_size = sizeof(struct rte_mbuf) + (unsigned)priv_size +
>>         (unsigned)data_room_size;
>>     mbp_priv.mbuf_data_room_size = data_room_size;
>>     mbp_priv.mbuf_priv_size = priv_size;
>>
>>     for (op = &ops[0]; *op != NULL; op++) {
>>         mp = rte_mempool_create_empty(name, n, elt_size, cache_size,
>>             sizeof(struct rte_pktmbuf_pool_private), socket_id, 0);
>>         if (mp == NULL)
>>             return NULL;
>>
>>         ret = rte_mempool_set_ops_byname(mp, *op, NULL);
>>         if (ret != 0) {
>>             RTE_LOG(ERR, MBUF, "error setting mempool handler\n");
>>             rte_mempool_free(mp);
>>             if (ret == -ENOTSUP)
>>                 continue;
>>             rte_errno = -ret;
>>             return NULL;
>>         }
>>         rte_pktmbuf_pool_init(mp, &mbp_priv);
>>
>>         ret = rte_mempool_populate_default(mp);
>>         if (ret < 0) {
>>             rte_mempool_free(mp);
>>             if (ret == -ENOTSUP)
>>                 continue;
>>             rte_errno = -ret;
>>             return NULL;
>>         }
>>     }
>>
>>     rte_mempool_obj_iter(mp, rte_pktmbuf_init, NULL);
>>
>>     return mp;
>> }
>>
>>
> [Hemant]  This look fine to me. Please submit a patch for the same. 
> 
>>>>> I've just submitted an RFC, which I think is quite linked:
>>>>> http://dpdk.org/ml/archives/dev/2016-September/046974.html
>>>>> Assuming a new parameter "mempool_ops" is added to
>>>>> rte_pktmbuf_pool_create(), would it make sense to fallback to
>>>>> "ring_mp_mc"? What about just returning ENOTSUP? The application
>>>>> could do the job and decide which sw fallback to use.
>>>>
>>>> We ran into this issue when trying to run the standard DPDK examples
>>>> (l3fwd) in VM. Do you think, is it practical to add fallback handling
>>>> in each of the DPDK examples?
>>
>> OK. What is still unclear for me, is how the software is aware of the different
>> hardware-assisted handlers. Moreover, we could imagine more software
>> handlers, which could be used depending on the use case.
>>
>> I think this choice has to be made by the user or the application:
>>
>> - the application may want to use a specific (sw or hw) handler: in
>>   this case, it want to be notified if it fails, instead of having
>>   a quiet fallback to ring_mp_mc
>> - if several handlers are available, the application may want to
>>   try them in a specific order
>> - maybe some handlers will have some limitations with some
>>   configurations or driver? The application could decide to use
>>   a different handler according the configuration.
>>
>> So that's why I think this is an application decision.
>>
> [Hemant]  We should simplify it:  if the application has supplied the handler, it is application's responsibility to take care of failure. Only if the application want to use the default handler, the implementation can fallback.  The fallback handler can again be configurable. 

Honestly, I'm not very convinced that having a quiet fallback is
the proper solution: the application won't be notified that the
fallback occured.

I understand your patch solves your use-case, but my fear is that
we just integrate this minimal patch and never do the harder work
of solving all the use-cases. I think we need to give the tools to
the applications to control what occurs because we also need to solve
these issues:
- you have a hardware handler, but you want to use the software
  handler
- you have several software handlers, and you (as an administrator) or
  the application knows which one is the best to use in your case.

An alternative (which I don't like either) to solve your issue without
modifying the mbuf code is to have your own handler fallbacking to
ring_mp_mc.


>>>> Typically when someone is writing a application on host, he need not
>>>> worry non-availability of the hw offloaded mempool. He may also want
>>>> to run the same binary in virtual machine. In VM, it is not
>>>> guaranteed that hw offloaded mempools will be available.
>>
>> Running the same binary is of course a need. But if your VM does not provide
>> the same virtualized hardware than the host, I think the command line option
>> makes sense.
>>
>> AFAIU, on the host, you can use a hw mempool handler or a sw one, and on the
>> guest, only a sw one. So you need an option to select the behavior you want on
>> the host, without recompiling.
>>
>> I understand that modifying all the applications is not a good option either. I'm
>> thinking a a EAL parameter that would allow to configure a library (mbuf in this
>> case). Something like kernel boot options.
>> Example: testpmd -l 2,4 --opt mbuf.handler="ring_mp_mc" -- [app args]
>>
>> I don't know if this is feasible, this has to be discussed first, but what do you
>> think on the principle? The value could also be an ordered list if we want a
>> fallback, and this option could be overriden by the application before creating
>> the mbuf pool. There was some discussions about a kind of dpdk global
>> configuration some time ago.
>>
> [Hemant] I agree that command line option provide a better control in this case. 
> On the flipside, We need to be careful that we do not end up having too many command line options. 

Yes, we should avoid having too many command line arguments.
I think we should go in the direction of having a sort of key/value
database in EAL. It could be set by:
- a generic command line argument
- a config file (maybe later)
- the application through an API

Then, it would be used by:
- dpdk libraries
- the application (maybe)

This has been discussed some times, the latest was probably:
http://dpdk.org/ml/archives/dev/2016-June/040079.html

I think it would be a good tool for dpdk configurability, and it would
help to remove some compile-time options and maybe some eal options.
Unfortunately, I don't have the time to work on this at the moment.

Regards,
Olivier

^ permalink raw reply

* Re: [PATCH 0/4] libeventdev API and northbound implementation
From: Shreyansh Jain @ 2016-11-22  9:05 UTC (permalink / raw)
  To: Yuanhan Liu, Jerin Jacob
  Cc: Bruce Richardson, dev, harry.van.haaren, hemant.agrawal,
	gage.eads, thomas.monjalon
In-Reply-To: <20161122020014.GU5048@yliu-dev.sh.intel.com>

On Tuesday 22 November 2016 07:30 AM, Yuanhan Liu wrote:
> On Sat, Nov 19, 2016 at 12:57:15AM +0530, Jerin Jacob wrote:
>> On Fri, Nov 18, 2016 at 04:04:29PM +0000, Bruce Richardson wrote:
>>> +Thomas
>>>
>>> On Fri, Nov 18, 2016 at 03:25:18PM +0000, Bruce Richardson wrote:
>>>> On Fri, Nov 18, 2016 at 11:14:58AM +0530, Jerin Jacob wrote:
>>>>> As previously discussed in RFC v1 [1], RFC v2 [2], with changes
>>>>> described in [3] (also pasted below), here is the first non-draft series
>>>>> for this new API.
>>>>>
>>>>> [1] http://dpdk.org/ml/archives/dev/2016-August/045181.html
>>>>> [2] http://dpdk.org/ml/archives/dev/2016-October/048592.html
>>>>> [3] http://dpdk.org/ml/archives/dev/2016-October/048196.html
>>>>>
>>>>> Changes since RFC v2:
>>>>>
>>>>> - Updated the documentation to define the need for this library[Jerin]
>>>>> - Added RTE_EVENT_QUEUE_CFG_*_ONLY configuration parameters in
>>>>>   struct rte_event_queue_conf to enable optimized sw implementation [Bruce]
>>>>> - Introduced RTE_EVENT_OP* ops [Bruce]
>>>>> - Added nb_event_queue_flows,nb_event_port_dequeue_depth, nb_event_port_enqueue_depth
>>>>>   in rte_event_dev_configure() like ethdev and crypto library[Jerin]
>>>>> - Removed rte_event_release() and replaced with RTE_EVENT_OP_RELEASE ops to
>>>>>   reduce fast path APIs and it is redundant too[Jerin]
>>>>> - In the view of better application portability, Removed pin_event
>>>>>   from rte_event_enqueue as it is just hint and Intel/NXP can not support it[Jerin]
>>>>> - Added rte_event_port_links_get()[Jerin]
>>>>> - Added rte_event_dev_dump[Harry]
>>>>>
>>>>> Notes:
>>>>>
>>>>> - This patch set is check-patch clean with an exception that
>>>>> 02/04 has one WARNING:MACRO_WITH_FLOW_CONTROL
>>>>> - Looking forward to getting additional maintainers for libeventdev
>>>>>
>>>>>
>>>>> Possible next steps:
>>>>> 1) Review this patch set
>>>>> 2) Integrate Intel's SW driver[http://dpdk.org/dev/patchwork/patch/17049/]
>>>>> 3) Review proposed examples/eventdev_pipeline application[http://dpdk.org/dev/patchwork/patch/17053/]
>>>>> 4) Review proposed functional tests[http://dpdk.org/dev/patchwork/patch/17051/]
>>>>> 5) Cavium's HW based eventdev driver
>>>>>
>>>>> I am planning to work on (3),(4) and (5)
>>>>>
>>>> Thanks Jerin,
>>>>
>>>> we'll review and get back to you with any comments or feedback (1), and
>>>> obviously start working on item (2) also! :-)
>>>>
>>>> I'm also wonder whether we should have a staging tree for this work to
>>>> make interaction between us easier. Although this may not be
>>>> finalised enough for 17.02 release, do you think having an
>>>> dpdk-eventdev-next tree would be a help? My thinking is that once we get
>>>> the eventdev library itself in reasonable shape following our review, we
>>>> could commit that and make any changes thereafter as new patches, rather
>>>> than constantly respinning the same set. It also gives us a clean git
>>>> tree to base the respective driver implementations on from our two sides.
>>>>
>>>> Thomas, any thoughts here on your end - or from anyone else?
>>
>> I was thinking more or less along the same lines. To avoid re-spinning the
>> same set, it is better to have libeventdev library mark as EXPERIMENTAL
>> and commit it somewhere on dpdk-eventdev-next or main tree
>>
>> I think, EXPERIMENTAL status can be changed only when
>> - At least two event drivers available
>> - Functional test applications fine with at least two drivers
>> - Portable example application to showcase the features of the library
>> - eventdev integration with another dpdk subsystem such as ethdev
>
> I'm wondering maybe we could have a staging tree, for all features like
> this one (and one branch for each feature)?
>
> 	--yliu
>

+1

It would help a lot of 'experimental' stuff reach a wider audience 
without waiting for a complete cycle of upstreaming.
Though, I am not sure how would we limit the branches - or if that is 
even required.

-- 
-
Shreyansh

^ permalink raw reply

* Re: [PATCH 7/7] examples/eventdev_pipeline: adding example
From: Jerin Jacob @ 2016-11-22  6:02 UTC (permalink / raw)
  To: Harry van Haaren; +Cc: dev, Gage Eads, Bruce Richardson
In-Reply-To: <1479319207-130646-8-git-send-email-harry.van.haaren@intel.com>

On Wed, Nov 16, 2016 at 06:00:07PM +0000, Harry van Haaren wrote:
> This patch adds a sample app to the examples/ directory, which can be used
> as a reference application and for general testing. The application requires
> two ethdev ports and expects traffic to be flowing. The application must be
> run with the --vdev flags as follows to indicate to EAL that a virtual
> eventdev device called "evdev_sw0" is available to be used:
> 
>     ./build/eventdev_pipeline --vdev evdev_sw0
> 
> The general flow of the traffic is as follows:
> 
>     Rx core -> Atomic Queue => 4 worker cores => TX core
> 
> A scheduler core is required to do the packet scheduling, making this
> configuration require 7 cores (Rx, Tx, Scheduler, and 4 workers). Finally
> a master core brings the core count to 8 for this configuration. The

Thanks for the example application.I will try to share my views on
ethdev integration and usability perspective. Hope we can converge.

Some of the high level details first before getting into exact details.

1) From the HW and ethdev integration perspective, The integrated NIC controllers
does not need producer core(s) to push the event/packets to event queue. So, I was
thinking to use 6WIND rte_flow spec to create the "ethdev port to event
queue wiring" connection by extending the output ACTION definition, which
specifies event queue its need to enqueued to for the given ethdev port
(something your are doing in application).

I guess, the producer part of this example can be created as common
code, somewhere in rte_flow/ethdev to reuse. We would need this scheme also
where when we deal with external nics + HW event manager use case

The complete event driven model can be verified and exercised without
integrating with eventdev subsystem. So I think, may be we need to
focus on functional applications without ethdev to verify the eventdev
features like(automatic multicore scaling,  dynamic load balancing, pipelining,
packet ingress order maintenance and synchronization services) and then
integrate with ethdev

> +	const unsigned cores_needed = num_workers +
> +			/*main*/1 +
> +			/*sched*/1 +
> +			/*TX*/1 +
> +			/*RX*/1;
> +

2) One of the prime aims of the event driven model is to remove the fixed
function core mappings and enable automatic multicore scaling,  dynamic load
balancing etc.I will try to use an example in review section to show the
method for removing "consumer core" in this case.

> application can be configured for various numbers of flows and worker
> cores. Run the application with -h for details.
> 
> Signed-off-by: Gage Eads <gage.eads@intel.com>
> Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> Signed-off-by: Harry van Haaren <harry.van.haaren@intel.com>
> ---
>  examples/eventdev_pipeline/Makefile |  49 +++
>  examples/eventdev_pipeline/main.c   | 718 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 767 insertions(+)
>  create mode 100644 examples/eventdev_pipeline/Makefile
>  create mode 100644 examples/eventdev_pipeline/main.c
> 
> +static int sched_type = RTE_SCHED_TYPE_ATOMIC;

RTE_SCHED_TYPE_ORDERED makes sense as a default. Most common case will
have ORDERD at first stage so that it can scale.

> +
> +
> +static int
> +worker(void *arg)
> +{
> +	struct rte_event rcv_events[BATCH_SIZE];
> +
> +	struct worker_data *data = (struct worker_data *)arg;
> +	uint8_t event_dev_id = data->event_dev_id;
> +	uint8_t event_port_id = data->event_port_id;
> +	int32_t qid = data->qid;
> +	size_t sent = 0, received = 0;
> +
> +	while (!done) {
> +		uint16_t i;
> +
> +		uint16_t n = rte_event_dequeue_burst(event_dev_id,
> +						     event_port_id,
> +						     rcv_events,
> +						     RTE_DIM(rcv_events),
> +						     false);
> +		if (n == 0){
> +			rte_pause();
> +			/* Flush any buffered events */
> +			rte_event_dequeue(event_dev_id,
> +					  event_port_id,
> +					  NULL,
> +					  false);

The above can be done in implementation. May not be the candidate for common code.

> +			continue;
> +		}
> +		received += n;
> +
> +		for (i = 0; i < n; i++) {
> +			struct ether_hdr *eth;
> +			struct ether_addr addr;
> +			struct rte_event *ev = &rcv_events[i];
> +
> +			ev->queue_id = qid;
> +			ev->flow_id = 0;

Another way to deal wit out additional consumer core(it creates issue in
scaling and load balancing) is

in worker:
while(1) {

	ev = dequeue(port);

	// stage 1 app processing
	if (ev.event_type == RTE_EVENT_TYPE_ETHDEV) {
		// identify the Ethernet port and tx queue the packet needs to go
		// create the flow based on that
		ev.flow_id = flow(port_id, tx_queue_id);
		ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
		ev.operation = RTE_EVENT_OP_FORWARD;
		ev.event_type = RTE_EVENT_TYPE_CORE;
	} // stage 2 app processing
	else if (ev.event_type == RTE_EVENT_TYPE_CORE) {
		port_id = function_of(ev.flow_id) ;// look stage 1 processing
		tx_queue_id = function_of(ev.flow_id) //look stage 1 processing
		remaining ethdev based tx is same as yours
	}
	enqueue(ev);
}



> +			ev->priority = 0;
> +			ev->sched_type = RTE_SCHED_TYPE_ATOMIC;
> +			ev->operation = RTE_EVENT_OP_FORWARD;
> +
> +			uint64_t now = rte_rdtsc();
> +			while(now + 750 > rte_rdtsc()) {}

Why delay ?

> +
> +			/* change mac addresses on packet */
> +			eth = rte_pktmbuf_mtod(ev->mbuf, struct ether_hdr *);
> +			ether_addr_copy(&eth->d_addr, &addr);
> +			ether_addr_copy(&eth->s_addr, &eth->d_addr);
> +			ether_addr_copy(&addr, &eth->s_addr);
> +		}
> +		int ret = rte_event_enqueue_burst(event_dev_id, event_port_id,
> +					rcv_events, n, false);
> +		if (ret != n)
> +			rte_panic("worker %u thread failed to enqueue event\n",
> +				rte_lcore_id());
> +	}
> +
> +	/* Flush the buffered events */
> +	rte_event_dequeue(event_dev_id, event_port_id, NULL, false);
> +
> +	if (!quiet)
> +		printf("  worker %u thread done. RX=%zu TX=%zu\n",
> +				rte_lcore_id(), received, sent);
> +
> +	return 0;
> +}
> +
> +static int
> +scheduler(void *arg)
> +{

Maybe better to abstract as "service core" or something like I mentioned
earlier, as HW implementation does not need this

> +	RTE_SET_USED(arg);
> +	size_t loops = 0;
> +
> +	while (!done) {
> +		/* Assumes an event dev ID of 0 */
> +		rte_event_schedule(0);
> +		loops++;
> +	}
> +
> +	printf("  scheduler thread done. loops=%zu\n", loops);
> +
> +	return 0;
> +}
> +
> +
> +static int
> +producer(void *arg)
> +{
> +
> +	struct prod_data *data = (struct prod_data *)arg;
> +	size_t npackets = num_packets;
> +	unsigned i;
> +	uint64_t mbuf_seqno = 0;
> +	size_t sent = 0;
> +	uint8_t eth_port = 0;
> +	uint8_t event_dev_id = data->event_dev_id;
> +	uint8_t event_port_id = data->event_port_id;
> +	int fid_counter = 0;
> +
> +	while (!done) {
> +		int ret;
> +		unsigned num_ports = data->num_ports;
> +		int32_t qid = data->qid;
> +		struct rte_event events[BATCH_SIZE];
> +		struct rte_mbuf *mbufs[BATCH_SIZE];
> +
> +		uint16_t nb_rx = rte_eth_rx_burst(eth_port, 0, mbufs, BATCH_SIZE);
> +		if (++eth_port == num_ports)
> +			eth_port = 0;
> +		if (nb_rx == 0) {
> +			rte_pause();
> +			/* Flush any buffered events */
> +			rte_event_dequeue(event_dev_id,
> +					  event_port_id,
> +					  NULL,
> +					  false);
> +			continue;
> +		}
> +
> +		for (i = 0; i < nb_rx; i++) {
> +			struct rte_mbuf *m = mbufs[i];
> +			struct rte_event *ev = &events[i];
> +
> +			ev->queue_id = qid;
> +			ev->flow_id = fid_counter++ % 6;

To me, flow_id should be a function of port_id and rx queue number here.
right?

> +			ev->priority = 0;
> +			m->udata64 = mbuf_seqno++;

Why update mbuf_seqno++ here. Shouldn't be something inside the
implementation?

> +			ev->mbuf = m;
> +			ev->sched_type = sched_type;
> +			ev->operation = RTE_EVENT_OP_NEW;
> +		}
> +
> +		do {
> +			ret = rte_event_enqueue_burst(event_dev_id,
> +							event_port_id,
> +							events,
> +							nb_rx,
> +							false);
> +		} while (ret == -ENOSPC);

I guess, -ENOSPC can be checked inside the implementation. I guess, we
can pass the info required in the configuration stage to decide the timeout. May
not be the candidate for common code.

> +		if (ret != nb_rx)
> +			rte_panic("producer thread failed to enqueue *all* events\n");
> +
> +		sent += nb_rx;
> +
> +		if (num_packets > 0 && npackets > 0) {
> +			npackets -= nb_rx;
> +			if (npackets == 0)
> +				break;
> +		}
> +	}
> +
> +	/* Flush any buffered events */
> +	while (!done)
> +		rte_event_dequeue(event_dev_id, event_port_id, NULL, false);
> +
> +	printf("  prod thread done! TX=%zu across %u flows\n", sent, num_fids);
> +
> +	return 0;
> +}
> +

> +static uint8_t
> +setup_event_dev(struct prod_data *prod_data,
> +		struct cons_data *cons_data,
> +		struct worker_data *worker_data)
> +{
> +	config.nb_events_limit = 256;

In real application, we may need to pass as command line

> +	config.dequeue_wait_ns = 0;
> +
> +	ret = rte_event_dev_configure(id, &config);
> +	if (ret)
> +		rte_panic("Failed to configure the event dev\n");
> +
> +	/* Create queues */
> +	queue_config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY;
> +	queue_config.priority = 0;
> +
> +	qid0 = 0;
> +	ret = rte_event_queue_setup(id, qid0, &queue_config);
> +	if (ret < 0)
> +		rte_panic("Failed to create the scheduled QID\n");
> +
> +	queue_config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER;
> +	queue_config.priority = 0;
> +
> +	cons_qid = 1;
> +	ret = rte_event_queue_setup(id, cons_qid, &queue_config);
> +	if (ret < 0)
> +		rte_panic("Failed to create the cons directed QID\n");
> +
> +	queue_config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER;

I guess its more of RTE_EVENT_QUEUE_CFG_SINGLE_PRODUCER case, Does it
make sense to add RTE_EVENT_QUEUE_CFG_SINGLE_PRODUCER in spec, if you are
enqueueing only through that port. see next comment.

> +	queue_config.priority = 0;
> +
> +	prod_qid = 2;
> +	ret = rte_event_queue_setup(id, prod_qid, &queue_config);
> +	if (ret < 0)
> +		rte_panic("Failed to create the prod directed QID\n");
> +

Looks like prod_qid is just created as a dummy, The actual producer is
en-queuing on qid0.Something not adding up.

> +	/* Create ports */
> +#define LB_PORT_DEPTH 16
> +#define DIR_PORT_DEPTH 32
> +	port_config.enqueue_queue_depth = LB_PORT_DEPTH;
> +	port_config.dequeue_queue_depth = LB_PORT_DEPTH;

We need to check the info->max_enqueue_queue_depth.

Jerin

^ permalink raw reply

* Re: [PATCH 0/4] libeventdev API and northbound implementation
From: Yuanhan Liu @ 2016-11-22  2:00 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: Bruce Richardson, dev, harry.van.haaren, hemant.agrawal,
	gage.eads, thomas.monjalon
In-Reply-To: <20161118192715.GA8674@localhost.localdomain>

On Sat, Nov 19, 2016 at 12:57:15AM +0530, Jerin Jacob wrote:
> On Fri, Nov 18, 2016 at 04:04:29PM +0000, Bruce Richardson wrote:
> > +Thomas
> > 
> > On Fri, Nov 18, 2016 at 03:25:18PM +0000, Bruce Richardson wrote:
> > > On Fri, Nov 18, 2016 at 11:14:58AM +0530, Jerin Jacob wrote:
> > > > As previously discussed in RFC v1 [1], RFC v2 [2], with changes
> > > > described in [3] (also pasted below), here is the first non-draft series
> > > > for this new API.
> > > > 
> > > > [1] http://dpdk.org/ml/archives/dev/2016-August/045181.html
> > > > [2] http://dpdk.org/ml/archives/dev/2016-October/048592.html
> > > > [3] http://dpdk.org/ml/archives/dev/2016-October/048196.html
> > > > 
> > > > Changes since RFC v2:
> > > > 
> > > > - Updated the documentation to define the need for this library[Jerin]
> > > > - Added RTE_EVENT_QUEUE_CFG_*_ONLY configuration parameters in
> > > >   struct rte_event_queue_conf to enable optimized sw implementation [Bruce]
> > > > - Introduced RTE_EVENT_OP* ops [Bruce]
> > > > - Added nb_event_queue_flows,nb_event_port_dequeue_depth, nb_event_port_enqueue_depth
> > > >   in rte_event_dev_configure() like ethdev and crypto library[Jerin]
> > > > - Removed rte_event_release() and replaced with RTE_EVENT_OP_RELEASE ops to
> > > >   reduce fast path APIs and it is redundant too[Jerin]
> > > > - In the view of better application portability, Removed pin_event
> > > >   from rte_event_enqueue as it is just hint and Intel/NXP can not support it[Jerin]
> > > > - Added rte_event_port_links_get()[Jerin]
> > > > - Added rte_event_dev_dump[Harry]
> > > > 
> > > > Notes:
> > > > 
> > > > - This patch set is check-patch clean with an exception that
> > > > 02/04 has one WARNING:MACRO_WITH_FLOW_CONTROL
> > > > - Looking forward to getting additional maintainers for libeventdev
> > > > 
> > > > 
> > > > Possible next steps:
> > > > 1) Review this patch set
> > > > 2) Integrate Intel's SW driver[http://dpdk.org/dev/patchwork/patch/17049/]
> > > > 3) Review proposed examples/eventdev_pipeline application[http://dpdk.org/dev/patchwork/patch/17053/]
> > > > 4) Review proposed functional tests[http://dpdk.org/dev/patchwork/patch/17051/]
> > > > 5) Cavium's HW based eventdev driver
> > > > 
> > > > I am planning to work on (3),(4) and (5)
> > > > 
> > > Thanks Jerin,
> > > 
> > > we'll review and get back to you with any comments or feedback (1), and
> > > obviously start working on item (2) also! :-)
> > > 
> > > I'm also wonder whether we should have a staging tree for this work to
> > > make interaction between us easier. Although this may not be
> > > finalised enough for 17.02 release, do you think having an
> > > dpdk-eventdev-next tree would be a help? My thinking is that once we get
> > > the eventdev library itself in reasonable shape following our review, we
> > > could commit that and make any changes thereafter as new patches, rather
> > > than constantly respinning the same set. It also gives us a clean git
> > > tree to base the respective driver implementations on from our two sides.
> > > 
> > > Thomas, any thoughts here on your end - or from anyone else?
> 
> I was thinking more or less along the same lines. To avoid re-spinning the
> same set, it is better to have libeventdev library mark as EXPERIMENTAL
> and commit it somewhere on dpdk-eventdev-next or main tree
> 
> I think, EXPERIMENTAL status can be changed only when
> - At least two event drivers available
> - Functional test applications fine with at least two drivers
> - Portable example application to showcase the features of the library
> - eventdev integration with another dpdk subsystem such as ethdev

I'm wondering maybe we could have a staging tree, for all features like
this one (and one branch for each feature)?

	--yliu

^ permalink raw reply

* [PATCH v2] examples/ethtool: fix bug in drvinfo callback
From: Qiming Yang @ 2016-11-22  1:41 UTC (permalink / raw)
  To: dev; +Cc: remy.horton, Qiming Yang
In-Reply-To: <1479462013-11562-1-git-send-email-qiming.yang@intel.com>

Function pcmd_drvinfo_callback uses struct info to get
the ethtool information of each port. Struct info will
store the information of previous port until this
information be updated. This patch fixes this issue.

Fixes: bda68ab9d1e7 ("examples/ethtool: add user-space ethtool sample application")

Signed-off-by: Qiming Yang <qiming.yang@intel.com>
---
v2 changes:
* fixed the spelling mistake in commit log
---
---
 examples/ethtool/ethtool-app/ethapp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/examples/ethtool/ethtool-app/ethapp.c b/examples/ethtool/ethtool-app/ethapp.c
index 9b77385..192d941 100644
--- a/examples/ethtool/ethtool-app/ethapp.c
+++ b/examples/ethtool/ethtool-app/ethapp.c
@@ -177,6 +177,7 @@ pcmd_drvinfo_callback(__rte_unused void *ptr_params,
 	int id_port;
 
 	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
+		memset(&info, 0, sizeof(info));
 		if (rte_ethtool_get_drvinfo(id_port, &info)) {
 			printf("Error getting info for port %i\n", id_port);
 			return;
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH] mk: remove make target for examples
From: Ferruh Yigit @ 2016-11-22  0:34 UTC (permalink / raw)
  To: Thomas Monjalon, dev
In-Reply-To: <1479772058-7112-1-git-send-email-thomas.monjalon@6wind.com>

On 11/21/2016 11:47 PM, Thomas Monjalon wrote:
> The command
>   make examples
> works only if target directories have the exact name of configs.
> 
> It is more flexible to use
>   make -C examples RTE_SDK=$(pwd) RTE_TARGET=build
> 
> Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>

Instead of removing examples & examples_clean targets, what do you think
keeping them as wrapper to suggested usage, for backward compatibility.

Something like:
"
BUILDING_RTE_SDK :=
export BUILDING_RTE_SDK

# Build directory is given with O=
O ?= $(RTE_SDK)/examples

# Target for which examples should be built.
T ?= build

.PHONY: examples
examples:
        @echo ================== Build examples for $(T)
        $(MAKE) -C examples O=$(abspath $(O)) RTE_TARGET=$(T);

.PHONY: examples_clean
examples_clean:
        @echo ================== Clean examples for $(T)
        $(MAKE) -C examples O=$(abspath $(O)) RTE_TARGET=$(T) clean;
"

^ permalink raw reply

* Re: [PATCH 0/4] libeventdev API and northbound implementation
From: Thomas Monjalon @ 2016-11-22  0:11 UTC (permalink / raw)
  To: Bruce Richardson, Jerin Jacob
  Cc: dev, harry.van.haaren, hemant.agrawal, gage.eads
In-Reply-To: <20161121095718.GB16124@bricha3-MOBL3.ger.corp.intel.com>

2016-11-21 09:57, Bruce Richardson:
> On Mon, Nov 21, 2016 at 10:40:50AM +0100, Thomas Monjalon wrote:
> > Are you asking for a temporary tree?
> > If yes, please tell its name and its committers, it will be done.
> 
> Yes, we are asking for a new tree, but I would not assume it is
> temporary - it might be, but it also might not be, given how other
> threads are discussing having an increasing number of subtrees giving
> pull requests. :-)
> 
> Name: dpdk-eventdev-next

Named dpdk-next-eventdev for consistency.

> Committers: Bruce Richardson & Jerin Jacob

Access granted. Jerin could you send me a public SSH key please?

^ permalink raw reply

* [PATCH] mk: remove make target for examples
From: Thomas Monjalon @ 2016-11-21 23:47 UTC (permalink / raw)
  To: dev

The command
  make examples
works only if target directories have the exact name of configs.

It is more flexible to use
  make -C examples RTE_SDK=$(pwd) RTE_TARGET=build

Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
---
 mk/rte.sdkexamples.mk | 77 ---------------------------------------------------
 mk/rte.sdkroot.mk     |  4 ---
 2 files changed, 81 deletions(-)
 delete mode 100644 mk/rte.sdkexamples.mk

diff --git a/mk/rte.sdkexamples.mk b/mk/rte.sdkexamples.mk
deleted file mode 100644
index 111ce91..0000000
--- a/mk/rte.sdkexamples.mk
+++ /dev/null
@@ -1,77 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2014 6WIND S.A.
-#
-#   Redistribution and use in source and binary forms, with or without
-#   modification, are permitted provided that the following conditions
-#   are met:
-#
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above copyright
-#       notice, this list of conditions and the following disclaimer in
-#       the documentation and/or other materials provided with the
-#       distribution.
-#     * Neither the name of 6WIND S.A. nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-#
-#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# examples application are seen as external applications which are
-# not part of SDK.
-BUILDING_RTE_SDK :=
-export BUILDING_RTE_SDK
-
-# Build directory is given with O=
-O ?= $(RTE_SDK)/examples
-
-# Target for which examples should be built.
-T ?= *
-
-# list all available configurations
-EXAMPLES_CONFIGS := $(patsubst $(RTE_SRCDIR)/config/defconfig_%,%,\
-	$(wildcard $(RTE_SRCDIR)/config/defconfig_$(T)))
-EXAMPLES_TARGETS := $(addsuffix _examples,\
-	$(filter-out %~,$(EXAMPLES_CONFIGS)))
-
-.PHONY: examples
-examples: $(EXAMPLES_TARGETS)
-
-%_examples:
-	@echo ================== Build examples for $*
-	$(Q)if [ ! -d "${RTE_SDK}/${*}" ]; then \
-		echo "Target ${*} does not exist in ${RTE_SDK}/${*}." ; \
-		echo -n "Please install DPDK first (make install) or use another " ; \
-		echo "target argument (T=target)." ; \
-		false ; \
-	else \
-		$(MAKE) -C examples O=$(abspath $(O)) RTE_TARGET=$(*); \
-	fi
-
-EXAMPLES_CLEAN_TARGETS := $(addsuffix _examples_clean,\
-	$(filter-out %~,$(EXAMPLES_CONFIGS)))
-
-.PHONY: examples_clean
-examples_clean: $(EXAMPLES_CLEAN_TARGETS)
-
-%_examples_clean:
-	@echo ================== Clean examples for $*
-	$(Q)if [ ! -d "${RTE_SDK}/${*}" ]; then \
-		echo "Target ${*} does not exist in ${RTE_SDK}/${*}." ; \
-		echo -n "Please install DPDK first (make install) or use another " ; \
-		echo "target argument (T=target)." ; \
-		false ; \
-	else \
-		$(MAKE) -C examples O=$(abspath $(O)) RTE_TARGET=$(*) clean; \
-	fi
diff --git a/mk/rte.sdkroot.mk b/mk/rte.sdkroot.mk
index 04ad523..81233ed 100644
--- a/mk/rte.sdkroot.mk
+++ b/mk/rte.sdkroot.mk
@@ -117,10 +117,6 @@ depdirs depgraph:
 gcov gcovclean:
 	$(Q)$(MAKE) -f $(RTE_SDK)/mk/rte.sdkgcov.mk $@
 
-.PHONY: examples examples_clean
-examples examples_clean:
-	$(Q)$(MAKE) -f $(RTE_SDK)/mk/rte.sdkexamples.mk $@
-
 # all other build targets
 %:
 	$(Q)$(MAKE) -f $(RTE_SDK)/mk/rte.sdkconfig.mk checkconfig
-- 
2.7.0

^ permalink raw reply related

* Coverity project created for dpdk-next-net tree
From: Ferruh Yigit @ 2016-11-21 23:29 UTC (permalink / raw)
  To: DPDK, Yong Wang, John McNamara
  Cc: Adrien Mazarguil, Ajit Khaparde, Alejandro Lucero,
	Bruce Richardson, Declan Doherty, Evgeny Schemeilin, Ferruh Yigit,
	Harish Patil, Helin Zhang, Huawei Xie, Jakub Palider, Jan Medala,
	Jerin Jacob, Jing Chen, Jingjing Wu, John Daley, John W. Linville,
	Konstantin Ananyev, Maciej Czekaj, Matej Vido, Nelson Escobar,
	Netanel Belgazal <netanel

Coverity project created for dpdk-next-net tree:
https://scan.coverity.com/projects/dpdk-next-net

This can be useful to fix coverity issues before next-net merged into
master branch.

Project is open for everyone to register and to get scan reports, there
will be regular scans for next-net tree.

Specially driver maintainers, please consider registering to the project
and checking your driver's defect status.
I believe there are some false positives, it is appreciated if you can
identify and mark them in coverity tool.

Thanks,
ferruh

PS: As a reminder, a coverity project already exists for main dpdk repo:
https://scan.coverity.com/projects/dpdk-data-plane-development-kit

^ permalink raw reply

* [PATCH] scripts: check cc stable mailing list in commit
From: Thomas Monjalon @ 2016-11-21 22:43 UTC (permalink / raw)
  To: dev

Add a check for commits fixing a released bug.
Such commits are found thanks to scripts/git-log-fixes.sh.
They must be sent CC: stable@dpdk.org.
In order to avoid forgetting CC, this mail header can be written
in the git commit message.

Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
---
 scripts/check-git-log.sh | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/scripts/check-git-log.sh b/scripts/check-git-log.sh
index 5f8a9fc..4f98a7a 100755
--- a/scripts/check-git-log.sh
+++ b/scripts/check-git-log.sh
@@ -47,12 +47,14 @@ if [ "$1" = '-h' -o "$1" = '--help' ] ; then
 	exit
 fi
 
+selfdir=$(dirname $(readlink -e $0))
 range=${1:-origin/master..}
 
 commits=$(git log --format='%h' --reverse $range)
 headlines=$(git log --format='%s' --reverse $range)
 bodylines=$(git log --format='%b' --reverse $range)
 fixes=$(git log --format='%h %s' --reverse $range | grep -i ': *fix' | cut -d' ' -f1)
+stablefixes=$($selfdir/git-log-fixes.sh $range | sed '/(N\/A)$/d'  | cut -d' ' -f2)
 tags=$(git log --format='%b' --reverse $range | grep -i -e 'by *:' -e 'fix.*:')
 bytag='\(Reported\|Suggested\|Signed-off\|Acked\|Reviewed\|Tested\)-by:'
 
@@ -191,3 +193,10 @@ bad=$(for fixtag in $fixtags ; do
 	printf "$fixtag" | grep -v "^$good$"
 done | sed 's,^,\t,')
 [ -z "$bad" ] || printf "Wrong 'Fixes' reference:\n$bad\n"
+
+# check CC:stable for fixes
+bad=$(for fix in $stablefixes ; do
+	git log --format='%b' -1 $fix | grep -qi '^CC: *stable@dpdk.org' ||
+		git log --format='\t%s' -1 $fix
+done)
+[ -z "$bad" ] || printf "Should CC: stable@dpdk.org\n$bad\n"
-- 
2.7.0

^ permalink raw reply related

* [PATCH] scripts: fix checkpatch from standard input
From: Thomas Monjalon @ 2016-11-21 22:42 UTC (permalink / raw)
  To: dev

When checking a valid patch from standard input,
the footer lines of the report are not filtered out.

The function check is called outside of any loop,
so the statement continue has no effect and the footer is printed.

Fixes: 8005feef421d ("scripts: add standard input to checkpatch")

Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
---
 scripts/checkpatches.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/checkpatches.sh b/scripts/checkpatches.sh
index 336cc7b..cfe262b 100755
--- a/scripts/checkpatches.sh
+++ b/scripts/checkpatches.sh
@@ -94,7 +94,7 @@ check () { # <patch> <commit> <title>
 	else
 		report=$($DPDK_CHECKPATCH_PATH $options - 2>/dev/null)
 	fi
-	[ $? -ne 0 ] || continue
+	[ $? -ne 0 ] || return 0
 	$verbose || printf '\n### %s\n\n' "$3"
 	printf '%s\n' "$report" | sed -n '1,/^total:.*lines checked$/p'
 	status=$(($status + 1))
-- 
2.7.0

^ permalink raw reply related

* Re: [PATCH v2] i40e: Fix eth_i40e_dev_init sequence on ThunderX
From: Jerin Jacob @ 2016-11-21 22:16 UTC (permalink / raw)
  To: Ananyev, Konstantin
  Cc: Satha Rao, Zhang, Helin, Wu, Jingjing, jianbo.liu@linaro.org,
	dev@dpdk.org
In-Reply-To: <2601191342CEEE43887BDE71AB9772583F0DE265@irsmsx105.ger.corp.intel.com>

On Sun, Nov 20, 2016 at 11:21:43PM +0000, Ananyev, Konstantin wrote:
> Hi
> > 
> > i40e_asq_send_command: rd32 & wr32 under ThunderX gives unpredictable
> >                        results. To solve this include rte memory barriers
> > 
> > Signed-off-by: Satha Rao <skoteshwar@caviumnetworks.com>
> > ---
> >  drivers/net/i40e/base/i40e_osdep.h | 14 ++++++++++++++
> >  1 file changed, 14 insertions(+)
> > 
> > diff --git a/drivers/net/i40e/base/i40e_osdep.h b/drivers/net/i40e/base/i40e_osdep.h
> > index 38e7ba5..ffa3160 100644
> > --- a/drivers/net/i40e/base/i40e_osdep.h
> > +++ b/drivers/net/i40e/base/i40e_osdep.h
> > @@ -158,7 +158,13 @@ do {                                                            \
> >  	((volatile uint32_t *)((char *)(a)->hw_addr + (reg)))
> >  static inline uint32_t i40e_read_addr(volatile void *addr)
> >  {
> > +#if defined(RTE_ARCH_ARM64)
> > +	uint32_t val = rte_le_to_cpu_32(I40E_PCI_REG(addr));
> > +	rte_rmb();
> > +	return val;
> 
> If you really need an rmb/wmb with MMIO read/writes on ARM,
> I think you can avoid #ifdefs here and use rte_smp_rmb/rte_smp_wmb.
> BTW, I suppose if you need it for i40e, you would need it for other devices too.

Yes. ARM would need for all devices(typically, the devices on external PCI bus).
I guess rte_smp_rmb may not be the correct abstraction. So we need more of
rte_rmb() as we need only non smp variant on IO side. I guess then it make sense to
create new abstraction in eal with following variants so that each arch
gets opportunity to make what it makes sense that specific platform

rte_readb_relaxed
rte_readw_relaxed
rte_readl_relaxed
rte_readq_relaxed
rte_writeb_relaxed
rte_writew_relaxed
rte_writel_relaxed
rte_writeq_relaxed
rte_readb
rte_readw
rte_readl
rte_readq
rte_writeb
rte_writew
rte_writel
rte_writeq

Thoughts ?

Jerin

> Konstantin
> 
> > +#else
> >  	return rte_le_to_cpu_32(I40E_PCI_REG(addr));
> > +#endif
> >  }
> >  #define I40E_PCI_REG_WRITE(reg, value) \
> >  	do { I40E_PCI_REG((reg)) = rte_cpu_to_le_32(value); } while (0)
> > @@ -171,8 +177,16 @@ static inline uint32_t i40e_read_addr(volatile void *addr)
> >  	I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((hw), (reg)), (value))
> > 
> >  #define rd32(a, reg) i40e_read_addr(I40E_PCI_REG_ADDR((a), (reg)))
> > +#if defined(RTE_ARCH_ARM64)
> > +#define wr32(a, reg, value) \
> > +	do { \
> > +		I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((a), (reg)), (value)); \
> > +		rte_wmb(); \
> > +	} while (0)
> > +#else
> >  #define wr32(a, reg, value) \
> >  	I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((a), (reg)), (value))
> > +#endif
> >  #define flush(a) i40e_read_addr(I40E_PCI_REG_ADDR((a), (I40E_GLGEN_STAT)))
> > 
> >  #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
> > --
> > 2.7.4
> 

^ permalink raw reply

* Re: [RFC PATCH 0/7] RFC: EventDev Software PMD
From: Jerin Jacob @ 2016-11-21 20:18 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: Harry van Haaren, dev
In-Reply-To: <20161121094856.GA16124@bricha3-MOBL3.ger.corp.intel.com>

On Mon, Nov 21, 2016 at 09:48:56AM +0000, Bruce Richardson wrote:
> On Sat, Nov 19, 2016 at 03:53:25AM +0530, Jerin Jacob wrote:
> > On Thu, Nov 17, 2016 at 10:05:07AM +0000, Bruce Richardson wrote:
> > > > 2) device stats API can be based on capability, HW implementations may not
> > > > support all the stats
> > > 
> > > Yes, this is something we were thinking about. It would be nice if we
> > > could at least come up with a common set of stats - maybe even ones
> > > tracked at an eventdev API level, e.g. nb enqueues/dequeues. As well as
> > > that, we think the idea of an xstats API, like in ethdev, might work
> > > well. For our software implementation, having visibility into the
> > > scheduler behaviour can be important, so we'd like a way to report out
> > > things like internal queue depths etc.
> > >
> > 
> > Since these are not very generic hardware, I am not sure how much sense
> > to have generic stats API. But, Something similar to ethdev's xstat(any capability based)
> > the scheme works well. Look forward to seeing API proposal with common code.
> > 
> > Jerin
> > 
> Well, to start off with, some stats that could be tracked at the API
> level could be common. What about counts of number of enqueues and
> dequeues?
> 
> I suppose the other way we can look at this is: once we get a few
> implementations of the interface, we can look at the provided xstats
> values from each one, and see if there is anything common between them.

That makes more sense to me as we don't have proposed counts. I think,
Then we should not use stats for functional tests as proposed. We could
verify the functional test by embedding some value in event object on
enqueue and later check the same on dequeue kind of scheme.

Jerin



> 
> /Bruce

^ permalink raw reply

* Re: [PATCH 2/4] eventdev: implement the northbound APIs
From: Jerin Jacob @ 2016-11-21 19:31 UTC (permalink / raw)
  To: Eads, Gage
  Cc: dev@dpdk.org, Richardson, Bruce, Van Haaren, Harry,
	hemant.agrawal@nxp.com
In-Reply-To: <20161121191358.GA9044@svelivela-lt.caveonetworks.com>

On Tue, Nov 22, 2016 at 12:43:58AM +0530, Jerin Jacob wrote:
> On Mon, Nov 21, 2016 at 05:45:51PM +0000, Eads, Gage wrote:
> > Hi Jerin,
> > 
> > I did a quick review and overall this implementation looks good. I noticed just one issue in rte_event_queue_setup(): the check of nb_atomic_order_sequences is being applied to atomic-type queues, but that field applies to ordered-type queues.
> 
> Thanks Gage. I will fix that in v2.
> 
> > 
> > One open issue I noticed is the "typical workflow" description starting in rte_eventdev.h:204 conflicts with the centralized software PMD that Harry posted last week. Specifically, that PMD expects a single core to call the schedule function. We could extend the documentation to account for this alternative style of scheduler invocation, or discuss ways to make the software PMD work with the documented workflow. I prefer the former, but either way I think we ought to expose the scheduler's expected usage to the user -- perhaps through an RTE_EVENT_DEV_CAP flag?
> 
> I prefer former too, you can propose the documentation change required for software PMD.
> 
> On same note, If software PMD based workflow need  a separate core(s) for
> schedule function then, Can we hide that from API specification and pass an
> argument to SW pmd to define the scheduling core(s)?
> 
> Something like --vdev=eventsw0,schedule_cmask=0x2

Just a thought,

Perhaps, We could introduce generic "service" cores concept to DPDK to hide the
requirement where the implementation needs dedicated core to do certain
work. I guess it would useful for other NPU integration in DPDK.

> 
> > 
> > Thanks,
> > Gage
> > 
> > >  -----Original Message-----
> > >  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> > >  Sent: Thursday, November 17, 2016 11:45 PM
> > >  To: dev@dpdk.org
> > >  Cc: Richardson, Bruce <bruce.richardson@intel.com>; Van Haaren, Harry
> > >  <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com; Eads, Gage
> > >  <gage.eads@intel.com>; Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > >  Subject: [dpdk-dev] [PATCH 2/4] eventdev: implement the northbound APIs
> > >  
> > >  This patch set defines the southbound driver interface
> > >  and implements the common code required for northbound
> > >  eventdev API interface.
> > >  
> > >  Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > >  ---
> > >   config/common_base                           |    6 +
> > >   lib/Makefile                                 |    1 +
> > >   lib/librte_eal/common/include/rte_log.h      |    1 +
> > >   lib/librte_eventdev/Makefile                 |   57 ++
> > >   lib/librte_eventdev/rte_eventdev.c           | 1211
> > >  ++++++++++++++++++++++++++
> > >   lib/librte_eventdev/rte_eventdev_pmd.h       |  504 +++++++++++
> > >   lib/librte_eventdev/rte_eventdev_version.map |   39 +
> > >   mk/rte.app.mk                                |    1 +
> > >   8 files changed, 1820 insertions(+)
> > >   create mode 100644 lib/librte_eventdev/Makefile
> > >   create mode 100644 lib/librte_eventdev/rte_eventdev.c
> > >   create mode 100644 lib/librte_eventdev/rte_eventdev_pmd.h
> > >   create mode 100644 lib/librte_eventdev/rte_eventdev_version.map
> > >  
> > >  diff --git a/config/common_base b/config/common_base
> > >  index 4bff83a..7a8814e 100644
> > >  --- a/config/common_base
> > >  +++ b/config/common_base
> > >  @@ -411,6 +411,12 @@ CONFIG_RTE_LIBRTE_PMD_ZUC_DEBUG=n
> > >   CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=y
> > >  
> > >   #
> > >  +# Compile generic event device library
> > >  +#
> > >  +CONFIG_RTE_LIBRTE_EVENTDEV=y
> > >  +CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
> > >  +CONFIG_RTE_EVENT_MAX_DEVS=16
> > >  +CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
> > >   # Compile librte_ring
> > >   #
> > >   CONFIG_RTE_LIBRTE_RING=y
> > >  diff --git a/lib/Makefile b/lib/Makefile
> > >  index 990f23a..1a067bf 100644
> > >  --- a/lib/Makefile
> > >  +++ b/lib/Makefile
> > >  @@ -41,6 +41,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
> > >   DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
> > >   DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
> > >   DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
> > >  +DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
> > >   DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
> > >   DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
> > >   DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
> > >  diff --git a/lib/librte_eal/common/include/rte_log.h
> > >  b/lib/librte_eal/common/include/rte_log.h
> > >  index 29f7d19..9a07d92 100644
> > >  --- a/lib/librte_eal/common/include/rte_log.h
> > >  +++ b/lib/librte_eal/common/include/rte_log.h
> > >  @@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
> > >   #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
> > >   #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
> > >   #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to
> > >  cryptodev. */
> > >  +#define RTE_LOGTYPE_EVENTDEV 0x00040000 /**< Log related to eventdev.
> > >  */
> > >  
> > >   /* these log types can be used in an application */
> > >   #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
> > >  diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
> > >  new file mode 100644
> > >  index 0000000..dac0663
> > >  --- /dev/null
> > >  +++ b/lib/librte_eventdev/Makefile
> > >  @@ -0,0 +1,57 @@
> > >  +#   BSD LICENSE
> > >  +#
> > >  +#   Copyright(c) 2016 Cavium networks. All rights reserved.
> > >  +#
> > >  +#   Redistribution and use in source and binary forms, with or without
> > >  +#   modification, are permitted provided that the following conditions
> > >  +#   are met:
> > >  +#
> > >  +#     * Redistributions of source code must retain the above copyright
> > >  +#       notice, this list of conditions and the following disclaimer.
> > >  +#     * Redistributions in binary form must reproduce the above copyright
> > >  +#       notice, this list of conditions and the following disclaimer in
> > >  +#       the documentation and/or other materials provided with the
> > >  +#       distribution.
> > >  +#     * Neither the name of Cavium networks nor the names of its
> > >  +#       contributors may be used to endorse or promote products derived
> > >  +#       from this software without specific prior written permission.
> > >  +#
> > >  +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > >  CONTRIBUTORS
> > >  +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> > >  NOT
> > >  +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > >  FITNESS FOR
> > >  +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > >  COPYRIGHT
> > >  +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > >  INCIDENTAL,
> > >  +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> > >  NOT
> > >  +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> > >  OF USE,
> > >  +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> > >  ON ANY
> > >  +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > >  TORT
> > >  +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> > >  THE USE
> > >  +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > >  DAMAGE.
> > >  +
> > >  +include $(RTE_SDK)/mk/rte.vars.mk
> > >  +
> > >  +# library name
> > >  +LIB = librte_eventdev.a
> > >  +
> > >  +# library version
> > >  +LIBABIVER := 1
> > >  +
> > >  +# build flags
> > >  +CFLAGS += -O3
> > >  +CFLAGS += $(WERROR_FLAGS)
> > >  +
> > >  +# library source files
> > >  +SRCS-y += rte_eventdev.c
> > >  +
> > >  +# export include files
> > >  +SYMLINK-y-include += rte_eventdev.h
> > >  +SYMLINK-y-include += rte_eventdev_pmd.h
> > >  +
> > >  +# versioning export map
> > >  +EXPORT_MAP := rte_eventdev_version.map
> > >  +
> > >  +# library dependencies
> > >  +DEPDIRS-y += lib/librte_eal
> > >  +DEPDIRS-y += lib/librte_mbuf
> > >  +
> > >  +include $(RTE_SDK)/mk/rte.lib.mk
> > >  diff --git a/lib/librte_eventdev/rte_eventdev.c
> > >  b/lib/librte_eventdev/rte_eventdev.c
> > >  new file mode 100644
> > >  index 0000000..17ce5c3
> > >  --- /dev/null
> > >  +++ b/lib/librte_eventdev/rte_eventdev.c
> > >  @@ -0,0 +1,1211 @@
> > >  +/*
> > >  + *   BSD LICENSE
> > >  + *
> > >  + *   Copyright(c) 2016 Cavium networks. All rights reserved.
> > >  + *
> > >  + *   Redistribution and use in source and binary forms, with or without
> > >  + *   modification, are permitted provided that the following conditions
> > >  + *   are met:
> > >  + *
> > >  + *     * Redistributions of source code must retain the above copyright
> > >  + *       notice, this list of conditions and the following disclaimer.
> > >  + *     * Redistributions in binary form must reproduce the above copyright
> > >  + *       notice, this list of conditions and the following disclaimer in
> > >  + *       the documentation and/or other materials provided with the
> > >  + *       distribution.
> > >  + *     * Neither the name of Cavium networks nor the names of its
> > >  + *       contributors may be used to endorse or promote products derived
> > >  + *       from this software without specific prior written permission.
> > >  + *
> > >  + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > >  CONTRIBUTORS
> > >  + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> > >  NOT
> > >  + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > >  FITNESS FOR
> > >  + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > >  COPYRIGHT
> > >  + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > >  INCIDENTAL,
> > >  + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> > >  NOT
> > >  + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> > >  OF USE,
> > >  + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> > >  AND ON ANY
> > >  + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > >  TORT
> > >  + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> > >  THE USE
> > >  + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > >  DAMAGE.
> > >  + */
> > >  +
> > >  +#include <ctype.h>
> > >  +#include <stdio.h>
> > >  +#include <stdlib.h>
> > >  +#include <string.h>
> > >  +#include <stdarg.h>
> > >  +#include <errno.h>
> > >  +#include <stdint.h>
> > >  +#include <inttypes.h>
> > >  +#include <sys/types.h>
> > >  +#include <sys/queue.h>
> > >  +
> > >  +#include <rte_byteorder.h>
> > >  +#include <rte_log.h>
> > >  +#include <rte_debug.h>
> > >  +#include <rte_dev.h>
> > >  +#include <rte_pci.h>
> > >  +#include <rte_memory.h>
> > >  +#include <rte_memcpy.h>
> > >  +#include <rte_memzone.h>
> > >  +#include <rte_eal.h>
> > >  +#include <rte_per_lcore.h>
> > >  +#include <rte_lcore.h>
> > >  +#include <rte_atomic.h>
> > >  +#include <rte_branch_prediction.h>
> > >  +#include <rte_common.h>
> > >  +#include <rte_malloc.h>
> > >  +#include <rte_errno.h>
> > >  +
> > >  +#include "rte_eventdev.h"
> > >  +#include "rte_eventdev_pmd.h"
> > >  +
> > >  +struct rte_eventdev rte_event_devices[RTE_EVENT_MAX_DEVS];
> > >  +
> > >  +struct rte_eventdev *rte_eventdevs = &rte_event_devices[0];
> > >  +
> > >  +static struct rte_eventdev_global eventdev_globals = {
> > >  +	.nb_devs		= 0
> > >  +};
> > >  +
> > >  +struct rte_eventdev_global *rte_eventdev_globals = &eventdev_globals;
> > >  +
> > >  +/* Event dev north bound API implementation */
> > >  +
> > >  +uint8_t
> > >  +rte_event_dev_count(void)
> > >  +{
> > >  +	return rte_eventdev_globals->nb_devs;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dev_get_dev_id(const char *name)
> > >  +{
> > >  +	int i;
> > >  +
> > >  +	if (!name)
> > >  +		return -EINVAL;
> > >  +
> > >  +	for (i = 0; i < rte_eventdev_globals->nb_devs; i++)
> > >  +		if ((strcmp(rte_event_devices[i].data->name, name)
> > >  +				== 0) &&
> > >  +				(rte_event_devices[i].attached ==
> > >  +						RTE_EVENTDEV_ATTACHED))
> > >  +			return i;
> > >  +	return -ENODEV;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dev_socket_id(uint8_t dev_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	return dev->data->socket_id;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dev_info_get(uint8_t dev_id, struct rte_event_dev_info *dev_info)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	if (dev_info == NULL)
> > >  +		return -EINVAL;
> > >  +
> > >  +	memset(dev_info, 0, sizeof(struct rte_event_dev_info));
> > >  +
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
> > >  ENOTSUP);
> > >  +	(*dev->dev_ops->dev_infos_get)(dev, dev_info);
> > >  +
> > >  +	dev_info->pci_dev = dev->pci_dev;
> > >  +	if (dev->driver)
> > >  +		dev_info->driver_name = dev->driver->pci_drv.driver.name;
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +static inline int
> > >  +rte_event_dev_queue_config(struct rte_eventdev *dev, uint8_t nb_queues)
> > >  +{
> > >  +	uint8_t old_nb_queues = dev->data->nb_queues;
> > >  +	void **queues;
> > >  +	uint8_t *queues_prio;
> > >  +	unsigned int i;
> > >  +
> > >  +	EDEV_LOG_DEBUG("Setup %d queues on device %u", nb_queues,
> > >  +			 dev->data->dev_id);
> > >  +
> > >  +	/* First time configuration */
> > >  +	if (dev->data->queues == NULL && nb_queues != 0) {
> > >  +		dev->data->queues = rte_zmalloc_socket("eventdev->data-
> > >  >queues",
> > >  +				sizeof(dev->data->queues[0]) * nb_queues,
> > >  +				RTE_CACHE_LINE_SIZE, dev->data-
> > >  >socket_id);
> > >  +		if (dev->data->queues == NULL) {
> > >  +			dev->data->nb_queues = 0;
> > >  +			EDEV_LOG_ERR("failed to get memory for queue meta
> > >  data,"
> > >  +					"nb_queues %u", nb_queues);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +		/* Allocate memory to store queue priority */
> > >  +		dev->data->queues_prio = rte_zmalloc_socket(
> > >  +				"eventdev->data->queues_prio",
> > >  +				sizeof(dev->data->queues_prio[0]) *
> > >  nb_queues,
> > >  +				RTE_CACHE_LINE_SIZE, dev->data-
> > >  >socket_id);
> > >  +		if (dev->data->queues_prio == NULL) {
> > >  +			dev->data->nb_queues = 0;
> > >  +			EDEV_LOG_ERR("failed to get memory for queue
> > >  priority,"
> > >  +					"nb_queues %u", nb_queues);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +	} else if (dev->data->queues != NULL && nb_queues != 0) {/* re-config
> > >  */
> > >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > >  >queue_release, -ENOTSUP);
> > >  +
> > >  +		queues = dev->data->queues;
> > >  +		for (i = nb_queues; i < old_nb_queues; i++)
> > >  +			(*dev->dev_ops->queue_release)(queues[i]);
> > >  +
> > >  +		queues = rte_realloc(queues, sizeof(queues[0]) * nb_queues,
> > >  +				RTE_CACHE_LINE_SIZE);
> > >  +		if (queues == NULL) {
> > >  +			EDEV_LOG_ERR("failed to realloc queue meta data,"
> > >  +						" nb_queues %u",
> > >  nb_queues);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +		dev->data->queues = queues;
> > >  +
> > >  +		/* Re allocate memory to store queue priority */
> > >  +		queues_prio = dev->data->queues_prio;
> > >  +		queues_prio = rte_realloc(queues_prio,
> > >  +				sizeof(queues_prio[0]) * nb_queues,
> > >  +				RTE_CACHE_LINE_SIZE);
> > >  +		if (queues_prio == NULL) {
> > >  +			EDEV_LOG_ERR("failed to realloc queue priority,"
> > >  +						" nb_queues %u",
> > >  nb_queues);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +		dev->data->queues_prio = queues_prio;
> > >  +
> > >  +		if (nb_queues > old_nb_queues) {
> > >  +			uint8_t new_qs = nb_queues - old_nb_queues;
> > >  +
> > >  +			memset(queues + old_nb_queues, 0,
> > >  +				sizeof(queues[0]) * new_qs);
> > >  +			memset(queues_prio + old_nb_queues, 0,
> > >  +				sizeof(queues_prio[0]) * new_qs);
> > >  +		}
> > >  +	} else if (dev->data->queues != NULL && nb_queues == 0) {
> > >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > >  >queue_release, -ENOTSUP);
> > >  +
> > >  +		queues = dev->data->queues;
> > >  +		for (i = nb_queues; i < old_nb_queues; i++)
> > >  +			(*dev->dev_ops->queue_release)(queues[i]);
> > >  +	}
> > >  +
> > >  +	dev->data->nb_queues = nb_queues;
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +static inline int
> > >  +rte_event_dev_port_config(struct rte_eventdev *dev, uint8_t nb_ports)
> > >  +{
> > >  +	uint8_t old_nb_ports = dev->data->nb_ports;
> > >  +	void **ports;
> > >  +	uint16_t *links_map;
> > >  +	uint8_t *ports_dequeue_depth;
> > >  +	uint8_t *ports_enqueue_depth;
> > >  +	unsigned int i;
> > >  +
> > >  +	EDEV_LOG_DEBUG("Setup %d ports on device %u", nb_ports,
> > >  +			 dev->data->dev_id);
> > >  +
> > >  +	/* First time configuration */
> > >  +	if (dev->data->ports == NULL && nb_ports != 0) {
> > >  +		dev->data->ports = rte_zmalloc_socket("eventdev->data-
> > >  >ports",
> > >  +				sizeof(dev->data->ports[0]) * nb_ports,
> > >  +				RTE_CACHE_LINE_SIZE, dev->data-
> > >  >socket_id);
> > >  +		if (dev->data->ports == NULL) {
> > >  +			dev->data->nb_ports = 0;
> > >  +			EDEV_LOG_ERR("failed to get memory for port meta
> > >  data,"
> > >  +					"nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +		/* Allocate memory to store ports dequeue depth */
> > >  +		dev->data->ports_dequeue_depth =
> > >  +			rte_zmalloc_socket("eventdev-
> > >  >ports_dequeue_depth",
> > >  +			sizeof(dev->data->ports_dequeue_depth[0]) *
> > >  nb_ports,
> > >  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
> > >  +		if (dev->data->ports_dequeue_depth == NULL) {
> > >  +			dev->data->nb_ports = 0;
> > >  +			EDEV_LOG_ERR("failed to get memory for port deq
> > >  meta,"
> > >  +					"nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +		/* Allocate memory to store ports enqueue depth */
> > >  +		dev->data->ports_enqueue_depth =
> > >  +			rte_zmalloc_socket("eventdev-
> > >  >ports_enqueue_depth",
> > >  +			sizeof(dev->data->ports_enqueue_depth[0]) *
> > >  nb_ports,
> > >  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
> > >  +		if (dev->data->ports_enqueue_depth == NULL) {
> > >  +			dev->data->nb_ports = 0;
> > >  +			EDEV_LOG_ERR("failed to get memory for port enq
> > >  meta,"
> > >  +					"nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +		/* Allocate memory to store queue to port link connection */
> > >  +		dev->data->links_map =
> > >  +			rte_zmalloc_socket("eventdev->links_map",
> > >  +			sizeof(dev->data->links_map[0]) * nb_ports *
> > >  +			RTE_EVENT_MAX_QUEUES_PER_DEV,
> > >  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
> > >  +		if (dev->data->links_map == NULL) {
> > >  +			dev->data->nb_ports = 0;
> > >  +			EDEV_LOG_ERR("failed to get memory for port_map
> > >  area,"
> > >  +					"nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +	} else if (dev->data->ports != NULL && nb_ports != 0) {/* re-config */
> > >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release,
> > >  -ENOTSUP);
> > >  +
> > >  +		ports = dev->data->ports;
> > >  +		ports_dequeue_depth = dev->data->ports_dequeue_depth;
> > >  +		ports_enqueue_depth = dev->data->ports_enqueue_depth;
> > >  +		links_map = dev->data->links_map;
> > >  +
> > >  +		for (i = nb_ports; i < old_nb_ports; i++)
> > >  +			(*dev->dev_ops->port_release)(ports[i]);
> > >  +
> > >  +		/* Realloc memory for ports */
> > >  +		ports = rte_realloc(ports, sizeof(ports[0]) * nb_ports,
> > >  +				RTE_CACHE_LINE_SIZE);
> > >  +		if (ports == NULL) {
> > >  +			EDEV_LOG_ERR("failed to realloc port meta data,"
> > >  +						" nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +		/* Realloc memory for ports_dequeue_depth */
> > >  +		ports_dequeue_depth = rte_realloc(ports_dequeue_depth,
> > >  +			sizeof(ports_dequeue_depth[0]) * nb_ports,
> > >  +			RTE_CACHE_LINE_SIZE);
> > >  +		if (ports_dequeue_depth == NULL) {
> > >  +			EDEV_LOG_ERR("failed to realloc port deqeue meta
> > >  data,"
> > >  +						" nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +		/* Realloc memory for ports_enqueue_depth */
> > >  +		ports_enqueue_depth = rte_realloc(ports_enqueue_depth,
> > >  +			sizeof(ports_enqueue_depth[0]) * nb_ports,
> > >  +			RTE_CACHE_LINE_SIZE);
> > >  +		if (ports_enqueue_depth == NULL) {
> > >  +			EDEV_LOG_ERR("failed to realloc port enqueue meta
> > >  data,"
> > >  +						" nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +		/* Realloc memory to store queue to port link connection */
> > >  +		links_map = rte_realloc(links_map,
> > >  +			sizeof(dev->data->links_map[0]) * nb_ports *
> > >  +			RTE_EVENT_MAX_QUEUES_PER_DEV,
> > >  +			RTE_CACHE_LINE_SIZE);
> > >  +		if (dev->data->links_map == NULL) {
> > >  +			dev->data->nb_ports = 0;
> > >  +			EDEV_LOG_ERR("failed to realloc mem for port_map
> > >  area,"
> > >  +					"nb_ports %u", nb_ports);
> > >  +			return -(ENOMEM);
> > >  +		}
> > >  +
> > >  +		if (nb_ports > old_nb_ports) {
> > >  +			uint8_t new_ps = nb_ports - old_nb_ports;
> > >  +
> > >  +			memset(ports + old_nb_ports, 0,
> > >  +				sizeof(ports[0]) * new_ps);
> > >  +			memset(ports_dequeue_depth + old_nb_ports, 0,
> > >  +				sizeof(ports_dequeue_depth[0]) * new_ps);
> > >  +			memset(ports_enqueue_depth + old_nb_ports, 0,
> > >  +				sizeof(ports_enqueue_depth[0]) * new_ps);
> > >  +			memset(links_map +
> > >  +				(old_nb_ports *
> > >  RTE_EVENT_MAX_QUEUES_PER_DEV),
> > >  +				0, sizeof(ports_enqueue_depth[0]) * new_ps);
> > >  +		}
> > >  +
> > >  +		dev->data->ports = ports;
> > >  +		dev->data->ports_dequeue_depth = ports_dequeue_depth;
> > >  +		dev->data->ports_enqueue_depth = ports_enqueue_depth;
> > >  +		dev->data->links_map = links_map;
> > >  +	} else if (dev->data->ports != NULL && nb_ports == 0) {
> > >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release,
> > >  -ENOTSUP);
> > >  +
> > >  +		ports = dev->data->ports;
> > >  +		for (i = nb_ports; i < old_nb_ports; i++)
> > >  +			(*dev->dev_ops->port_release)(ports[i]);
> > >  +	}
> > >  +
> > >  +	dev->data->nb_ports = nb_ports;
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dev_configure(uint8_t dev_id, struct rte_event_dev_config
> > >  *dev_conf)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	struct rte_event_dev_info info;
> > >  +	int diag;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
> > >  ENOTSUP);
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -
> > >  ENOTSUP);
> > >  +
> > >  +	if (dev->data->dev_started) {
> > >  +		EDEV_LOG_ERR(
> > >  +		    "device %d must be stopped to allow configuration",
> > >  dev_id);
> > >  +		return -EBUSY;
> > >  +	}
> > >  +
> > >  +	if (dev_conf == NULL)
> > >  +		return -EINVAL;
> > >  +
> > >  +	(*dev->dev_ops->dev_infos_get)(dev, &info);
> > >  +
> > >  +	/* Check dequeue_wait_ns value is in limit */
> > >  +	if (!dev_conf->event_dev_cfg &
> > >  RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT) {
> > >  +		if (dev_conf->dequeue_wait_ns < info.min_dequeue_wait_ns
> > >  ||
> > >  +			dev_conf->dequeue_wait_ns >
> > >  info.max_dequeue_wait_ns) {
> > >  +			EDEV_LOG_ERR("dev%d invalid dequeue_wait_ns=%d"
> > >  +			" min_dequeue_wait_ns=%d
> > >  max_dequeue_wait_ns=%d",
> > >  +			dev_id, dev_conf->dequeue_wait_ns,
> > >  +			info.min_dequeue_wait_ns,
> > >  +			info.max_dequeue_wait_ns);
> > >  +			return -EINVAL;
> > >  +		}
> > >  +	}
> > >  +
> > >  +	/* Check nb_events_limit is in limit */
> > >  +	if (dev_conf->nb_events_limit > info.max_num_events) {
> > >  +		EDEV_LOG_ERR("dev%d nb_events_limit=%d >
> > >  max_num_events=%d",
> > >  +		dev_id, dev_conf->nb_events_limit, info.max_num_events);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check nb_event_queues is in limit */
> > >  +	if (!dev_conf->nb_event_queues) {
> > >  +		EDEV_LOG_ERR("dev%d nb_event_queues cannot be zero",
> > >  dev_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +	if (dev_conf->nb_event_queues > info.max_event_queues) {
> > >  +		EDEV_LOG_ERR("dev%d nb_event_queues=%d >
> > >  max_event_queues=%d",
> > >  +		dev_id, dev_conf->nb_event_queues,
> > >  info.max_event_queues);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check nb_event_ports is in limit */
> > >  +	if (!dev_conf->nb_event_ports) {
> > >  +		EDEV_LOG_ERR("dev%d nb_event_ports cannot be zero",
> > >  dev_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +	if (dev_conf->nb_event_ports > info.max_event_ports) {
> > >  +		EDEV_LOG_ERR("dev%d nb_event_ports=%d >
> > >  max_event_ports= %d",
> > >  +		dev_id, dev_conf->nb_event_ports, info.max_event_ports);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check nb_event_queue_flows is in limit */
> > >  +	if (!dev_conf->nb_event_queue_flows) {
> > >  +		EDEV_LOG_ERR("dev%d nb_flows cannot be zero", dev_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +	if (dev_conf->nb_event_queue_flows > info.max_event_queue_flows)
> > >  {
> > >  +		EDEV_LOG_ERR("dev%d nb_flows=%x > max_flows=%x",
> > >  +		dev_id, dev_conf->nb_event_queue_flows,
> > >  +		info.max_event_queue_flows);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check nb_event_port_dequeue_depth is in limit */
> > >  +	if (!dev_conf->nb_event_port_dequeue_depth) {
> > >  +		EDEV_LOG_ERR("dev%d nb_dequeue_depth cannot be zero",
> > >  dev_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +	if (dev_conf->nb_event_port_dequeue_depth >
> > >  +			 info.max_event_port_dequeue_depth) {
> > >  +		EDEV_LOG_ERR("dev%d nb_dequeue_depth=%d >
> > >  max_dequeue_depth=%d",
> > >  +		dev_id, dev_conf->nb_event_port_dequeue_depth,
> > >  +		info.max_event_port_dequeue_depth);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check nb_event_port_enqueue_depth is in limit */
> > >  +	if (!dev_conf->nb_event_port_enqueue_depth) {
> > >  +		EDEV_LOG_ERR("dev%d nb_enqueue_depth cannot be zero",
> > >  dev_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +	if (dev_conf->nb_event_port_enqueue_depth >
> > >  +			 info.max_event_port_enqueue_depth) {
> > >  +		EDEV_LOG_ERR("dev%d nb_enqueue_depth=%d >
> > >  max_enqueue_depth=%d",
> > >  +		dev_id, dev_conf->nb_event_port_enqueue_depth,
> > >  +		info.max_event_port_enqueue_depth);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Copy the dev_conf parameter into the dev structure */
> > >  +	memcpy(&dev->data->dev_conf, dev_conf, sizeof(dev->data-
> > >  >dev_conf));
> > >  +
> > >  +	/* Setup new number of queues and reconfigure device. */
> > >  +	diag = rte_event_dev_queue_config(dev, dev_conf-
> > >  >nb_event_queues);
> > >  +	if (diag != 0) {
> > >  +		EDEV_LOG_ERR("dev%d rte_event_dev_queue_config = %d",
> > >  +				dev_id, diag);
> > >  +		return diag;
> > >  +	}
> > >  +
> > >  +	/* Setup new number of ports and reconfigure device. */
> > >  +	diag = rte_event_dev_port_config(dev, dev_conf->nb_event_ports);
> > >  +	if (diag != 0) {
> > >  +		rte_event_dev_queue_config(dev, 0);
> > >  +		EDEV_LOG_ERR("dev%d rte_event_dev_port_config = %d",
> > >  +				dev_id, diag);
> > >  +		return diag;
> > >  +	}
> > >  +
> > >  +	/* Configure the device */
> > >  +	diag = (*dev->dev_ops->dev_configure)(dev);
> > >  +	if (diag != 0) {
> > >  +		EDEV_LOG_ERR("dev%d dev_configure = %d", dev_id, diag);
> > >  +		rte_event_dev_queue_config(dev, 0);
> > >  +		rte_event_dev_port_config(dev, 0);
> > >  +	}
> > >  +
> > >  +	dev->data->event_dev_cap = info.event_dev_cap;
> > >  +	return diag;
> > >  +}
> > >  +
> > >  +static inline int
> > >  +is_valid_queue(struct rte_eventdev *dev, uint8_t queue_id)
> > >  +{
> > >  +	if (queue_id < dev->data->nb_queues && queue_id <
> > >  +				RTE_EVENT_MAX_QUEUES_PER_DEV)
> > >  +		return 1;
> > >  +	else
> > >  +		return 0;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_queue_default_conf_get(uint8_t dev_id, uint8_t queue_id,
> > >  +				 struct rte_event_queue_conf *queue_conf)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	if (queue_conf == NULL)
> > >  +		return -EINVAL;
> > >  +
> > >  +	if (!is_valid_queue(dev, queue_id)) {
> > >  +		EDEV_LOG_ERR("Invalid queue_id=%" PRIu8, queue_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_def_conf, -
> > >  ENOTSUP);
> > >  +	memset(queue_conf, 0, sizeof(struct rte_event_queue_conf));
> > >  +	(*dev->dev_ops->queue_def_conf)(dev, queue_id, queue_conf);
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +static inline int
> > >  +is_valid_atomic_queue_conf(struct rte_event_queue_conf *queue_conf)
> > >  +{
> > >  +	if (queue_conf && (
> > >  +		((queue_conf->event_queue_cfg &
> > >  RTE_EVENT_QUEUE_CFG_TYPE_MASK)
> > >  +			== RTE_EVENT_QUEUE_CFG_ALL_TYPES) ||
> > >  +		((queue_conf->event_queue_cfg &
> > >  RTE_EVENT_QUEUE_CFG_TYPE_MASK)
> > >  +			== RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY)
> > >  +		))
> > >  +		return 1;
> > >  +	else
> > >  +		return 0;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_queue_setup(uint8_t dev_id, uint8_t queue_id,
> > >  +		      struct rte_event_queue_conf *queue_conf)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	struct rte_event_queue_conf def_conf;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	if (!is_valid_queue(dev, queue_id)) {
> > >  +		EDEV_LOG_ERR("Invalid queue_id=%" PRIu8, queue_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check nb_atomic_flows limit */
> > >  +	if (is_valid_atomic_queue_conf(queue_conf)) {
> > >  +		if (queue_conf->nb_atomic_flows == 0 ||
> > >  +		    queue_conf->nb_atomic_flows >
> > >  +			dev->data->dev_conf.nb_event_queue_flows) {
> > >  +			EDEV_LOG_ERR(
> > >  +		"dev%d queue%d Invalid nb_atomic_flows=%d
> > >  max_flows=%d",
> > >  +			dev_id, queue_id, queue_conf->nb_atomic_flows,
> > >  +			dev->data->dev_conf.nb_event_queue_flows);
> > >  +			return -EINVAL;
> > >  +		}
> > >  +	}
> > >  +
> > >  +	/* Check nb_atomic_order_sequences limit */
> > >  +	if (is_valid_atomic_queue_conf(queue_conf)) {
> > >  +		if (queue_conf->nb_atomic_order_sequences == 0 ||
> > >  +		    queue_conf->nb_atomic_order_sequences >
> > >  +			dev->data->dev_conf.nb_event_queue_flows) {
> > >  +			EDEV_LOG_ERR(
> > >  +		"dev%d queue%d Invalid nb_atomic_order_seq=%d
> > >  max_flows=%d",
> > >  +			dev_id, queue_id, queue_conf-
> > >  >nb_atomic_order_sequences,
> > >  +			dev->data->dev_conf.nb_event_queue_flows);
> > >  +			return -EINVAL;
> > >  +		}
> > >  +	}
> > >  +
> > >  +	if (dev->data->dev_started) {
> > >  +		EDEV_LOG_ERR(
> > >  +		    "device %d must be stopped to allow queue setup", dev_id);
> > >  +		return -EBUSY;
> > >  +	}
> > >  +
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_setup, -
> > >  ENOTSUP);
> > >  +
> > >  +	if (queue_conf == NULL) {
> > >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > >  >queue_def_conf,
> > >  +					-ENOTSUP);
> > >  +		(*dev->dev_ops->queue_def_conf)(dev, queue_id, &def_conf);
> > >  +		def_conf.event_queue_cfg =
> > >  RTE_EVENT_QUEUE_CFG_DEFAULT;
> > >  +		queue_conf = &def_conf;
> > >  +	}
> > >  +
> > >  +	dev->data->queues_prio[queue_id] = queue_conf->priority;
> > >  +	return (*dev->dev_ops->queue_setup)(dev, queue_id, queue_conf);
> > >  +}
> > >  +
> > >  +uint8_t
> > >  +rte_event_queue_count(uint8_t dev_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	return dev->data->nb_queues;
> > >  +}
> > >  +
> > >  +uint8_t
> > >  +rte_event_queue_priority(uint8_t dev_id, uint8_t queue_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	if (dev->data->event_dev_cap & RTE_EVENT_DEV_CAP_QUEUE_QOS)
> > >  +		return dev->data->queues_prio[queue_id];
> > >  +	else
> > >  +		return RTE_EVENT_QUEUE_PRIORITY_NORMAL;
> > >  +}
> > >  +
> > >  +static inline int
> > >  +is_valid_port(struct rte_eventdev *dev, uint8_t port_id)
> > >  +{
> > >  +	if (port_id < dev->data->nb_ports)
> > >  +		return 1;
> > >  +	else
> > >  +		return 0;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_port_default_conf_get(uint8_t dev_id, uint8_t port_id,
> > >  +				 struct rte_event_port_conf *port_conf)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	if (port_conf == NULL)
> > >  +		return -EINVAL;
> > >  +
> > >  +	if (!is_valid_port(dev, port_id)) {
> > >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_def_conf, -
> > >  ENOTSUP);
> > >  +	memset(port_conf, 0, sizeof(struct rte_event_port_conf));
> > >  +	(*dev->dev_ops->port_def_conf)(dev, port_id, port_conf);
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_port_setup(uint8_t dev_id, uint8_t port_id,
> > >  +		      struct rte_event_port_conf *port_conf)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	struct rte_event_port_conf def_conf;
> > >  +	int diag;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	if (!is_valid_port(dev, port_id)) {
> > >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check new_event_threshold limit */
> > >  +	if ((port_conf && !port_conf->new_event_threshold) ||
> > >  +			(port_conf && port_conf->new_event_threshold >
> > >  +				 dev->data->dev_conf.nb_events_limit)) {
> > >  +		EDEV_LOG_ERR(
> > >  +		   "dev%d port%d Invalid event_threshold=%d
> > >  nb_events_limit=%d",
> > >  +			dev_id, port_id, port_conf->new_event_threshold,
> > >  +			dev->data->dev_conf.nb_events_limit);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check dequeue_depth limit */
> > >  +	if ((port_conf && !port_conf->dequeue_depth) ||
> > >  +			(port_conf && port_conf->dequeue_depth >
> > >  +		dev->data->dev_conf.nb_event_port_dequeue_depth)) {
> > >  +		EDEV_LOG_ERR(
> > >  +		   "dev%d port%d Invalid dequeue depth=%d
> > >  max_dequeue_depth=%d",
> > >  +			dev_id, port_id, port_conf->dequeue_depth,
> > >  +			dev->data-
> > >  >dev_conf.nb_event_port_dequeue_depth);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	/* Check enqueue_depth limit */
> > >  +	if ((port_conf && !port_conf->enqueue_depth) ||
> > >  +			(port_conf && port_conf->enqueue_depth >
> > >  +		dev->data->dev_conf.nb_event_port_enqueue_depth)) {
> > >  +		EDEV_LOG_ERR(
> > >  +		   "dev%d port%d Invalid enqueue depth=%d
> > >  max_enqueue_depth=%d",
> > >  +			dev_id, port_id, port_conf->enqueue_depth,
> > >  +			dev->data-
> > >  >dev_conf.nb_event_port_enqueue_depth);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	if (dev->data->dev_started) {
> > >  +		EDEV_LOG_ERR(
> > >  +		    "device %d must be stopped to allow port setup", dev_id);
> > >  +		return -EBUSY;
> > >  +	}
> > >  +
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_setup, -
> > >  ENOTSUP);
> > >  +
> > >  +	if (port_conf == NULL) {
> > >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> > >  >port_def_conf,
> > >  +					-ENOTSUP);
> > >  +		(*dev->dev_ops->port_def_conf)(dev, port_id, &def_conf);
> > >  +		port_conf = &def_conf;
> > >  +	}
> > >  +
> > >  +	dev->data->ports_dequeue_depth[port_id] =
> > >  +			port_conf->dequeue_depth;
> > >  +	dev->data->ports_enqueue_depth[port_id] =
> > >  +			port_conf->enqueue_depth;
> > >  +
> > >  +	diag = (*dev->dev_ops->port_setup)(dev, port_id, port_conf);
> > >  +
> > >  +	/* Unlink all the queues from this port(default state after setup) */
> > >  +	if (!diag)
> > >  +		diag = rte_event_port_unlink(dev_id, port_id, NULL, 0);
> > >  +
> > >  +	if (diag < 0)
> > >  +		return diag;
> > >  +
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +uint8_t
> > >  +rte_event_port_dequeue_depth(uint8_t dev_id, uint8_t port_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	return dev->data->ports_dequeue_depth[port_id];
> > >  +}
> > >  +
> > >  +uint8_t
> > >  +rte_event_port_enqueue_depth(uint8_t dev_id, uint8_t port_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	return dev->data->ports_enqueue_depth[port_id];
> > >  +}
> > >  +
> > >  +uint8_t
> > >  +rte_event_port_count(uint8_t dev_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	return dev->data->nb_ports;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_port_link(uint8_t dev_id, uint8_t port_id,
> > >  +		    struct rte_event_queue_link link[], uint16_t nb_links)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	struct rte_event_queue_link
> > >  all_queues[RTE_EVENT_MAX_QUEUES_PER_DEV];
> > >  +	uint16_t *links_map;
> > >  +	int i, diag;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_link, -ENOTSUP);
> > >  +
> > >  +	if (!is_valid_port(dev, port_id)) {
> > >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	if (link == NULL) {
> > >  +		for (i = 0; i < dev->data->nb_queues; i++) {
> > >  +			all_queues[i].queue_id = i;
> > >  +			all_queues[i].priority =
> > >  +
> > >  	RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL;
> > >  +		}
> > >  +		link = all_queues;
> > >  +		nb_links = dev->data->nb_queues;
> > >  +	}
> > >  +
> > >  +	for (i = 0; i < nb_links; i++)
> > >  +		if (link[i].queue_id >= RTE_EVENT_MAX_QUEUES_PER_DEV)
> > >  +			return -EINVAL;
> > >  +
> > >  +	diag = (*dev->dev_ops->port_link)(dev->data->ports[port_id], link,
> > >  +						 nb_links);
> > >  +	if (diag < 0)
> > >  +		return diag;
> > >  +
> > >  +	links_map = dev->data->links_map;
> > >  +	/* Point links_map to this port specific area */
> > >  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
> > >  +	for (i = 0; i < diag; i++)
> > >  +		links_map[link[i].queue_id] = (uint8_t)link[i].priority;
> > >  +
> > >  +	return diag;
> > >  +}
> > >  +
> > >  +#define EVENT_QUEUE_SERVICE_PRIORITY_INVALID (0xdead)
> > >  +
> > >  +int
> > >  +rte_event_port_unlink(uint8_t dev_id, uint8_t port_id,
> > >  +		      uint8_t queues[], uint16_t nb_unlinks)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	uint8_t all_queues[RTE_EVENT_MAX_QUEUES_PER_DEV];
> > >  +	int i, diag;
> > >  +	uint16_t *links_map;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_unlink, -
> > >  ENOTSUP);
> > >  +
> > >  +	if (!is_valid_port(dev, port_id)) {
> > >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	if (queues == NULL) {
> > >  +		for (i = 0; i < dev->data->nb_queues; i++)
> > >  +			all_queues[i] = i;
> > >  +		queues = all_queues;
> > >  +		nb_unlinks = dev->data->nb_queues;
> > >  +	}
> > >  +
> > >  +	for (i = 0; i < nb_unlinks; i++)
> > >  +		if (queues[i] >= RTE_EVENT_MAX_QUEUES_PER_DEV)
> > >  +			return -EINVAL;
> > >  +
> > >  +	diag = (*dev->dev_ops->port_unlink)(dev->data->ports[port_id],
> > >  queues,
> > >  +					nb_unlinks);
> > >  +
> > >  +	if (diag < 0)
> > >  +		return diag;
> > >  +
> > >  +	links_map = dev->data->links_map;
> > >  +	/* Point links_map to this port specific area */
> > >  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
> > >  +	for (i = 0; i < diag; i++)
> > >  +		links_map[queues[i]] =
> > >  EVENT_QUEUE_SERVICE_PRIORITY_INVALID;
> > >  +
> > >  +	return diag;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_port_links_get(uint8_t dev_id, uint8_t port_id,
> > >  +			struct rte_event_queue_link link[])
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	uint16_t *links_map;
> > >  +	int i, count = 0;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	if (!is_valid_port(dev, port_id)) {
> > >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> > >  +		return -EINVAL;
> > >  +	}
> > >  +
> > >  +	links_map = dev->data->links_map;
> > >  +	/* Point links_map to this port specific area */
> > >  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
> > >  +	for (i = 0; i < RTE_EVENT_MAX_QUEUES_PER_DEV; i++) {
> > >  +		if (links_map[i] !=
> > >  EVENT_QUEUE_SERVICE_PRIORITY_INVALID) {
> > >  +			link[count].queue_id = i;
> > >  +			link[count].priority = (uint8_t)links_map[i];
> > >  +			++count;
> > >  +		}
> > >  +	}
> > >  +	return count;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dequeue_wait_time(uint8_t dev_id, uint64_t ns, uint64_t
> > >  *wait_ticks)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->wait_time, -
> > >  ENOTSUP);
> > >  +
> > >  +	if (wait_ticks == NULL)
> > >  +		return -EINVAL;
> > >  +
> > >  +	(*dev->dev_ops->wait_time)(dev, ns, wait_ticks);
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dev_dump(uint8_t dev_id, FILE *f)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dump, -ENOTSUP);
> > >  +
> > >  +	(*dev->dev_ops->dump)(dev, f);
> > >  +	return 0;
> > >  +
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dev_start(uint8_t dev_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	int diag;
> > >  +
> > >  +	EDEV_LOG_DEBUG("Start dev_id=%" PRIu8, dev_id);
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_start, -ENOTSUP);
> > >  +
> > >  +	if (dev->data->dev_started != 0) {
> > >  +		EDEV_LOG_ERR("Device with dev_id=%" PRIu8 " already
> > >  started",
> > >  +			dev_id);
> > >  +		return 0;
> > >  +	}
> > >  +
> > >  +	diag = (*dev->dev_ops->dev_start)(dev);
> > >  +	if (diag == 0)
> > >  +		dev->data->dev_started = 1;
> > >  +	else
> > >  +		return diag;
> > >  +
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +void
> > >  +rte_event_dev_stop(uint8_t dev_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	EDEV_LOG_DEBUG("Stop dev_id=%" PRIu8, dev_id);
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_RET(dev_id);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_stop);
> > >  +
> > >  +	if (dev->data->dev_started == 0) {
> > >  +		EDEV_LOG_ERR("Device with dev_id=%" PRIu8 " already
> > >  stopped",
> > >  +			dev_id);
> > >  +		return;
> > >  +	}
> > >  +
> > >  +	dev->data->dev_started = 0;
> > >  +	(*dev->dev_ops->dev_stop)(dev);
> > >  +}
> > >  +
> > >  +int
> > >  +rte_event_dev_close(uint8_t dev_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -
> > >  ENOTSUP);
> > >  +
> > >  +	/* Device must be stopped before it can be closed */
> > >  +	if (dev->data->dev_started == 1) {
> > >  +		EDEV_LOG_ERR("Device %u must be stopped before closing",
> > >  +				dev_id);
> > >  +		return -EBUSY;
> > >  +	}
> > >  +
> > >  +	return (*dev->dev_ops->dev_close)(dev);
> > >  +}
> > >  +
> > >  +static inline int
> > >  +rte_eventdev_data_alloc(uint8_t dev_id, struct rte_eventdev_data **data,
> > >  +		int socket_id)
> > >  +{
> > >  +	char mz_name[RTE_EVENTDEV_NAME_MAX_LEN];
> > >  +	const struct rte_memzone *mz;
> > >  +	int n;
> > >  +
> > >  +	/* Generate memzone name */
> > >  +	n = snprintf(mz_name, sizeof(mz_name), "rte_eventdev_data_%u",
> > >  dev_id);
> > >  +	if (n >= (int)sizeof(mz_name))
> > >  +		return -EINVAL;
> > >  +
> > >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> > >  +		mz = rte_memzone_reserve(mz_name,
> > >  +				sizeof(struct rte_eventdev_data),
> > >  +				socket_id, 0);
> > >  +	} else
> > >  +		mz = rte_memzone_lookup(mz_name);
> > >  +
> > >  +	if (mz == NULL)
> > >  +		return -ENOMEM;
> > >  +
> > >  +	*data = mz->addr;
> > >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> > >  +		memset(*data, 0, sizeof(struct rte_eventdev_data));
> > >  +
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +static uint8_t
> > >  +rte_eventdev_find_free_device_index(void)
> > >  +{
> > >  +	uint8_t dev_id;
> > >  +
> > >  +	for (dev_id = 0; dev_id < RTE_EVENT_MAX_DEVS; dev_id++) {
> > >  +		if (rte_eventdevs[dev_id].attached ==
> > >  +				RTE_EVENTDEV_DETACHED)
> > >  +			return dev_id;
> > >  +	}
> > >  +	return RTE_EVENT_MAX_DEVS;
> > >  +}
> > >  +
> > >  +struct rte_eventdev *
> > >  +rte_eventdev_pmd_allocate(const char *name, int socket_id)
> > >  +{
> > >  +	struct rte_eventdev *eventdev;
> > >  +	uint8_t dev_id;
> > >  +
> > >  +	if (rte_eventdev_pmd_get_named_dev(name) != NULL) {
> > >  +		EDEV_LOG_ERR("Event device with name %s already "
> > >  +				"allocated!", name);
> > >  +		return NULL;
> > >  +	}
> > >  +
> > >  +	dev_id = rte_eventdev_find_free_device_index();
> > >  +	if (dev_id == RTE_EVENT_MAX_DEVS) {
> > >  +		EDEV_LOG_ERR("Reached maximum number of event
> > >  devices");
> > >  +		return NULL;
> > >  +	}
> > >  +
> > >  +	eventdev = &rte_eventdevs[dev_id];
> > >  +
> > >  +	if (eventdev->data == NULL) {
> > >  +		struct rte_eventdev_data *eventdev_data = NULL;
> > >  +
> > >  +		int retval = rte_eventdev_data_alloc(dev_id, &eventdev_data,
> > >  +				socket_id);
> > >  +
> > >  +		if (retval < 0 || eventdev_data == NULL)
> > >  +			return NULL;
> > >  +
> > >  +		eventdev->data = eventdev_data;
> > >  +
> > >  +		snprintf(eventdev->data->name,
> > >  RTE_EVENTDEV_NAME_MAX_LEN,
> > >  +				"%s", name);
> > >  +
> > >  +		eventdev->data->dev_id = dev_id;
> > >  +		eventdev->data->socket_id = socket_id;
> > >  +		eventdev->data->dev_started = 0;
> > >  +
> > >  +		eventdev->attached = RTE_EVENTDEV_ATTACHED;
> > >  +
> > >  +		eventdev_globals.nb_devs++;
> > >  +	}
> > >  +
> > >  +	return eventdev;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_eventdev_pmd_release(struct rte_eventdev *eventdev)
> > >  +{
> > >  +	int ret;
> > >  +
> > >  +	if (eventdev == NULL)
> > >  +		return -EINVAL;
> > >  +
> > >  +	ret = rte_event_dev_close(eventdev->data->dev_id);
> > >  +	if (ret < 0)
> > >  +		return ret;
> > >  +
> > >  +	eventdev->attached = RTE_EVENTDEV_DETACHED;
> > >  +	eventdev_globals.nb_devs--;
> > >  +	eventdev->data = NULL;
> > >  +
> > >  +	return 0;
> > >  +}
> > >  +
> > >  +struct rte_eventdev *
> > >  +rte_eventdev_pmd_vdev_init(const char *name, size_t dev_private_size,
> > >  +		int socket_id)
> > >  +{
> > >  +	struct rte_eventdev *eventdev;
> > >  +
> > >  +	/* Allocate device structure */
> > >  +	eventdev = rte_eventdev_pmd_allocate(name, socket_id);
> > >  +	if (eventdev == NULL)
> > >  +		return NULL;
> > >  +
> > >  +	/* Allocate private device structure */
> > >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> > >  +		eventdev->data->dev_private =
> > >  +				rte_zmalloc_socket("eventdev device private",
> > >  +						dev_private_size,
> > >  +						RTE_CACHE_LINE_SIZE,
> > >  +						socket_id);
> > >  +
> > >  +		if (eventdev->data->dev_private == NULL)
> > >  +			rte_panic("Cannot allocate memzone for private
> > >  device"
> > >  +					" data");
> > >  +	}
> > >  +
> > >  +	return eventdev;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_eventdev_pmd_pci_probe(struct rte_pci_driver *pci_drv,
> > >  +			struct rte_pci_device *pci_dev)
> > >  +{
> > >  +	struct rte_eventdev_driver *eventdrv;
> > >  +	struct rte_eventdev *eventdev;
> > >  +
> > >  +	char eventdev_name[RTE_EVENTDEV_NAME_MAX_LEN];
> > >  +
> > >  +	int retval;
> > >  +
> > >  +	eventdrv = (struct rte_eventdev_driver *)pci_drv;
> > >  +	if (eventdrv == NULL)
> > >  +		return -ENODEV;
> > >  +
> > >  +	rte_eal_pci_device_name(&pci_dev->addr, eventdev_name,
> > >  +			sizeof(eventdev_name));
> > >  +
> > >  +	eventdev = rte_eventdev_pmd_allocate(eventdev_name,
> > >  +			 pci_dev->device.numa_node);
> > >  +	if (eventdev == NULL)
> > >  +		return -ENOMEM;
> > >  +
> > >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> > >  +		eventdev->data->dev_private =
> > >  +				rte_zmalloc_socket(
> > >  +						"eventdev private structure",
> > >  +						eventdrv->dev_private_size,
> > >  +						RTE_CACHE_LINE_SIZE,
> > >  +						rte_socket_id());
> > >  +
> > >  +		if (eventdev->data->dev_private == NULL)
> > >  +			rte_panic("Cannot allocate memzone for private "
> > >  +					"device data");
> > >  +	}
> > >  +
> > >  +	eventdev->pci_dev = pci_dev;
> > >  +	eventdev->driver = eventdrv;
> > >  +
> > >  +	/* Invoke PMD device initialization function */
> > >  +	retval = (*eventdrv->eventdev_init)(eventdev);
> > >  +	if (retval == 0)
> > >  +		return 0;
> > >  +
> > >  +	EDEV_LOG_ERR("driver %s: event_dev_init(vendor_id=0x%x
> > >  device_id=0x%x)"
> > >  +			" failed", pci_drv->driver.name,
> > >  +			(unsigned int) pci_dev->id.vendor_id,
> > >  +			(unsigned int) pci_dev->id.device_id);
> > >  +
> > >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> > >  +		rte_free(eventdev->data->dev_private);
> > >  +
> > >  +	eventdev->attached = RTE_EVENTDEV_DETACHED;
> > >  +	eventdev_globals.nb_devs--;
> > >  +
> > >  +	return -ENXIO;
> > >  +}
> > >  +
> > >  +int
> > >  +rte_eventdev_pmd_pci_remove(struct rte_pci_device *pci_dev)
> > >  +{
> > >  +	const struct rte_eventdev_driver *eventdrv;
> > >  +	struct rte_eventdev *eventdev;
> > >  +	char eventdev_name[RTE_EVENTDEV_NAME_MAX_LEN];
> > >  +	int ret;
> > >  +
> > >  +	if (pci_dev == NULL)
> > >  +		return -EINVAL;
> > >  +
> > >  +	rte_eal_pci_device_name(&pci_dev->addr, eventdev_name,
> > >  +			sizeof(eventdev_name));
> > >  +
> > >  +	eventdev = rte_eventdev_pmd_get_named_dev(eventdev_name);
> > >  +	if (eventdev == NULL)
> > >  +		return -ENODEV;
> > >  +
> > >  +	eventdrv = (const struct rte_eventdev_driver *)pci_dev->driver;
> > >  +	if (eventdrv == NULL)
> > >  +		return -ENODEV;
> > >  +
> > >  +	/* Invoke PMD device uninit function */
> > >  +	if (*eventdrv->eventdev_uninit) {
> > >  +		ret = (*eventdrv->eventdev_uninit)(eventdev);
> > >  +		if (ret)
> > >  +			return ret;
> > >  +	}
> > >  +
> > >  +	/* Free event device */
> > >  +	rte_eventdev_pmd_release(eventdev);
> > >  +
> > >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> > >  +		rte_free(eventdev->data->dev_private);
> > >  +
> > >  +	eventdev->pci_dev = NULL;
> > >  +	eventdev->driver = NULL;
> > >  +
> > >  +	return 0;
> > >  +}
> > >  diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h
> > >  b/lib/librte_eventdev/rte_eventdev_pmd.h
> > >  new file mode 100644
> > >  index 0000000..e9d9b83
> > >  --- /dev/null
> > >  +++ b/lib/librte_eventdev/rte_eventdev_pmd.h
> > >  @@ -0,0 +1,504 @@
> > >  +/*
> > >  + *
> > >  + *   Copyright(c) 2016 Cavium networks. All rights reserved.
> > >  + *
> > >  + *   Redistribution and use in source and binary forms, with or without
> > >  + *   modification, are permitted provided that the following conditions
> > >  + *   are met:
> > >  + *
> > >  + *     * Redistributions of source code must retain the above copyright
> > >  + *       notice, this list of conditions and the following disclaimer.
> > >  + *     * Redistributions in binary form must reproduce the above copyright
> > >  + *       notice, this list of conditions and the following disclaimer in
> > >  + *       the documentation and/or other materials provided with the
> > >  + *       distribution.
> > >  + *     * Neither the name of Cavium networks nor the names of its
> > >  + *       contributors may be used to endorse or promote products derived
> > >  + *       from this software without specific prior written permission.
> > >  + *
> > >  + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > >  CONTRIBUTORS
> > >  + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> > >  NOT
> > >  + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > >  FITNESS FOR
> > >  + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > >  COPYRIGHT
> > >  + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > >  INCIDENTAL,
> > >  + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> > >  NOT
> > >  + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> > >  OF USE,
> > >  + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> > >  AND ON ANY
> > >  + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > >  TORT
> > >  + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> > >  THE USE
> > >  + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > >  DAMAGE.
> > >  + */
> > >  +
> > >  +#ifndef _RTE_EVENTDEV_PMD_H_
> > >  +#define _RTE_EVENTDEV_PMD_H_
> > >  +
> > >  +/** @file
> > >  + * RTE Event PMD APIs
> > >  + *
> > >  + * @note
> > >  + * These API are from event PMD only and user applications should not call
> > >  + * them directly.
> > >  + */
> > >  +
> > >  +#ifdef __cplusplus
> > >  +extern "C" {
> > >  +#endif
> > >  +
> > >  +#include <string.h>
> > >  +
> > >  +#include <rte_dev.h>
> > >  +#include <rte_pci.h>
> > >  +#include <rte_malloc.h>
> > >  +#include <rte_log.h>
> > >  +#include <rte_common.h>
> > >  +
> > >  +#include "rte_eventdev.h"
> > >  +
> > >  +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> > >  +#define RTE_PMD_DEBUG_TRACE(...) \
> > >  +	rte_pmd_debug_trace(__func__, __VA_ARGS__)
> > >  +#else
> > >  +#define RTE_PMD_DEBUG_TRACE(...)
> > >  +#endif
> > >  +
> > >  +/* Logging Macros */
> > >  +#define EDEV_LOG_ERR(fmt, args...) \
> > >  +	RTE_LOG(ERR, EVENTDEV, "%s() line %u: " fmt "\n",  \
> > >  +			__func__, __LINE__, ## args)
> > >  +
> > >  +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> > >  +#define EDEV_LOG_DEBUG(fmt, args...) \
> > >  +	RTE_LOG(DEBUG, EVENTDEV, "%s() line %u: " fmt "\n",  \
> > >  +			__func__, __LINE__, ## args)
> > >  +#else
> > >  +#define EDEV_LOG_DEBUG(fmt, args...) (void)0
> > >  +#endif
> > >  +
> > >  +/* Macros to check for valid device */
> > >  +#define RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, retval) do { \
> > >  +	if (!rte_eventdev_pmd_is_valid_dev((dev_id))) { \
> > >  +		EDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
> > >  +		return retval; \
> > >  +	} \
> > >  +} while (0)
> > >  +
> > >  +#define RTE_EVENTDEV_VALID_DEVID_OR_RET(dev_id) do { \
> > >  +	if (!rte_eventdev_pmd_is_valid_dev((dev_id))) { \
> > >  +		EDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
> > >  +		return; \
> > >  +	} \
> > >  +} while (0)
> > >  +
> > >  +#define RTE_EVENTDEV_DETACHED  (0)
> > >  +#define RTE_EVENTDEV_ATTACHED  (1)
> > >  +
> > >  +/**
> > >  + * Initialisation function of a event driver invoked for each matching
> > >  + * event PCI device detected during the PCI probing phase.
> > >  + *
> > >  + * @param dev
> > >  + *   The dev pointer is the address of the *rte_eventdev* structure associated
> > >  + *   with the matching device and which has been [automatically] allocated in
> > >  + *   the *rte_event_devices* array.
> > >  + *
> > >  + * @return
> > >  + *   - 0: Success, the device is properly initialised by the driver.
> > >  + *        In particular, the driver MUST have set up the *dev_ops* pointer
> > >  + *        of the *dev* structure.
> > >  + *   - <0: Error code of the device initialisation failure.
> > >  + */
> > >  +typedef int (*eventdev_init_t)(struct rte_eventdev *dev);
> > >  +
> > >  +/**
> > >  + * Finalisation function of a driver invoked for each matching
> > >  + * PCI device detected during the PCI closing phase.
> > >  + *
> > >  + * @param dev
> > >  + *   The dev pointer is the address of the *rte_eventdev* structure associated
> > >  + *   with the matching device and which	has been [automatically] allocated in
> > >  + *   the *rte_event_devices* array.
> > >  + *
> > >  + * @return
> > >  + *   - 0: Success, the device is properly finalised by the driver.
> > >  + *        In particular, the driver MUST free the *dev_ops* pointer
> > >  + *        of the *dev* structure.
> > >  + *   - <0: Error code of the device initialisation failure.
> > >  + */
> > >  +typedef int (*eventdev_uninit_t)(struct rte_eventdev *dev);
> > >  +
> > >  +/**
> > >  + * The structure associated with a PMD driver.
> > >  + *
> > >  + * Each driver acts as a PCI driver and is represented by a generic
> > >  + * *event_driver* structure that holds:
> > >  + *
> > >  + * - An *rte_pci_driver* structure (which must be the first field).
> > >  + *
> > >  + * - The *eventdev_init* function invoked for each matching PCI device.
> > >  + *
> > >  + * - The size of the private data to allocate for each matching device.
> > >  + */
> > >  +struct rte_eventdev_driver {
> > >  +	struct rte_pci_driver pci_drv;	/**< The PMD is also a PCI driver. */
> > >  +	unsigned int dev_private_size;	/**< Size of device private data. */
> > >  +
> > >  +	eventdev_init_t eventdev_init;	/**< Device init function. */
> > >  +	eventdev_uninit_t eventdev_uninit; /**< Device uninit function. */
> > >  +};
> > >  +
> > >  +/** Global structure used for maintaining state of allocated event devices */
> > >  +struct rte_eventdev_global {
> > >  +	uint8_t nb_devs;	/**< Number of devices found */
> > >  +	uint8_t max_devs;	/**< Max number of devices */
> > >  +};
> > >  +
> > >  +extern struct rte_eventdev_global *rte_eventdev_globals;
> > >  +/** Pointer to global event devices data structure. */
> > >  +extern struct rte_eventdev *rte_eventdevs;
> > >  +/** The pool of rte_eventdev structures. */
> > >  +
> > >  +/**
> > >  + * Get the rte_eventdev structure device pointer for the named device.
> > >  + *
> > >  + * @param name
> > >  + *   device name to select the device structure.
> > >  + *
> > >  + * @return
> > >  + *   - The rte_eventdev structure pointer for the given device ID.
> > >  + */
> > >  +static inline struct rte_eventdev *
> > >  +rte_eventdev_pmd_get_named_dev(const char *name)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +	unsigned int i;
> > >  +
> > >  +	if (name == NULL)
> > >  +		return NULL;
> > >  +
> > >  +	for (i = 0, dev = &rte_eventdevs[i];
> > >  +			i < rte_eventdev_globals->max_devs; i++) {
> > >  +		if ((dev->attached == RTE_EVENTDEV_ATTACHED) &&
> > >  +				(strcmp(dev->data->name, name) == 0))
> > >  +			return dev;
> > >  +	}
> > >  +
> > >  +	return NULL;
> > >  +}
> > >  +
> > >  +/**
> > >  + * Validate if the event device index is valid attached event device.
> > >  + *
> > >  + * @param dev_id
> > >  + *   Event device index.
> > >  + *
> > >  + * @return
> > >  + *   - If the device index is valid (1) or not (0).
> > >  + */
> > >  +static inline unsigned
> > >  +rte_eventdev_pmd_is_valid_dev(uint8_t dev_id)
> > >  +{
> > >  +	struct rte_eventdev *dev;
> > >  +
> > >  +	if (dev_id >= rte_eventdev_globals->nb_devs)
> > >  +		return 0;
> > >  +
> > >  +	dev = &rte_eventdevs[dev_id];
> > >  +	if (dev->attached != RTE_EVENTDEV_ATTACHED)
> > >  +		return 0;
> > >  +	else
> > >  +		return 1;
> > >  +}
> > >  +
> > >  +/**
> > >  + * Definitions of all functions exported by a driver through the
> > >  + * the generic structure of type *event_dev_ops* supplied in the
> > >  + * *rte_eventdev* structure associated with a device.
> > >  + */
> > >  +
> > >  +/**
> > >  + * Get device information of a device.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + * @param dev_info
> > >  + *   Event device information structure
> > >  + *
> > >  + * @return
> > >  + *   Returns 0 on success
> > >  + */
> > >  +typedef void (*eventdev_info_get_t)(struct rte_eventdev *dev,
> > >  +		struct rte_event_dev_info *dev_info);
> > >  +
> > >  +/**
> > >  + * Configure a device.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + *
> > >  + * @return
> > >  + *   Returns 0 on success
> > >  + */
> > >  +typedef int (*eventdev_configure_t)(struct rte_eventdev *dev);
> > >  +
> > >  +/**
> > >  + * Start a configured device.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + *
> > >  + * @return
> > >  + *   Returns 0 on success
> > >  + */
> > >  +typedef int (*eventdev_start_t)(struct rte_eventdev *dev);
> > >  +
> > >  +/**
> > >  + * Stop a configured device.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + */
> > >  +typedef void (*eventdev_stop_t)(struct rte_eventdev *dev);
> > >  +
> > >  +/**
> > >  + * Close a configured device.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + *
> > >  + * @return
> > >  + * - 0 on success
> > >  + * - (-EAGAIN) if can't close as device is busy
> > >  + */
> > >  +typedef int (*eventdev_close_t)(struct rte_eventdev *dev);
> > >  +
> > >  +/**
> > >  + * Retrieve the default event queue configuration.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + * @param queue_id
> > >  + *   Event queue index
> > >  + * @param[out] queue_conf
> > >  + *   Event queue configuration structure
> > >  + *
> > >  + */
> > >  +typedef void (*eventdev_queue_default_conf_get_t)(struct rte_eventdev
> > >  *dev,
> > >  +		uint8_t queue_id, struct rte_event_queue_conf *queue_conf);
> > >  +
> > >  +/**
> > >  + * Setup an event queue.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + * @param queue_id
> > >  + *   Event queue index
> > >  + * @param queue_conf
> > >  + *   Event queue configuration structure
> > >  + *
> > >  + * @return
> > >  + *   Returns 0 on success.
> > >  + */
> > >  +typedef int (*eventdev_queue_setup_t)(struct rte_eventdev *dev,
> > >  +		uint8_t queue_id, struct rte_event_queue_conf *queue_conf);
> > >  +
> > >  +/**
> > >  + * Release memory resources allocated by given event queue.
> > >  + *
> > >  + * @param queue
> > >  + *   Event queue pointer
> > >  + *
> > >  + */
> > >  +typedef void (*eventdev_queue_release_t)(void *queue);
> > >  +
> > >  +/**
> > >  + * Retrieve the default event port configuration.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + * @param port_id
> > >  + *   Event port index
> > >  + * @param[out] port_conf
> > >  + *   Event port configuration structure
> > >  + *
> > >  + */
> > >  +typedef void (*eventdev_port_default_conf_get_t)(struct rte_eventdev *dev,
> > >  +		uint8_t port_id, struct rte_event_port_conf *port_conf);
> > >  +
> > >  +/**
> > >  + * Setup an event port.
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + * @param port_id
> > >  + *   Event port index
> > >  + * @param port_conf
> > >  + *   Event port configuration structure
> > >  + *
> > >  + * @return
> > >  + *   Returns 0 on success.
> > >  + */
> > >  +typedef int (*eventdev_port_setup_t)(struct rte_eventdev *dev,
> > >  +		uint8_t port_id, struct rte_event_port_conf *port_conf);
> > >  +
> > >  +/**
> > >  + * Release memory resources allocated by given event port.
> > >  + *
> > >  + * @param port
> > >  + *   Event port pointer
> > >  + *
> > >  + */
> > >  +typedef void (*eventdev_port_release_t)(void *port);
> > >  +
> > >  +/**
> > >  + * Link multiple source event queues to destination event port.
> > >  + *
> > >  + * @param port
> > >  + *   Event port pointer
> > >  + * @param link
> > >  + *   An array of *nb_links* pointers to *rte_event_queue_link* structure
> > >  + * @param nb_links
> > >  + *   The number of links to establish
> > >  + *
> > >  + * @return
> > >  + *   Returns 0 on success.
> > >  + *
> > >  + */
> > >  +typedef int (*eventdev_port_link_t)(void *port,
> > >  +		struct rte_event_queue_link link[], uint16_t nb_links);
> > >  +
> > >  +/**
> > >  + * Unlink multiple source event queues from destination event port.
> > >  + *
> > >  + * @param port
> > >  + *   Event port pointer
> > >  + * @param queues
> > >  + *   An array of *nb_unlinks* event queues to be unlinked from the event port.
> > >  + * @param nb_unlinks
> > >  + *   The number of unlinks to establish
> > >  + *
> > >  + * @return
> > >  + *   Returns 0 on success.
> > >  + *
> > >  + */
> > >  +typedef int (*eventdev_port_unlink_t)(void *port,
> > >  +		uint8_t queues[], uint16_t nb_unlinks);
> > >  +
> > >  +/**
> > >  + * Converts nanoseconds to *wait* value for rte_event_dequeue()
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + * @param ns
> > >  + *   Wait time in nanosecond
> > >  + * @param[out] wait_ticks
> > >  + *   Value for the *wait* parameter in rte_event_dequeue() function
> > >  + *
> > >  + */
> > >  +typedef void (*eventdev_dequeue_wait_time_t)(struct rte_eventdev *dev,
> > >  +		uint64_t ns, uint64_t *wait_ticks);
> > >  +
> > >  +/**
> > >  + * Dump internal information
> > >  + *
> > >  + * @param dev
> > >  + *   Event device pointer
> > >  + * @param f
> > >  + *   A pointer to a file for output
> > >  + *
> > >  + */
> > >  +typedef void (*eventdev_dump_t)(struct rte_eventdev *dev, FILE *f);
> > >  +
> > >  +/** Event device operations function pointer table */
> > >  +struct rte_eventdev_ops {
> > >  +	eventdev_info_get_t dev_infos_get;	/**< Get device info. */
> > >  +	eventdev_configure_t dev_configure;	/**< Configure device. */
> > >  +	eventdev_start_t dev_start;		/**< Start device. */
> > >  +	eventdev_stop_t dev_stop;		/**< Stop device. */
> > >  +	eventdev_close_t dev_close;		/**< Close device. */
> > >  +
> > >  +	eventdev_queue_default_conf_get_t queue_def_conf;
> > >  +	/**< Get default queue configuration. */
> > >  +	eventdev_queue_setup_t queue_setup;
> > >  +	/**< Set up an event queue. */
> > >  +	eventdev_queue_release_t queue_release;
> > >  +	/**< Release an event queue. */
> > >  +
> > >  +	eventdev_port_default_conf_get_t port_def_conf;
> > >  +	/**< Get default port configuration. */
> > >  +	eventdev_port_setup_t port_setup;
> > >  +	/**< Set up an event port. */
> > >  +	eventdev_port_release_t port_release;
> > >  +	/**< Release an event port. */
> > >  +
> > >  +	eventdev_port_link_t port_link;
> > >  +	/**< Link event queues to an event port. */
> > >  +	eventdev_port_unlink_t port_unlink;
> > >  +	/**< Unlink event queues from an event port. */
> > >  +	eventdev_dequeue_wait_time_t wait_time;
> > >  +	/**< Converts nanoseconds to *wait* value for rte_event_dequeue()
> > >  */
> > >  +	eventdev_dump_t dump;
> > >  +	/* Dump internal information */
> > >  +};
> > >  +
> > >  +/**
> > >  + * Allocates a new eventdev slot for an event device and returns the pointer
> > >  + * to that slot for the driver to use.
> > >  + *
> > >  + * @param name
> > >  + *   Unique identifier name for each device
> > >  + * @param socket_id
> > >  + *   Socket to allocate resources on.
> > >  + * @return
> > >  + *   - Slot in the rte_dev_devices array for a new device;
> > >  + */
> > >  +struct rte_eventdev *
> > >  +rte_eventdev_pmd_allocate(const char *name, int socket_id);
> > >  +
> > >  +/**
> > >  + * Release the specified eventdev device.
> > >  + *
> > >  + * @param eventdev
> > >  + * The *eventdev* pointer is the address of the *rte_eventdev* structure.
> > >  + * @return
> > >  + *   - 0 on success, negative on error
> > >  + */
> > >  +int
> > >  +rte_eventdev_pmd_release(struct rte_eventdev *eventdev);
> > >  +
> > >  +/**
> > >  + * Creates a new virtual event device and returns the pointer to that device.
> > >  + *
> > >  + * @param name
> > >  + *   PMD type name
> > >  + * @param dev_private_size
> > >  + *   Size of event PMDs private data
> > >  + * @param socket_id
> > >  + *   Socket to allocate resources on.
> > >  + *
> > >  + * @return
> > >  + *   - Eventdev pointer if device is successfully created.
> > >  + *   - NULL if device cannot be created.
> > >  + */
> > >  +struct rte_eventdev *
> > >  +rte_eventdev_pmd_vdev_init(const char *name, size_t dev_private_size,
> > >  +		int socket_id);
> > >  +
> > >  +
> > >  +/**
> > >  + * Wrapper for use by pci drivers as a .probe function to attach to a event
> > >  + * interface.
> > >  + */
> > >  +int rte_eventdev_pmd_pci_probe(struct rte_pci_driver *pci_drv,
> > >  +			    struct rte_pci_device *pci_dev);
> > >  +
> > >  +/**
> > >  + * Wrapper for use by pci drivers as a .remove function to detach a event
> > >  + * interface.
> > >  + */
> > >  +int rte_eventdev_pmd_pci_remove(struct rte_pci_device *pci_dev);
> > >  +
> > >  +#ifdef __cplusplus
> > >  +}
> > >  +#endif
> > >  +
> > >  +#endif /* _RTE_EVENTDEV_PMD_H_ */
> > >  diff --git a/lib/librte_eventdev/rte_eventdev_version.map
> > >  b/lib/librte_eventdev/rte_eventdev_version.map
> > >  new file mode 100644
> > >  index 0000000..ef40aae
> > >  --- /dev/null
> > >  +++ b/lib/librte_eventdev/rte_eventdev_version.map
> > >  @@ -0,0 +1,39 @@
> > >  +DPDK_17.02 {
> > >  +	global:
> > >  +
> > >  +	rte_eventdevs;
> > >  +
> > >  +	rte_event_dev_count;
> > >  +	rte_event_dev_get_dev_id;
> > >  +	rte_event_dev_socket_id;
> > >  +	rte_event_dev_info_get;
> > >  +	rte_event_dev_configure;
> > >  +	rte_event_dev_start;
> > >  +	rte_event_dev_stop;
> > >  +	rte_event_dev_close;
> > >  +	rte_event_dev_dump;
> > >  +
> > >  +	rte_event_port_default_conf_get;
> > >  +	rte_event_port_setup;
> > >  +	rte_event_port_dequeue_depth;
> > >  +	rte_event_port_enqueue_depth;
> > >  +	rte_event_port_count;
> > >  +	rte_event_port_link;
> > >  +	rte_event_port_unlink;
> > >  +	rte_event_port_links_get;
> > >  +
> > >  +	rte_event_queue_default_conf_get
> > >  +	rte_event_queue_setup;
> > >  +	rte_event_queue_count;
> > >  +	rte_event_queue_priority;
> > >  +
> > >  +	rte_event_dequeue_wait_time;
> > >  +
> > >  +	rte_eventdev_pmd_allocate;
> > >  +	rte_eventdev_pmd_release;
> > >  +	rte_eventdev_pmd_vdev_init;
> > >  +	rte_eventdev_pmd_pci_probe;
> > >  +	rte_eventdev_pmd_pci_remove;
> > >  +
> > >  +	local: *;
> > >  +};
> > >  diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> > >  index f75f0e2..716725a 100644
> > >  --- a/mk/rte.app.mk
> > >  +++ b/mk/rte.app.mk
> > >  @@ -93,6 +93,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -
> > >  lrte_mbuf
> > >   _LDLIBS-$(CONFIG_RTE_LIBRTE_NET)            += -lrte_net
> > >   _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lrte_ethdev
> > >   _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
> > >  +_LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
> > >   _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
> > >   _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
> > >   _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
> > >  --
> > >  2.5.5
> > 

^ permalink raw reply

* Re: [PATCH 2/4] eventdev: implement the northbound APIs
From: Jerin Jacob @ 2016-11-21 19:13 UTC (permalink / raw)
  To: Eads, Gage
  Cc: dev@dpdk.org, Richardson, Bruce, Van Haaren, Harry,
	hemant.agrawal@nxp.com
In-Reply-To: <9184057F7FC11744A2107296B6B8EB1E01E31739@FMSMSX108.amr.corp.intel.com>

On Mon, Nov 21, 2016 at 05:45:51PM +0000, Eads, Gage wrote:
> Hi Jerin,
> 
> I did a quick review and overall this implementation looks good. I noticed just one issue in rte_event_queue_setup(): the check of nb_atomic_order_sequences is being applied to atomic-type queues, but that field applies to ordered-type queues.

Thanks Gage. I will fix that in v2.

> 
> One open issue I noticed is the "typical workflow" description starting in rte_eventdev.h:204 conflicts with the centralized software PMD that Harry posted last week. Specifically, that PMD expects a single core to call the schedule function. We could extend the documentation to account for this alternative style of scheduler invocation, or discuss ways to make the software PMD work with the documented workflow. I prefer the former, but either way I think we ought to expose the scheduler's expected usage to the user -- perhaps through an RTE_EVENT_DEV_CAP flag?

I prefer former too, you can propose the documentation change required for software PMD.

On same note, If software PMD based workflow need  a separate core(s) for
schedule function then, Can we hide that from API specification and pass an
argument to SW pmd to define the scheduling core(s)?

Something like --vdev=eventsw0,schedule_cmask=0x2

> 
> Thanks,
> Gage
> 
> >  -----Original Message-----
> >  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> >  Sent: Thursday, November 17, 2016 11:45 PM
> >  To: dev@dpdk.org
> >  Cc: Richardson, Bruce <bruce.richardson@intel.com>; Van Haaren, Harry
> >  <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com; Eads, Gage
> >  <gage.eads@intel.com>; Jerin Jacob <jerin.jacob@caviumnetworks.com>
> >  Subject: [dpdk-dev] [PATCH 2/4] eventdev: implement the northbound APIs
> >  
> >  This patch set defines the southbound driver interface
> >  and implements the common code required for northbound
> >  eventdev API interface.
> >  
> >  Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> >  ---
> >   config/common_base                           |    6 +
> >   lib/Makefile                                 |    1 +
> >   lib/librte_eal/common/include/rte_log.h      |    1 +
> >   lib/librte_eventdev/Makefile                 |   57 ++
> >   lib/librte_eventdev/rte_eventdev.c           | 1211
> >  ++++++++++++++++++++++++++
> >   lib/librte_eventdev/rte_eventdev_pmd.h       |  504 +++++++++++
> >   lib/librte_eventdev/rte_eventdev_version.map |   39 +
> >   mk/rte.app.mk                                |    1 +
> >   8 files changed, 1820 insertions(+)
> >   create mode 100644 lib/librte_eventdev/Makefile
> >   create mode 100644 lib/librte_eventdev/rte_eventdev.c
> >   create mode 100644 lib/librte_eventdev/rte_eventdev_pmd.h
> >   create mode 100644 lib/librte_eventdev/rte_eventdev_version.map
> >  
> >  diff --git a/config/common_base b/config/common_base
> >  index 4bff83a..7a8814e 100644
> >  --- a/config/common_base
> >  +++ b/config/common_base
> >  @@ -411,6 +411,12 @@ CONFIG_RTE_LIBRTE_PMD_ZUC_DEBUG=n
> >   CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=y
> >  
> >   #
> >  +# Compile generic event device library
> >  +#
> >  +CONFIG_RTE_LIBRTE_EVENTDEV=y
> >  +CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
> >  +CONFIG_RTE_EVENT_MAX_DEVS=16
> >  +CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
> >   # Compile librte_ring
> >   #
> >   CONFIG_RTE_LIBRTE_RING=y
> >  diff --git a/lib/Makefile b/lib/Makefile
> >  index 990f23a..1a067bf 100644
> >  --- a/lib/Makefile
> >  +++ b/lib/Makefile
> >  @@ -41,6 +41,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
> >   DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
> >   DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
> >   DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
> >  +DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
> >   DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
> >   DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
> >   DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
> >  diff --git a/lib/librte_eal/common/include/rte_log.h
> >  b/lib/librte_eal/common/include/rte_log.h
> >  index 29f7d19..9a07d92 100644
> >  --- a/lib/librte_eal/common/include/rte_log.h
> >  +++ b/lib/librte_eal/common/include/rte_log.h
> >  @@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
> >   #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
> >   #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
> >   #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to
> >  cryptodev. */
> >  +#define RTE_LOGTYPE_EVENTDEV 0x00040000 /**< Log related to eventdev.
> >  */
> >  
> >   /* these log types can be used in an application */
> >   #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
> >  diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
> >  new file mode 100644
> >  index 0000000..dac0663
> >  --- /dev/null
> >  +++ b/lib/librte_eventdev/Makefile
> >  @@ -0,0 +1,57 @@
> >  +#   BSD LICENSE
> >  +#
> >  +#   Copyright(c) 2016 Cavium networks. All rights reserved.
> >  +#
> >  +#   Redistribution and use in source and binary forms, with or without
> >  +#   modification, are permitted provided that the following conditions
> >  +#   are met:
> >  +#
> >  +#     * Redistributions of source code must retain the above copyright
> >  +#       notice, this list of conditions and the following disclaimer.
> >  +#     * Redistributions in binary form must reproduce the above copyright
> >  +#       notice, this list of conditions and the following disclaimer in
> >  +#       the documentation and/or other materials provided with the
> >  +#       distribution.
> >  +#     * Neither the name of Cavium networks nor the names of its
> >  +#       contributors may be used to endorse or promote products derived
> >  +#       from this software without specific prior written permission.
> >  +#
> >  +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> >  CONTRIBUTORS
> >  +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> >  NOT
> >  +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> >  FITNESS FOR
> >  +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> >  COPYRIGHT
> >  +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> >  INCIDENTAL,
> >  +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> >  NOT
> >  +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> >  OF USE,
> >  +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> >  ON ANY
> >  +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> >  TORT
> >  +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> >  THE USE
> >  +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> >  DAMAGE.
> >  +
> >  +include $(RTE_SDK)/mk/rte.vars.mk
> >  +
> >  +# library name
> >  +LIB = librte_eventdev.a
> >  +
> >  +# library version
> >  +LIBABIVER := 1
> >  +
> >  +# build flags
> >  +CFLAGS += -O3
> >  +CFLAGS += $(WERROR_FLAGS)
> >  +
> >  +# library source files
> >  +SRCS-y += rte_eventdev.c
> >  +
> >  +# export include files
> >  +SYMLINK-y-include += rte_eventdev.h
> >  +SYMLINK-y-include += rte_eventdev_pmd.h
> >  +
> >  +# versioning export map
> >  +EXPORT_MAP := rte_eventdev_version.map
> >  +
> >  +# library dependencies
> >  +DEPDIRS-y += lib/librte_eal
> >  +DEPDIRS-y += lib/librte_mbuf
> >  +
> >  +include $(RTE_SDK)/mk/rte.lib.mk
> >  diff --git a/lib/librte_eventdev/rte_eventdev.c
> >  b/lib/librte_eventdev/rte_eventdev.c
> >  new file mode 100644
> >  index 0000000..17ce5c3
> >  --- /dev/null
> >  +++ b/lib/librte_eventdev/rte_eventdev.c
> >  @@ -0,0 +1,1211 @@
> >  +/*
> >  + *   BSD LICENSE
> >  + *
> >  + *   Copyright(c) 2016 Cavium networks. All rights reserved.
> >  + *
> >  + *   Redistribution and use in source and binary forms, with or without
> >  + *   modification, are permitted provided that the following conditions
> >  + *   are met:
> >  + *
> >  + *     * Redistributions of source code must retain the above copyright
> >  + *       notice, this list of conditions and the following disclaimer.
> >  + *     * Redistributions in binary form must reproduce the above copyright
> >  + *       notice, this list of conditions and the following disclaimer in
> >  + *       the documentation and/or other materials provided with the
> >  + *       distribution.
> >  + *     * Neither the name of Cavium networks nor the names of its
> >  + *       contributors may be used to endorse or promote products derived
> >  + *       from this software without specific prior written permission.
> >  + *
> >  + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> >  CONTRIBUTORS
> >  + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> >  NOT
> >  + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> >  FITNESS FOR
> >  + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> >  COPYRIGHT
> >  + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> >  INCIDENTAL,
> >  + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> >  NOT
> >  + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> >  OF USE,
> >  + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> >  AND ON ANY
> >  + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> >  TORT
> >  + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> >  THE USE
> >  + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> >  DAMAGE.
> >  + */
> >  +
> >  +#include <ctype.h>
> >  +#include <stdio.h>
> >  +#include <stdlib.h>
> >  +#include <string.h>
> >  +#include <stdarg.h>
> >  +#include <errno.h>
> >  +#include <stdint.h>
> >  +#include <inttypes.h>
> >  +#include <sys/types.h>
> >  +#include <sys/queue.h>
> >  +
> >  +#include <rte_byteorder.h>
> >  +#include <rte_log.h>
> >  +#include <rte_debug.h>
> >  +#include <rte_dev.h>
> >  +#include <rte_pci.h>
> >  +#include <rte_memory.h>
> >  +#include <rte_memcpy.h>
> >  +#include <rte_memzone.h>
> >  +#include <rte_eal.h>
> >  +#include <rte_per_lcore.h>
> >  +#include <rte_lcore.h>
> >  +#include <rte_atomic.h>
> >  +#include <rte_branch_prediction.h>
> >  +#include <rte_common.h>
> >  +#include <rte_malloc.h>
> >  +#include <rte_errno.h>
> >  +
> >  +#include "rte_eventdev.h"
> >  +#include "rte_eventdev_pmd.h"
> >  +
> >  +struct rte_eventdev rte_event_devices[RTE_EVENT_MAX_DEVS];
> >  +
> >  +struct rte_eventdev *rte_eventdevs = &rte_event_devices[0];
> >  +
> >  +static struct rte_eventdev_global eventdev_globals = {
> >  +	.nb_devs		= 0
> >  +};
> >  +
> >  +struct rte_eventdev_global *rte_eventdev_globals = &eventdev_globals;
> >  +
> >  +/* Event dev north bound API implementation */
> >  +
> >  +uint8_t
> >  +rte_event_dev_count(void)
> >  +{
> >  +	return rte_eventdev_globals->nb_devs;
> >  +}
> >  +
> >  +int
> >  +rte_event_dev_get_dev_id(const char *name)
> >  +{
> >  +	int i;
> >  +
> >  +	if (!name)
> >  +		return -EINVAL;
> >  +
> >  +	for (i = 0; i < rte_eventdev_globals->nb_devs; i++)
> >  +		if ((strcmp(rte_event_devices[i].data->name, name)
> >  +				== 0) &&
> >  +				(rte_event_devices[i].attached ==
> >  +						RTE_EVENTDEV_ATTACHED))
> >  +			return i;
> >  +	return -ENODEV;
> >  +}
> >  +
> >  +int
> >  +rte_event_dev_socket_id(uint8_t dev_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +
> >  +	return dev->data->socket_id;
> >  +}
> >  +
> >  +int
> >  +rte_event_dev_info_get(uint8_t dev_id, struct rte_event_dev_info *dev_info)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +
> >  +	if (dev_info == NULL)
> >  +		return -EINVAL;
> >  +
> >  +	memset(dev_info, 0, sizeof(struct rte_event_dev_info));
> >  +
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
> >  ENOTSUP);
> >  +	(*dev->dev_ops->dev_infos_get)(dev, dev_info);
> >  +
> >  +	dev_info->pci_dev = dev->pci_dev;
> >  +	if (dev->driver)
> >  +		dev_info->driver_name = dev->driver->pci_drv.driver.name;
> >  +	return 0;
> >  +}
> >  +
> >  +static inline int
> >  +rte_event_dev_queue_config(struct rte_eventdev *dev, uint8_t nb_queues)
> >  +{
> >  +	uint8_t old_nb_queues = dev->data->nb_queues;
> >  +	void **queues;
> >  +	uint8_t *queues_prio;
> >  +	unsigned int i;
> >  +
> >  +	EDEV_LOG_DEBUG("Setup %d queues on device %u", nb_queues,
> >  +			 dev->data->dev_id);
> >  +
> >  +	/* First time configuration */
> >  +	if (dev->data->queues == NULL && nb_queues != 0) {
> >  +		dev->data->queues = rte_zmalloc_socket("eventdev->data-
> >  >queues",
> >  +				sizeof(dev->data->queues[0]) * nb_queues,
> >  +				RTE_CACHE_LINE_SIZE, dev->data-
> >  >socket_id);
> >  +		if (dev->data->queues == NULL) {
> >  +			dev->data->nb_queues = 0;
> >  +			EDEV_LOG_ERR("failed to get memory for queue meta
> >  data,"
> >  +					"nb_queues %u", nb_queues);
> >  +			return -(ENOMEM);
> >  +		}
> >  +		/* Allocate memory to store queue priority */
> >  +		dev->data->queues_prio = rte_zmalloc_socket(
> >  +				"eventdev->data->queues_prio",
> >  +				sizeof(dev->data->queues_prio[0]) *
> >  nb_queues,
> >  +				RTE_CACHE_LINE_SIZE, dev->data-
> >  >socket_id);
> >  +		if (dev->data->queues_prio == NULL) {
> >  +			dev->data->nb_queues = 0;
> >  +			EDEV_LOG_ERR("failed to get memory for queue
> >  priority,"
> >  +					"nb_queues %u", nb_queues);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +	} else if (dev->data->queues != NULL && nb_queues != 0) {/* re-config
> >  */
> >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >  >queue_release, -ENOTSUP);
> >  +
> >  +		queues = dev->data->queues;
> >  +		for (i = nb_queues; i < old_nb_queues; i++)
> >  +			(*dev->dev_ops->queue_release)(queues[i]);
> >  +
> >  +		queues = rte_realloc(queues, sizeof(queues[0]) * nb_queues,
> >  +				RTE_CACHE_LINE_SIZE);
> >  +		if (queues == NULL) {
> >  +			EDEV_LOG_ERR("failed to realloc queue meta data,"
> >  +						" nb_queues %u",
> >  nb_queues);
> >  +			return -(ENOMEM);
> >  +		}
> >  +		dev->data->queues = queues;
> >  +
> >  +		/* Re allocate memory to store queue priority */
> >  +		queues_prio = dev->data->queues_prio;
> >  +		queues_prio = rte_realloc(queues_prio,
> >  +				sizeof(queues_prio[0]) * nb_queues,
> >  +				RTE_CACHE_LINE_SIZE);
> >  +		if (queues_prio == NULL) {
> >  +			EDEV_LOG_ERR("failed to realloc queue priority,"
> >  +						" nb_queues %u",
> >  nb_queues);
> >  +			return -(ENOMEM);
> >  +		}
> >  +		dev->data->queues_prio = queues_prio;
> >  +
> >  +		if (nb_queues > old_nb_queues) {
> >  +			uint8_t new_qs = nb_queues - old_nb_queues;
> >  +
> >  +			memset(queues + old_nb_queues, 0,
> >  +				sizeof(queues[0]) * new_qs);
> >  +			memset(queues_prio + old_nb_queues, 0,
> >  +				sizeof(queues_prio[0]) * new_qs);
> >  +		}
> >  +	} else if (dev->data->queues != NULL && nb_queues == 0) {
> >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >  >queue_release, -ENOTSUP);
> >  +
> >  +		queues = dev->data->queues;
> >  +		for (i = nb_queues; i < old_nb_queues; i++)
> >  +			(*dev->dev_ops->queue_release)(queues[i]);
> >  +	}
> >  +
> >  +	dev->data->nb_queues = nb_queues;
> >  +	return 0;
> >  +}
> >  +
> >  +static inline int
> >  +rte_event_dev_port_config(struct rte_eventdev *dev, uint8_t nb_ports)
> >  +{
> >  +	uint8_t old_nb_ports = dev->data->nb_ports;
> >  +	void **ports;
> >  +	uint16_t *links_map;
> >  +	uint8_t *ports_dequeue_depth;
> >  +	uint8_t *ports_enqueue_depth;
> >  +	unsigned int i;
> >  +
> >  +	EDEV_LOG_DEBUG("Setup %d ports on device %u", nb_ports,
> >  +			 dev->data->dev_id);
> >  +
> >  +	/* First time configuration */
> >  +	if (dev->data->ports == NULL && nb_ports != 0) {
> >  +		dev->data->ports = rte_zmalloc_socket("eventdev->data-
> >  >ports",
> >  +				sizeof(dev->data->ports[0]) * nb_ports,
> >  +				RTE_CACHE_LINE_SIZE, dev->data-
> >  >socket_id);
> >  +		if (dev->data->ports == NULL) {
> >  +			dev->data->nb_ports = 0;
> >  +			EDEV_LOG_ERR("failed to get memory for port meta
> >  data,"
> >  +					"nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +		/* Allocate memory to store ports dequeue depth */
> >  +		dev->data->ports_dequeue_depth =
> >  +			rte_zmalloc_socket("eventdev-
> >  >ports_dequeue_depth",
> >  +			sizeof(dev->data->ports_dequeue_depth[0]) *
> >  nb_ports,
> >  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
> >  +		if (dev->data->ports_dequeue_depth == NULL) {
> >  +			dev->data->nb_ports = 0;
> >  +			EDEV_LOG_ERR("failed to get memory for port deq
> >  meta,"
> >  +					"nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +		/* Allocate memory to store ports enqueue depth */
> >  +		dev->data->ports_enqueue_depth =
> >  +			rte_zmalloc_socket("eventdev-
> >  >ports_enqueue_depth",
> >  +			sizeof(dev->data->ports_enqueue_depth[0]) *
> >  nb_ports,
> >  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
> >  +		if (dev->data->ports_enqueue_depth == NULL) {
> >  +			dev->data->nb_ports = 0;
> >  +			EDEV_LOG_ERR("failed to get memory for port enq
> >  meta,"
> >  +					"nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +		/* Allocate memory to store queue to port link connection */
> >  +		dev->data->links_map =
> >  +			rte_zmalloc_socket("eventdev->links_map",
> >  +			sizeof(dev->data->links_map[0]) * nb_ports *
> >  +			RTE_EVENT_MAX_QUEUES_PER_DEV,
> >  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
> >  +		if (dev->data->links_map == NULL) {
> >  +			dev->data->nb_ports = 0;
> >  +			EDEV_LOG_ERR("failed to get memory for port_map
> >  area,"
> >  +					"nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +	} else if (dev->data->ports != NULL && nb_ports != 0) {/* re-config */
> >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release,
> >  -ENOTSUP);
> >  +
> >  +		ports = dev->data->ports;
> >  +		ports_dequeue_depth = dev->data->ports_dequeue_depth;
> >  +		ports_enqueue_depth = dev->data->ports_enqueue_depth;
> >  +		links_map = dev->data->links_map;
> >  +
> >  +		for (i = nb_ports; i < old_nb_ports; i++)
> >  +			(*dev->dev_ops->port_release)(ports[i]);
> >  +
> >  +		/* Realloc memory for ports */
> >  +		ports = rte_realloc(ports, sizeof(ports[0]) * nb_ports,
> >  +				RTE_CACHE_LINE_SIZE);
> >  +		if (ports == NULL) {
> >  +			EDEV_LOG_ERR("failed to realloc port meta data,"
> >  +						" nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +		/* Realloc memory for ports_dequeue_depth */
> >  +		ports_dequeue_depth = rte_realloc(ports_dequeue_depth,
> >  +			sizeof(ports_dequeue_depth[0]) * nb_ports,
> >  +			RTE_CACHE_LINE_SIZE);
> >  +		if (ports_dequeue_depth == NULL) {
> >  +			EDEV_LOG_ERR("failed to realloc port deqeue meta
> >  data,"
> >  +						" nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +		/* Realloc memory for ports_enqueue_depth */
> >  +		ports_enqueue_depth = rte_realloc(ports_enqueue_depth,
> >  +			sizeof(ports_enqueue_depth[0]) * nb_ports,
> >  +			RTE_CACHE_LINE_SIZE);
> >  +		if (ports_enqueue_depth == NULL) {
> >  +			EDEV_LOG_ERR("failed to realloc port enqueue meta
> >  data,"
> >  +						" nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +		/* Realloc memory to store queue to port link connection */
> >  +		links_map = rte_realloc(links_map,
> >  +			sizeof(dev->data->links_map[0]) * nb_ports *
> >  +			RTE_EVENT_MAX_QUEUES_PER_DEV,
> >  +			RTE_CACHE_LINE_SIZE);
> >  +		if (dev->data->links_map == NULL) {
> >  +			dev->data->nb_ports = 0;
> >  +			EDEV_LOG_ERR("failed to realloc mem for port_map
> >  area,"
> >  +					"nb_ports %u", nb_ports);
> >  +			return -(ENOMEM);
> >  +		}
> >  +
> >  +		if (nb_ports > old_nb_ports) {
> >  +			uint8_t new_ps = nb_ports - old_nb_ports;
> >  +
> >  +			memset(ports + old_nb_ports, 0,
> >  +				sizeof(ports[0]) * new_ps);
> >  +			memset(ports_dequeue_depth + old_nb_ports, 0,
> >  +				sizeof(ports_dequeue_depth[0]) * new_ps);
> >  +			memset(ports_enqueue_depth + old_nb_ports, 0,
> >  +				sizeof(ports_enqueue_depth[0]) * new_ps);
> >  +			memset(links_map +
> >  +				(old_nb_ports *
> >  RTE_EVENT_MAX_QUEUES_PER_DEV),
> >  +				0, sizeof(ports_enqueue_depth[0]) * new_ps);
> >  +		}
> >  +
> >  +		dev->data->ports = ports;
> >  +		dev->data->ports_dequeue_depth = ports_dequeue_depth;
> >  +		dev->data->ports_enqueue_depth = ports_enqueue_depth;
> >  +		dev->data->links_map = links_map;
> >  +	} else if (dev->data->ports != NULL && nb_ports == 0) {
> >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release,
> >  -ENOTSUP);
> >  +
> >  +		ports = dev->data->ports;
> >  +		for (i = nb_ports; i < old_nb_ports; i++)
> >  +			(*dev->dev_ops->port_release)(ports[i]);
> >  +	}
> >  +
> >  +	dev->data->nb_ports = nb_ports;
> >  +	return 0;
> >  +}
> >  +
> >  +int
> >  +rte_event_dev_configure(uint8_t dev_id, struct rte_event_dev_config
> >  *dev_conf)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	struct rte_event_dev_info info;
> >  +	int diag;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
> >  ENOTSUP);
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -
> >  ENOTSUP);
> >  +
> >  +	if (dev->data->dev_started) {
> >  +		EDEV_LOG_ERR(
> >  +		    "device %d must be stopped to allow configuration",
> >  dev_id);
> >  +		return -EBUSY;
> >  +	}
> >  +
> >  +	if (dev_conf == NULL)
> >  +		return -EINVAL;
> >  +
> >  +	(*dev->dev_ops->dev_infos_get)(dev, &info);
> >  +
> >  +	/* Check dequeue_wait_ns value is in limit */
> >  +	if (!dev_conf->event_dev_cfg &
> >  RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT) {
> >  +		if (dev_conf->dequeue_wait_ns < info.min_dequeue_wait_ns
> >  ||
> >  +			dev_conf->dequeue_wait_ns >
> >  info.max_dequeue_wait_ns) {
> >  +			EDEV_LOG_ERR("dev%d invalid dequeue_wait_ns=%d"
> >  +			" min_dequeue_wait_ns=%d
> >  max_dequeue_wait_ns=%d",
> >  +			dev_id, dev_conf->dequeue_wait_ns,
> >  +			info.min_dequeue_wait_ns,
> >  +			info.max_dequeue_wait_ns);
> >  +			return -EINVAL;
> >  +		}
> >  +	}
> >  +
> >  +	/* Check nb_events_limit is in limit */
> >  +	if (dev_conf->nb_events_limit > info.max_num_events) {
> >  +		EDEV_LOG_ERR("dev%d nb_events_limit=%d >
> >  max_num_events=%d",
> >  +		dev_id, dev_conf->nb_events_limit, info.max_num_events);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check nb_event_queues is in limit */
> >  +	if (!dev_conf->nb_event_queues) {
> >  +		EDEV_LOG_ERR("dev%d nb_event_queues cannot be zero",
> >  dev_id);
> >  +		return -EINVAL;
> >  +	}
> >  +	if (dev_conf->nb_event_queues > info.max_event_queues) {
> >  +		EDEV_LOG_ERR("dev%d nb_event_queues=%d >
> >  max_event_queues=%d",
> >  +		dev_id, dev_conf->nb_event_queues,
> >  info.max_event_queues);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check nb_event_ports is in limit */
> >  +	if (!dev_conf->nb_event_ports) {
> >  +		EDEV_LOG_ERR("dev%d nb_event_ports cannot be zero",
> >  dev_id);
> >  +		return -EINVAL;
> >  +	}
> >  +	if (dev_conf->nb_event_ports > info.max_event_ports) {
> >  +		EDEV_LOG_ERR("dev%d nb_event_ports=%d >
> >  max_event_ports= %d",
> >  +		dev_id, dev_conf->nb_event_ports, info.max_event_ports);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check nb_event_queue_flows is in limit */
> >  +	if (!dev_conf->nb_event_queue_flows) {
> >  +		EDEV_LOG_ERR("dev%d nb_flows cannot be zero", dev_id);
> >  +		return -EINVAL;
> >  +	}
> >  +	if (dev_conf->nb_event_queue_flows > info.max_event_queue_flows)
> >  {
> >  +		EDEV_LOG_ERR("dev%d nb_flows=%x > max_flows=%x",
> >  +		dev_id, dev_conf->nb_event_queue_flows,
> >  +		info.max_event_queue_flows);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check nb_event_port_dequeue_depth is in limit */
> >  +	if (!dev_conf->nb_event_port_dequeue_depth) {
> >  +		EDEV_LOG_ERR("dev%d nb_dequeue_depth cannot be zero",
> >  dev_id);
> >  +		return -EINVAL;
> >  +	}
> >  +	if (dev_conf->nb_event_port_dequeue_depth >
> >  +			 info.max_event_port_dequeue_depth) {
> >  +		EDEV_LOG_ERR("dev%d nb_dequeue_depth=%d >
> >  max_dequeue_depth=%d",
> >  +		dev_id, dev_conf->nb_event_port_dequeue_depth,
> >  +		info.max_event_port_dequeue_depth);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check nb_event_port_enqueue_depth is in limit */
> >  +	if (!dev_conf->nb_event_port_enqueue_depth) {
> >  +		EDEV_LOG_ERR("dev%d nb_enqueue_depth cannot be zero",
> >  dev_id);
> >  +		return -EINVAL;
> >  +	}
> >  +	if (dev_conf->nb_event_port_enqueue_depth >
> >  +			 info.max_event_port_enqueue_depth) {
> >  +		EDEV_LOG_ERR("dev%d nb_enqueue_depth=%d >
> >  max_enqueue_depth=%d",
> >  +		dev_id, dev_conf->nb_event_port_enqueue_depth,
> >  +		info.max_event_port_enqueue_depth);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Copy the dev_conf parameter into the dev structure */
> >  +	memcpy(&dev->data->dev_conf, dev_conf, sizeof(dev->data-
> >  >dev_conf));
> >  +
> >  +	/* Setup new number of queues and reconfigure device. */
> >  +	diag = rte_event_dev_queue_config(dev, dev_conf-
> >  >nb_event_queues);
> >  +	if (diag != 0) {
> >  +		EDEV_LOG_ERR("dev%d rte_event_dev_queue_config = %d",
> >  +				dev_id, diag);
> >  +		return diag;
> >  +	}
> >  +
> >  +	/* Setup new number of ports and reconfigure device. */
> >  +	diag = rte_event_dev_port_config(dev, dev_conf->nb_event_ports);
> >  +	if (diag != 0) {
> >  +		rte_event_dev_queue_config(dev, 0);
> >  +		EDEV_LOG_ERR("dev%d rte_event_dev_port_config = %d",
> >  +				dev_id, diag);
> >  +		return diag;
> >  +	}
> >  +
> >  +	/* Configure the device */
> >  +	diag = (*dev->dev_ops->dev_configure)(dev);
> >  +	if (diag != 0) {
> >  +		EDEV_LOG_ERR("dev%d dev_configure = %d", dev_id, diag);
> >  +		rte_event_dev_queue_config(dev, 0);
> >  +		rte_event_dev_port_config(dev, 0);
> >  +	}
> >  +
> >  +	dev->data->event_dev_cap = info.event_dev_cap;
> >  +	return diag;
> >  +}
> >  +
> >  +static inline int
> >  +is_valid_queue(struct rte_eventdev *dev, uint8_t queue_id)
> >  +{
> >  +	if (queue_id < dev->data->nb_queues && queue_id <
> >  +				RTE_EVENT_MAX_QUEUES_PER_DEV)
> >  +		return 1;
> >  +	else
> >  +		return 0;
> >  +}
> >  +
> >  +int
> >  +rte_event_queue_default_conf_get(uint8_t dev_id, uint8_t queue_id,
> >  +				 struct rte_event_queue_conf *queue_conf)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +
> >  +	if (queue_conf == NULL)
> >  +		return -EINVAL;
> >  +
> >  +	if (!is_valid_queue(dev, queue_id)) {
> >  +		EDEV_LOG_ERR("Invalid queue_id=%" PRIu8, queue_id);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_def_conf, -
> >  ENOTSUP);
> >  +	memset(queue_conf, 0, sizeof(struct rte_event_queue_conf));
> >  +	(*dev->dev_ops->queue_def_conf)(dev, queue_id, queue_conf);
> >  +	return 0;
> >  +}
> >  +
> >  +static inline int
> >  +is_valid_atomic_queue_conf(struct rte_event_queue_conf *queue_conf)
> >  +{
> >  +	if (queue_conf && (
> >  +		((queue_conf->event_queue_cfg &
> >  RTE_EVENT_QUEUE_CFG_TYPE_MASK)
> >  +			== RTE_EVENT_QUEUE_CFG_ALL_TYPES) ||
> >  +		((queue_conf->event_queue_cfg &
> >  RTE_EVENT_QUEUE_CFG_TYPE_MASK)
> >  +			== RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY)
> >  +		))
> >  +		return 1;
> >  +	else
> >  +		return 0;
> >  +}
> >  +
> >  +int
> >  +rte_event_queue_setup(uint8_t dev_id, uint8_t queue_id,
> >  +		      struct rte_event_queue_conf *queue_conf)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	struct rte_event_queue_conf def_conf;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +
> >  +	if (!is_valid_queue(dev, queue_id)) {
> >  +		EDEV_LOG_ERR("Invalid queue_id=%" PRIu8, queue_id);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check nb_atomic_flows limit */
> >  +	if (is_valid_atomic_queue_conf(queue_conf)) {
> >  +		if (queue_conf->nb_atomic_flows == 0 ||
> >  +		    queue_conf->nb_atomic_flows >
> >  +			dev->data->dev_conf.nb_event_queue_flows) {
> >  +			EDEV_LOG_ERR(
> >  +		"dev%d queue%d Invalid nb_atomic_flows=%d
> >  max_flows=%d",
> >  +			dev_id, queue_id, queue_conf->nb_atomic_flows,
> >  +			dev->data->dev_conf.nb_event_queue_flows);
> >  +			return -EINVAL;
> >  +		}
> >  +	}
> >  +
> >  +	/* Check nb_atomic_order_sequences limit */
> >  +	if (is_valid_atomic_queue_conf(queue_conf)) {
> >  +		if (queue_conf->nb_atomic_order_sequences == 0 ||
> >  +		    queue_conf->nb_atomic_order_sequences >
> >  +			dev->data->dev_conf.nb_event_queue_flows) {
> >  +			EDEV_LOG_ERR(
> >  +		"dev%d queue%d Invalid nb_atomic_order_seq=%d
> >  max_flows=%d",
> >  +			dev_id, queue_id, queue_conf-
> >  >nb_atomic_order_sequences,
> >  +			dev->data->dev_conf.nb_event_queue_flows);
> >  +			return -EINVAL;
> >  +		}
> >  +	}
> >  +
> >  +	if (dev->data->dev_started) {
> >  +		EDEV_LOG_ERR(
> >  +		    "device %d must be stopped to allow queue setup", dev_id);
> >  +		return -EBUSY;
> >  +	}
> >  +
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_setup, -
> >  ENOTSUP);
> >  +
> >  +	if (queue_conf == NULL) {
> >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >  >queue_def_conf,
> >  +					-ENOTSUP);
> >  +		(*dev->dev_ops->queue_def_conf)(dev, queue_id, &def_conf);
> >  +		def_conf.event_queue_cfg =
> >  RTE_EVENT_QUEUE_CFG_DEFAULT;
> >  +		queue_conf = &def_conf;
> >  +	}
> >  +
> >  +	dev->data->queues_prio[queue_id] = queue_conf->priority;
> >  +	return (*dev->dev_ops->queue_setup)(dev, queue_id, queue_conf);
> >  +}
> >  +
> >  +uint8_t
> >  +rte_event_queue_count(uint8_t dev_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	return dev->data->nb_queues;
> >  +}
> >  +
> >  +uint8_t
> >  +rte_event_queue_priority(uint8_t dev_id, uint8_t queue_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	if (dev->data->event_dev_cap & RTE_EVENT_DEV_CAP_QUEUE_QOS)
> >  +		return dev->data->queues_prio[queue_id];
> >  +	else
> >  +		return RTE_EVENT_QUEUE_PRIORITY_NORMAL;
> >  +}
> >  +
> >  +static inline int
> >  +is_valid_port(struct rte_eventdev *dev, uint8_t port_id)
> >  +{
> >  +	if (port_id < dev->data->nb_ports)
> >  +		return 1;
> >  +	else
> >  +		return 0;
> >  +}
> >  +
> >  +int
> >  +rte_event_port_default_conf_get(uint8_t dev_id, uint8_t port_id,
> >  +				 struct rte_event_port_conf *port_conf)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +
> >  +	if (port_conf == NULL)
> >  +		return -EINVAL;
> >  +
> >  +	if (!is_valid_port(dev, port_id)) {
> >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_def_conf, -
> >  ENOTSUP);
> >  +	memset(port_conf, 0, sizeof(struct rte_event_port_conf));
> >  +	(*dev->dev_ops->port_def_conf)(dev, port_id, port_conf);
> >  +	return 0;
> >  +}
> >  +
> >  +int
> >  +rte_event_port_setup(uint8_t dev_id, uint8_t port_id,
> >  +		      struct rte_event_port_conf *port_conf)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	struct rte_event_port_conf def_conf;
> >  +	int diag;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +
> >  +	if (!is_valid_port(dev, port_id)) {
> >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check new_event_threshold limit */
> >  +	if ((port_conf && !port_conf->new_event_threshold) ||
> >  +			(port_conf && port_conf->new_event_threshold >
> >  +				 dev->data->dev_conf.nb_events_limit)) {
> >  +		EDEV_LOG_ERR(
> >  +		   "dev%d port%d Invalid event_threshold=%d
> >  nb_events_limit=%d",
> >  +			dev_id, port_id, port_conf->new_event_threshold,
> >  +			dev->data->dev_conf.nb_events_limit);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check dequeue_depth limit */
> >  +	if ((port_conf && !port_conf->dequeue_depth) ||
> >  +			(port_conf && port_conf->dequeue_depth >
> >  +		dev->data->dev_conf.nb_event_port_dequeue_depth)) {
> >  +		EDEV_LOG_ERR(
> >  +		   "dev%d port%d Invalid dequeue depth=%d
> >  max_dequeue_depth=%d",
> >  +			dev_id, port_id, port_conf->dequeue_depth,
> >  +			dev->data-
> >  >dev_conf.nb_event_port_dequeue_depth);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	/* Check enqueue_depth limit */
> >  +	if ((port_conf && !port_conf->enqueue_depth) ||
> >  +			(port_conf && port_conf->enqueue_depth >
> >  +		dev->data->dev_conf.nb_event_port_enqueue_depth)) {
> >  +		EDEV_LOG_ERR(
> >  +		   "dev%d port%d Invalid enqueue depth=%d
> >  max_enqueue_depth=%d",
> >  +			dev_id, port_id, port_conf->enqueue_depth,
> >  +			dev->data-
> >  >dev_conf.nb_event_port_enqueue_depth);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	if (dev->data->dev_started) {
> >  +		EDEV_LOG_ERR(
> >  +		    "device %d must be stopped to allow port setup", dev_id);
> >  +		return -EBUSY;
> >  +	}
> >  +
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_setup, -
> >  ENOTSUP);
> >  +
> >  +	if (port_conf == NULL) {
> >  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >  >port_def_conf,
> >  +					-ENOTSUP);
> >  +		(*dev->dev_ops->port_def_conf)(dev, port_id, &def_conf);
> >  +		port_conf = &def_conf;
> >  +	}
> >  +
> >  +	dev->data->ports_dequeue_depth[port_id] =
> >  +			port_conf->dequeue_depth;
> >  +	dev->data->ports_enqueue_depth[port_id] =
> >  +			port_conf->enqueue_depth;
> >  +
> >  +	diag = (*dev->dev_ops->port_setup)(dev, port_id, port_conf);
> >  +
> >  +	/* Unlink all the queues from this port(default state after setup) */
> >  +	if (!diag)
> >  +		diag = rte_event_port_unlink(dev_id, port_id, NULL, 0);
> >  +
> >  +	if (diag < 0)
> >  +		return diag;
> >  +
> >  +	return 0;
> >  +}
> >  +
> >  +uint8_t
> >  +rte_event_port_dequeue_depth(uint8_t dev_id, uint8_t port_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	return dev->data->ports_dequeue_depth[port_id];
> >  +}
> >  +
> >  +uint8_t
> >  +rte_event_port_enqueue_depth(uint8_t dev_id, uint8_t port_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	return dev->data->ports_enqueue_depth[port_id];
> >  +}
> >  +
> >  +uint8_t
> >  +rte_event_port_count(uint8_t dev_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	return dev->data->nb_ports;
> >  +}
> >  +
> >  +int
> >  +rte_event_port_link(uint8_t dev_id, uint8_t port_id,
> >  +		    struct rte_event_queue_link link[], uint16_t nb_links)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	struct rte_event_queue_link
> >  all_queues[RTE_EVENT_MAX_QUEUES_PER_DEV];
> >  +	uint16_t *links_map;
> >  +	int i, diag;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_link, -ENOTSUP);
> >  +
> >  +	if (!is_valid_port(dev, port_id)) {
> >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	if (link == NULL) {
> >  +		for (i = 0; i < dev->data->nb_queues; i++) {
> >  +			all_queues[i].queue_id = i;
> >  +			all_queues[i].priority =
> >  +
> >  	RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL;
> >  +		}
> >  +		link = all_queues;
> >  +		nb_links = dev->data->nb_queues;
> >  +	}
> >  +
> >  +	for (i = 0; i < nb_links; i++)
> >  +		if (link[i].queue_id >= RTE_EVENT_MAX_QUEUES_PER_DEV)
> >  +			return -EINVAL;
> >  +
> >  +	diag = (*dev->dev_ops->port_link)(dev->data->ports[port_id], link,
> >  +						 nb_links);
> >  +	if (diag < 0)
> >  +		return diag;
> >  +
> >  +	links_map = dev->data->links_map;
> >  +	/* Point links_map to this port specific area */
> >  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
> >  +	for (i = 0; i < diag; i++)
> >  +		links_map[link[i].queue_id] = (uint8_t)link[i].priority;
> >  +
> >  +	return diag;
> >  +}
> >  +
> >  +#define EVENT_QUEUE_SERVICE_PRIORITY_INVALID (0xdead)
> >  +
> >  +int
> >  +rte_event_port_unlink(uint8_t dev_id, uint8_t port_id,
> >  +		      uint8_t queues[], uint16_t nb_unlinks)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	uint8_t all_queues[RTE_EVENT_MAX_QUEUES_PER_DEV];
> >  +	int i, diag;
> >  +	uint16_t *links_map;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_unlink, -
> >  ENOTSUP);
> >  +
> >  +	if (!is_valid_port(dev, port_id)) {
> >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	if (queues == NULL) {
> >  +		for (i = 0; i < dev->data->nb_queues; i++)
> >  +			all_queues[i] = i;
> >  +		queues = all_queues;
> >  +		nb_unlinks = dev->data->nb_queues;
> >  +	}
> >  +
> >  +	for (i = 0; i < nb_unlinks; i++)
> >  +		if (queues[i] >= RTE_EVENT_MAX_QUEUES_PER_DEV)
> >  +			return -EINVAL;
> >  +
> >  +	diag = (*dev->dev_ops->port_unlink)(dev->data->ports[port_id],
> >  queues,
> >  +					nb_unlinks);
> >  +
> >  +	if (diag < 0)
> >  +		return diag;
> >  +
> >  +	links_map = dev->data->links_map;
> >  +	/* Point links_map to this port specific area */
> >  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
> >  +	for (i = 0; i < diag; i++)
> >  +		links_map[queues[i]] =
> >  EVENT_QUEUE_SERVICE_PRIORITY_INVALID;
> >  +
> >  +	return diag;
> >  +}
> >  +
> >  +int
> >  +rte_event_port_links_get(uint8_t dev_id, uint8_t port_id,
> >  +			struct rte_event_queue_link link[])
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	uint16_t *links_map;
> >  +	int i, count = 0;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	if (!is_valid_port(dev, port_id)) {
> >  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
> >  +		return -EINVAL;
> >  +	}
> >  +
> >  +	links_map = dev->data->links_map;
> >  +	/* Point links_map to this port specific area */
> >  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
> >  +	for (i = 0; i < RTE_EVENT_MAX_QUEUES_PER_DEV; i++) {
> >  +		if (links_map[i] !=
> >  EVENT_QUEUE_SERVICE_PRIORITY_INVALID) {
> >  +			link[count].queue_id = i;
> >  +			link[count].priority = (uint8_t)links_map[i];
> >  +			++count;
> >  +		}
> >  +	}
> >  +	return count;
> >  +}
> >  +
> >  +int
> >  +rte_event_dequeue_wait_time(uint8_t dev_id, uint64_t ns, uint64_t
> >  *wait_ticks)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->wait_time, -
> >  ENOTSUP);
> >  +
> >  +	if (wait_ticks == NULL)
> >  +		return -EINVAL;
> >  +
> >  +	(*dev->dev_ops->wait_time)(dev, ns, wait_ticks);
> >  +	return 0;
> >  +}
> >  +
> >  +int
> >  +rte_event_dev_dump(uint8_t dev_id, FILE *f)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dump, -ENOTSUP);
> >  +
> >  +	(*dev->dev_ops->dump)(dev, f);
> >  +	return 0;
> >  +
> >  +}
> >  +
> >  +int
> >  +rte_event_dev_start(uint8_t dev_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	int diag;
> >  +
> >  +	EDEV_LOG_DEBUG("Start dev_id=%" PRIu8, dev_id);
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_start, -ENOTSUP);
> >  +
> >  +	if (dev->data->dev_started != 0) {
> >  +		EDEV_LOG_ERR("Device with dev_id=%" PRIu8 " already
> >  started",
> >  +			dev_id);
> >  +		return 0;
> >  +	}
> >  +
> >  +	diag = (*dev->dev_ops->dev_start)(dev);
> >  +	if (diag == 0)
> >  +		dev->data->dev_started = 1;
> >  +	else
> >  +		return diag;
> >  +
> >  +	return 0;
> >  +}
> >  +
> >  +void
> >  +rte_event_dev_stop(uint8_t dev_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	EDEV_LOG_DEBUG("Stop dev_id=%" PRIu8, dev_id);
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_RET(dev_id);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_stop);
> >  +
> >  +	if (dev->data->dev_started == 0) {
> >  +		EDEV_LOG_ERR("Device with dev_id=%" PRIu8 " already
> >  stopped",
> >  +			dev_id);
> >  +		return;
> >  +	}
> >  +
> >  +	dev->data->dev_started = 0;
> >  +	(*dev->dev_ops->dev_stop)(dev);
> >  +}
> >  +
> >  +int
> >  +rte_event_dev_close(uint8_t dev_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -
> >  ENOTSUP);
> >  +
> >  +	/* Device must be stopped before it can be closed */
> >  +	if (dev->data->dev_started == 1) {
> >  +		EDEV_LOG_ERR("Device %u must be stopped before closing",
> >  +				dev_id);
> >  +		return -EBUSY;
> >  +	}
> >  +
> >  +	return (*dev->dev_ops->dev_close)(dev);
> >  +}
> >  +
> >  +static inline int
> >  +rte_eventdev_data_alloc(uint8_t dev_id, struct rte_eventdev_data **data,
> >  +		int socket_id)
> >  +{
> >  +	char mz_name[RTE_EVENTDEV_NAME_MAX_LEN];
> >  +	const struct rte_memzone *mz;
> >  +	int n;
> >  +
> >  +	/* Generate memzone name */
> >  +	n = snprintf(mz_name, sizeof(mz_name), "rte_eventdev_data_%u",
> >  dev_id);
> >  +	if (n >= (int)sizeof(mz_name))
> >  +		return -EINVAL;
> >  +
> >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> >  +		mz = rte_memzone_reserve(mz_name,
> >  +				sizeof(struct rte_eventdev_data),
> >  +				socket_id, 0);
> >  +	} else
> >  +		mz = rte_memzone_lookup(mz_name);
> >  +
> >  +	if (mz == NULL)
> >  +		return -ENOMEM;
> >  +
> >  +	*data = mz->addr;
> >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> >  +		memset(*data, 0, sizeof(struct rte_eventdev_data));
> >  +
> >  +	return 0;
> >  +}
> >  +
> >  +static uint8_t
> >  +rte_eventdev_find_free_device_index(void)
> >  +{
> >  +	uint8_t dev_id;
> >  +
> >  +	for (dev_id = 0; dev_id < RTE_EVENT_MAX_DEVS; dev_id++) {
> >  +		if (rte_eventdevs[dev_id].attached ==
> >  +				RTE_EVENTDEV_DETACHED)
> >  +			return dev_id;
> >  +	}
> >  +	return RTE_EVENT_MAX_DEVS;
> >  +}
> >  +
> >  +struct rte_eventdev *
> >  +rte_eventdev_pmd_allocate(const char *name, int socket_id)
> >  +{
> >  +	struct rte_eventdev *eventdev;
> >  +	uint8_t dev_id;
> >  +
> >  +	if (rte_eventdev_pmd_get_named_dev(name) != NULL) {
> >  +		EDEV_LOG_ERR("Event device with name %s already "
> >  +				"allocated!", name);
> >  +		return NULL;
> >  +	}
> >  +
> >  +	dev_id = rte_eventdev_find_free_device_index();
> >  +	if (dev_id == RTE_EVENT_MAX_DEVS) {
> >  +		EDEV_LOG_ERR("Reached maximum number of event
> >  devices");
> >  +		return NULL;
> >  +	}
> >  +
> >  +	eventdev = &rte_eventdevs[dev_id];
> >  +
> >  +	if (eventdev->data == NULL) {
> >  +		struct rte_eventdev_data *eventdev_data = NULL;
> >  +
> >  +		int retval = rte_eventdev_data_alloc(dev_id, &eventdev_data,
> >  +				socket_id);
> >  +
> >  +		if (retval < 0 || eventdev_data == NULL)
> >  +			return NULL;
> >  +
> >  +		eventdev->data = eventdev_data;
> >  +
> >  +		snprintf(eventdev->data->name,
> >  RTE_EVENTDEV_NAME_MAX_LEN,
> >  +				"%s", name);
> >  +
> >  +		eventdev->data->dev_id = dev_id;
> >  +		eventdev->data->socket_id = socket_id;
> >  +		eventdev->data->dev_started = 0;
> >  +
> >  +		eventdev->attached = RTE_EVENTDEV_ATTACHED;
> >  +
> >  +		eventdev_globals.nb_devs++;
> >  +	}
> >  +
> >  +	return eventdev;
> >  +}
> >  +
> >  +int
> >  +rte_eventdev_pmd_release(struct rte_eventdev *eventdev)
> >  +{
> >  +	int ret;
> >  +
> >  +	if (eventdev == NULL)
> >  +		return -EINVAL;
> >  +
> >  +	ret = rte_event_dev_close(eventdev->data->dev_id);
> >  +	if (ret < 0)
> >  +		return ret;
> >  +
> >  +	eventdev->attached = RTE_EVENTDEV_DETACHED;
> >  +	eventdev_globals.nb_devs--;
> >  +	eventdev->data = NULL;
> >  +
> >  +	return 0;
> >  +}
> >  +
> >  +struct rte_eventdev *
> >  +rte_eventdev_pmd_vdev_init(const char *name, size_t dev_private_size,
> >  +		int socket_id)
> >  +{
> >  +	struct rte_eventdev *eventdev;
> >  +
> >  +	/* Allocate device structure */
> >  +	eventdev = rte_eventdev_pmd_allocate(name, socket_id);
> >  +	if (eventdev == NULL)
> >  +		return NULL;
> >  +
> >  +	/* Allocate private device structure */
> >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> >  +		eventdev->data->dev_private =
> >  +				rte_zmalloc_socket("eventdev device private",
> >  +						dev_private_size,
> >  +						RTE_CACHE_LINE_SIZE,
> >  +						socket_id);
> >  +
> >  +		if (eventdev->data->dev_private == NULL)
> >  +			rte_panic("Cannot allocate memzone for private
> >  device"
> >  +					" data");
> >  +	}
> >  +
> >  +	return eventdev;
> >  +}
> >  +
> >  +int
> >  +rte_eventdev_pmd_pci_probe(struct rte_pci_driver *pci_drv,
> >  +			struct rte_pci_device *pci_dev)
> >  +{
> >  +	struct rte_eventdev_driver *eventdrv;
> >  +	struct rte_eventdev *eventdev;
> >  +
> >  +	char eventdev_name[RTE_EVENTDEV_NAME_MAX_LEN];
> >  +
> >  +	int retval;
> >  +
> >  +	eventdrv = (struct rte_eventdev_driver *)pci_drv;
> >  +	if (eventdrv == NULL)
> >  +		return -ENODEV;
> >  +
> >  +	rte_eal_pci_device_name(&pci_dev->addr, eventdev_name,
> >  +			sizeof(eventdev_name));
> >  +
> >  +	eventdev = rte_eventdev_pmd_allocate(eventdev_name,
> >  +			 pci_dev->device.numa_node);
> >  +	if (eventdev == NULL)
> >  +		return -ENOMEM;
> >  +
> >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> >  +		eventdev->data->dev_private =
> >  +				rte_zmalloc_socket(
> >  +						"eventdev private structure",
> >  +						eventdrv->dev_private_size,
> >  +						RTE_CACHE_LINE_SIZE,
> >  +						rte_socket_id());
> >  +
> >  +		if (eventdev->data->dev_private == NULL)
> >  +			rte_panic("Cannot allocate memzone for private "
> >  +					"device data");
> >  +	}
> >  +
> >  +	eventdev->pci_dev = pci_dev;
> >  +	eventdev->driver = eventdrv;
> >  +
> >  +	/* Invoke PMD device initialization function */
> >  +	retval = (*eventdrv->eventdev_init)(eventdev);
> >  +	if (retval == 0)
> >  +		return 0;
> >  +
> >  +	EDEV_LOG_ERR("driver %s: event_dev_init(vendor_id=0x%x
> >  device_id=0x%x)"
> >  +			" failed", pci_drv->driver.name,
> >  +			(unsigned int) pci_dev->id.vendor_id,
> >  +			(unsigned int) pci_dev->id.device_id);
> >  +
> >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> >  +		rte_free(eventdev->data->dev_private);
> >  +
> >  +	eventdev->attached = RTE_EVENTDEV_DETACHED;
> >  +	eventdev_globals.nb_devs--;
> >  +
> >  +	return -ENXIO;
> >  +}
> >  +
> >  +int
> >  +rte_eventdev_pmd_pci_remove(struct rte_pci_device *pci_dev)
> >  +{
> >  +	const struct rte_eventdev_driver *eventdrv;
> >  +	struct rte_eventdev *eventdev;
> >  +	char eventdev_name[RTE_EVENTDEV_NAME_MAX_LEN];
> >  +	int ret;
> >  +
> >  +	if (pci_dev == NULL)
> >  +		return -EINVAL;
> >  +
> >  +	rte_eal_pci_device_name(&pci_dev->addr, eventdev_name,
> >  +			sizeof(eventdev_name));
> >  +
> >  +	eventdev = rte_eventdev_pmd_get_named_dev(eventdev_name);
> >  +	if (eventdev == NULL)
> >  +		return -ENODEV;
> >  +
> >  +	eventdrv = (const struct rte_eventdev_driver *)pci_dev->driver;
> >  +	if (eventdrv == NULL)
> >  +		return -ENODEV;
> >  +
> >  +	/* Invoke PMD device uninit function */
> >  +	if (*eventdrv->eventdev_uninit) {
> >  +		ret = (*eventdrv->eventdev_uninit)(eventdev);
> >  +		if (ret)
> >  +			return ret;
> >  +	}
> >  +
> >  +	/* Free event device */
> >  +	rte_eventdev_pmd_release(eventdev);
> >  +
> >  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> >  +		rte_free(eventdev->data->dev_private);
> >  +
> >  +	eventdev->pci_dev = NULL;
> >  +	eventdev->driver = NULL;
> >  +
> >  +	return 0;
> >  +}
> >  diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h
> >  b/lib/librte_eventdev/rte_eventdev_pmd.h
> >  new file mode 100644
> >  index 0000000..e9d9b83
> >  --- /dev/null
> >  +++ b/lib/librte_eventdev/rte_eventdev_pmd.h
> >  @@ -0,0 +1,504 @@
> >  +/*
> >  + *
> >  + *   Copyright(c) 2016 Cavium networks. All rights reserved.
> >  + *
> >  + *   Redistribution and use in source and binary forms, with or without
> >  + *   modification, are permitted provided that the following conditions
> >  + *   are met:
> >  + *
> >  + *     * Redistributions of source code must retain the above copyright
> >  + *       notice, this list of conditions and the following disclaimer.
> >  + *     * Redistributions in binary form must reproduce the above copyright
> >  + *       notice, this list of conditions and the following disclaimer in
> >  + *       the documentation and/or other materials provided with the
> >  + *       distribution.
> >  + *     * Neither the name of Cavium networks nor the names of its
> >  + *       contributors may be used to endorse or promote products derived
> >  + *       from this software without specific prior written permission.
> >  + *
> >  + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> >  CONTRIBUTORS
> >  + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> >  NOT
> >  + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> >  FITNESS FOR
> >  + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> >  COPYRIGHT
> >  + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> >  INCIDENTAL,
> >  + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> >  NOT
> >  + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> >  OF USE,
> >  + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> >  AND ON ANY
> >  + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> >  TORT
> >  + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> >  THE USE
> >  + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> >  DAMAGE.
> >  + */
> >  +
> >  +#ifndef _RTE_EVENTDEV_PMD_H_
> >  +#define _RTE_EVENTDEV_PMD_H_
> >  +
> >  +/** @file
> >  + * RTE Event PMD APIs
> >  + *
> >  + * @note
> >  + * These API are from event PMD only and user applications should not call
> >  + * them directly.
> >  + */
> >  +
> >  +#ifdef __cplusplus
> >  +extern "C" {
> >  +#endif
> >  +
> >  +#include <string.h>
> >  +
> >  +#include <rte_dev.h>
> >  +#include <rte_pci.h>
> >  +#include <rte_malloc.h>
> >  +#include <rte_log.h>
> >  +#include <rte_common.h>
> >  +
> >  +#include "rte_eventdev.h"
> >  +
> >  +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> >  +#define RTE_PMD_DEBUG_TRACE(...) \
> >  +	rte_pmd_debug_trace(__func__, __VA_ARGS__)
> >  +#else
> >  +#define RTE_PMD_DEBUG_TRACE(...)
> >  +#endif
> >  +
> >  +/* Logging Macros */
> >  +#define EDEV_LOG_ERR(fmt, args...) \
> >  +	RTE_LOG(ERR, EVENTDEV, "%s() line %u: " fmt "\n",  \
> >  +			__func__, __LINE__, ## args)
> >  +
> >  +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> >  +#define EDEV_LOG_DEBUG(fmt, args...) \
> >  +	RTE_LOG(DEBUG, EVENTDEV, "%s() line %u: " fmt "\n",  \
> >  +			__func__, __LINE__, ## args)
> >  +#else
> >  +#define EDEV_LOG_DEBUG(fmt, args...) (void)0
> >  +#endif
> >  +
> >  +/* Macros to check for valid device */
> >  +#define RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, retval) do { \
> >  +	if (!rte_eventdev_pmd_is_valid_dev((dev_id))) { \
> >  +		EDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
> >  +		return retval; \
> >  +	} \
> >  +} while (0)
> >  +
> >  +#define RTE_EVENTDEV_VALID_DEVID_OR_RET(dev_id) do { \
> >  +	if (!rte_eventdev_pmd_is_valid_dev((dev_id))) { \
> >  +		EDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
> >  +		return; \
> >  +	} \
> >  +} while (0)
> >  +
> >  +#define RTE_EVENTDEV_DETACHED  (0)
> >  +#define RTE_EVENTDEV_ATTACHED  (1)
> >  +
> >  +/**
> >  + * Initialisation function of a event driver invoked for each matching
> >  + * event PCI device detected during the PCI probing phase.
> >  + *
> >  + * @param dev
> >  + *   The dev pointer is the address of the *rte_eventdev* structure associated
> >  + *   with the matching device and which has been [automatically] allocated in
> >  + *   the *rte_event_devices* array.
> >  + *
> >  + * @return
> >  + *   - 0: Success, the device is properly initialised by the driver.
> >  + *        In particular, the driver MUST have set up the *dev_ops* pointer
> >  + *        of the *dev* structure.
> >  + *   - <0: Error code of the device initialisation failure.
> >  + */
> >  +typedef int (*eventdev_init_t)(struct rte_eventdev *dev);
> >  +
> >  +/**
> >  + * Finalisation function of a driver invoked for each matching
> >  + * PCI device detected during the PCI closing phase.
> >  + *
> >  + * @param dev
> >  + *   The dev pointer is the address of the *rte_eventdev* structure associated
> >  + *   with the matching device and which	has been [automatically] allocated in
> >  + *   the *rte_event_devices* array.
> >  + *
> >  + * @return
> >  + *   - 0: Success, the device is properly finalised by the driver.
> >  + *        In particular, the driver MUST free the *dev_ops* pointer
> >  + *        of the *dev* structure.
> >  + *   - <0: Error code of the device initialisation failure.
> >  + */
> >  +typedef int (*eventdev_uninit_t)(struct rte_eventdev *dev);
> >  +
> >  +/**
> >  + * The structure associated with a PMD driver.
> >  + *
> >  + * Each driver acts as a PCI driver and is represented by a generic
> >  + * *event_driver* structure that holds:
> >  + *
> >  + * - An *rte_pci_driver* structure (which must be the first field).
> >  + *
> >  + * - The *eventdev_init* function invoked for each matching PCI device.
> >  + *
> >  + * - The size of the private data to allocate for each matching device.
> >  + */
> >  +struct rte_eventdev_driver {
> >  +	struct rte_pci_driver pci_drv;	/**< The PMD is also a PCI driver. */
> >  +	unsigned int dev_private_size;	/**< Size of device private data. */
> >  +
> >  +	eventdev_init_t eventdev_init;	/**< Device init function. */
> >  +	eventdev_uninit_t eventdev_uninit; /**< Device uninit function. */
> >  +};
> >  +
> >  +/** Global structure used for maintaining state of allocated event devices */
> >  +struct rte_eventdev_global {
> >  +	uint8_t nb_devs;	/**< Number of devices found */
> >  +	uint8_t max_devs;	/**< Max number of devices */
> >  +};
> >  +
> >  +extern struct rte_eventdev_global *rte_eventdev_globals;
> >  +/** Pointer to global event devices data structure. */
> >  +extern struct rte_eventdev *rte_eventdevs;
> >  +/** The pool of rte_eventdev structures. */
> >  +
> >  +/**
> >  + * Get the rte_eventdev structure device pointer for the named device.
> >  + *
> >  + * @param name
> >  + *   device name to select the device structure.
> >  + *
> >  + * @return
> >  + *   - The rte_eventdev structure pointer for the given device ID.
> >  + */
> >  +static inline struct rte_eventdev *
> >  +rte_eventdev_pmd_get_named_dev(const char *name)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +	unsigned int i;
> >  +
> >  +	if (name == NULL)
> >  +		return NULL;
> >  +
> >  +	for (i = 0, dev = &rte_eventdevs[i];
> >  +			i < rte_eventdev_globals->max_devs; i++) {
> >  +		if ((dev->attached == RTE_EVENTDEV_ATTACHED) &&
> >  +				(strcmp(dev->data->name, name) == 0))
> >  +			return dev;
> >  +	}
> >  +
> >  +	return NULL;
> >  +}
> >  +
> >  +/**
> >  + * Validate if the event device index is valid attached event device.
> >  + *
> >  + * @param dev_id
> >  + *   Event device index.
> >  + *
> >  + * @return
> >  + *   - If the device index is valid (1) or not (0).
> >  + */
> >  +static inline unsigned
> >  +rte_eventdev_pmd_is_valid_dev(uint8_t dev_id)
> >  +{
> >  +	struct rte_eventdev *dev;
> >  +
> >  +	if (dev_id >= rte_eventdev_globals->nb_devs)
> >  +		return 0;
> >  +
> >  +	dev = &rte_eventdevs[dev_id];
> >  +	if (dev->attached != RTE_EVENTDEV_ATTACHED)
> >  +		return 0;
> >  +	else
> >  +		return 1;
> >  +}
> >  +
> >  +/**
> >  + * Definitions of all functions exported by a driver through the
> >  + * the generic structure of type *event_dev_ops* supplied in the
> >  + * *rte_eventdev* structure associated with a device.
> >  + */
> >  +
> >  +/**
> >  + * Get device information of a device.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + * @param dev_info
> >  + *   Event device information structure
> >  + *
> >  + * @return
> >  + *   Returns 0 on success
> >  + */
> >  +typedef void (*eventdev_info_get_t)(struct rte_eventdev *dev,
> >  +		struct rte_event_dev_info *dev_info);
> >  +
> >  +/**
> >  + * Configure a device.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + *
> >  + * @return
> >  + *   Returns 0 on success
> >  + */
> >  +typedef int (*eventdev_configure_t)(struct rte_eventdev *dev);
> >  +
> >  +/**
> >  + * Start a configured device.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + *
> >  + * @return
> >  + *   Returns 0 on success
> >  + */
> >  +typedef int (*eventdev_start_t)(struct rte_eventdev *dev);
> >  +
> >  +/**
> >  + * Stop a configured device.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + */
> >  +typedef void (*eventdev_stop_t)(struct rte_eventdev *dev);
> >  +
> >  +/**
> >  + * Close a configured device.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + *
> >  + * @return
> >  + * - 0 on success
> >  + * - (-EAGAIN) if can't close as device is busy
> >  + */
> >  +typedef int (*eventdev_close_t)(struct rte_eventdev *dev);
> >  +
> >  +/**
> >  + * Retrieve the default event queue configuration.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + * @param queue_id
> >  + *   Event queue index
> >  + * @param[out] queue_conf
> >  + *   Event queue configuration structure
> >  + *
> >  + */
> >  +typedef void (*eventdev_queue_default_conf_get_t)(struct rte_eventdev
> >  *dev,
> >  +		uint8_t queue_id, struct rte_event_queue_conf *queue_conf);
> >  +
> >  +/**
> >  + * Setup an event queue.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + * @param queue_id
> >  + *   Event queue index
> >  + * @param queue_conf
> >  + *   Event queue configuration structure
> >  + *
> >  + * @return
> >  + *   Returns 0 on success.
> >  + */
> >  +typedef int (*eventdev_queue_setup_t)(struct rte_eventdev *dev,
> >  +		uint8_t queue_id, struct rte_event_queue_conf *queue_conf);
> >  +
> >  +/**
> >  + * Release memory resources allocated by given event queue.
> >  + *
> >  + * @param queue
> >  + *   Event queue pointer
> >  + *
> >  + */
> >  +typedef void (*eventdev_queue_release_t)(void *queue);
> >  +
> >  +/**
> >  + * Retrieve the default event port configuration.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + * @param port_id
> >  + *   Event port index
> >  + * @param[out] port_conf
> >  + *   Event port configuration structure
> >  + *
> >  + */
> >  +typedef void (*eventdev_port_default_conf_get_t)(struct rte_eventdev *dev,
> >  +		uint8_t port_id, struct rte_event_port_conf *port_conf);
> >  +
> >  +/**
> >  + * Setup an event port.
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + * @param port_id
> >  + *   Event port index
> >  + * @param port_conf
> >  + *   Event port configuration structure
> >  + *
> >  + * @return
> >  + *   Returns 0 on success.
> >  + */
> >  +typedef int (*eventdev_port_setup_t)(struct rte_eventdev *dev,
> >  +		uint8_t port_id, struct rte_event_port_conf *port_conf);
> >  +
> >  +/**
> >  + * Release memory resources allocated by given event port.
> >  + *
> >  + * @param port
> >  + *   Event port pointer
> >  + *
> >  + */
> >  +typedef void (*eventdev_port_release_t)(void *port);
> >  +
> >  +/**
> >  + * Link multiple source event queues to destination event port.
> >  + *
> >  + * @param port
> >  + *   Event port pointer
> >  + * @param link
> >  + *   An array of *nb_links* pointers to *rte_event_queue_link* structure
> >  + * @param nb_links
> >  + *   The number of links to establish
> >  + *
> >  + * @return
> >  + *   Returns 0 on success.
> >  + *
> >  + */
> >  +typedef int (*eventdev_port_link_t)(void *port,
> >  +		struct rte_event_queue_link link[], uint16_t nb_links);
> >  +
> >  +/**
> >  + * Unlink multiple source event queues from destination event port.
> >  + *
> >  + * @param port
> >  + *   Event port pointer
> >  + * @param queues
> >  + *   An array of *nb_unlinks* event queues to be unlinked from the event port.
> >  + * @param nb_unlinks
> >  + *   The number of unlinks to establish
> >  + *
> >  + * @return
> >  + *   Returns 0 on success.
> >  + *
> >  + */
> >  +typedef int (*eventdev_port_unlink_t)(void *port,
> >  +		uint8_t queues[], uint16_t nb_unlinks);
> >  +
> >  +/**
> >  + * Converts nanoseconds to *wait* value for rte_event_dequeue()
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + * @param ns
> >  + *   Wait time in nanosecond
> >  + * @param[out] wait_ticks
> >  + *   Value for the *wait* parameter in rte_event_dequeue() function
> >  + *
> >  + */
> >  +typedef void (*eventdev_dequeue_wait_time_t)(struct rte_eventdev *dev,
> >  +		uint64_t ns, uint64_t *wait_ticks);
> >  +
> >  +/**
> >  + * Dump internal information
> >  + *
> >  + * @param dev
> >  + *   Event device pointer
> >  + * @param f
> >  + *   A pointer to a file for output
> >  + *
> >  + */
> >  +typedef void (*eventdev_dump_t)(struct rte_eventdev *dev, FILE *f);
> >  +
> >  +/** Event device operations function pointer table */
> >  +struct rte_eventdev_ops {
> >  +	eventdev_info_get_t dev_infos_get;	/**< Get device info. */
> >  +	eventdev_configure_t dev_configure;	/**< Configure device. */
> >  +	eventdev_start_t dev_start;		/**< Start device. */
> >  +	eventdev_stop_t dev_stop;		/**< Stop device. */
> >  +	eventdev_close_t dev_close;		/**< Close device. */
> >  +
> >  +	eventdev_queue_default_conf_get_t queue_def_conf;
> >  +	/**< Get default queue configuration. */
> >  +	eventdev_queue_setup_t queue_setup;
> >  +	/**< Set up an event queue. */
> >  +	eventdev_queue_release_t queue_release;
> >  +	/**< Release an event queue. */
> >  +
> >  +	eventdev_port_default_conf_get_t port_def_conf;
> >  +	/**< Get default port configuration. */
> >  +	eventdev_port_setup_t port_setup;
> >  +	/**< Set up an event port. */
> >  +	eventdev_port_release_t port_release;
> >  +	/**< Release an event port. */
> >  +
> >  +	eventdev_port_link_t port_link;
> >  +	/**< Link event queues to an event port. */
> >  +	eventdev_port_unlink_t port_unlink;
> >  +	/**< Unlink event queues from an event port. */
> >  +	eventdev_dequeue_wait_time_t wait_time;
> >  +	/**< Converts nanoseconds to *wait* value for rte_event_dequeue()
> >  */
> >  +	eventdev_dump_t dump;
> >  +	/* Dump internal information */
> >  +};
> >  +
> >  +/**
> >  + * Allocates a new eventdev slot for an event device and returns the pointer
> >  + * to that slot for the driver to use.
> >  + *
> >  + * @param name
> >  + *   Unique identifier name for each device
> >  + * @param socket_id
> >  + *   Socket to allocate resources on.
> >  + * @return
> >  + *   - Slot in the rte_dev_devices array for a new device;
> >  + */
> >  +struct rte_eventdev *
> >  +rte_eventdev_pmd_allocate(const char *name, int socket_id);
> >  +
> >  +/**
> >  + * Release the specified eventdev device.
> >  + *
> >  + * @param eventdev
> >  + * The *eventdev* pointer is the address of the *rte_eventdev* structure.
> >  + * @return
> >  + *   - 0 on success, negative on error
> >  + */
> >  +int
> >  +rte_eventdev_pmd_release(struct rte_eventdev *eventdev);
> >  +
> >  +/**
> >  + * Creates a new virtual event device and returns the pointer to that device.
> >  + *
> >  + * @param name
> >  + *   PMD type name
> >  + * @param dev_private_size
> >  + *   Size of event PMDs private data
> >  + * @param socket_id
> >  + *   Socket to allocate resources on.
> >  + *
> >  + * @return
> >  + *   - Eventdev pointer if device is successfully created.
> >  + *   - NULL if device cannot be created.
> >  + */
> >  +struct rte_eventdev *
> >  +rte_eventdev_pmd_vdev_init(const char *name, size_t dev_private_size,
> >  +		int socket_id);
> >  +
> >  +
> >  +/**
> >  + * Wrapper for use by pci drivers as a .probe function to attach to a event
> >  + * interface.
> >  + */
> >  +int rte_eventdev_pmd_pci_probe(struct rte_pci_driver *pci_drv,
> >  +			    struct rte_pci_device *pci_dev);
> >  +
> >  +/**
> >  + * Wrapper for use by pci drivers as a .remove function to detach a event
> >  + * interface.
> >  + */
> >  +int rte_eventdev_pmd_pci_remove(struct rte_pci_device *pci_dev);
> >  +
> >  +#ifdef __cplusplus
> >  +}
> >  +#endif
> >  +
> >  +#endif /* _RTE_EVENTDEV_PMD_H_ */
> >  diff --git a/lib/librte_eventdev/rte_eventdev_version.map
> >  b/lib/librte_eventdev/rte_eventdev_version.map
> >  new file mode 100644
> >  index 0000000..ef40aae
> >  --- /dev/null
> >  +++ b/lib/librte_eventdev/rte_eventdev_version.map
> >  @@ -0,0 +1,39 @@
> >  +DPDK_17.02 {
> >  +	global:
> >  +
> >  +	rte_eventdevs;
> >  +
> >  +	rte_event_dev_count;
> >  +	rte_event_dev_get_dev_id;
> >  +	rte_event_dev_socket_id;
> >  +	rte_event_dev_info_get;
> >  +	rte_event_dev_configure;
> >  +	rte_event_dev_start;
> >  +	rte_event_dev_stop;
> >  +	rte_event_dev_close;
> >  +	rte_event_dev_dump;
> >  +
> >  +	rte_event_port_default_conf_get;
> >  +	rte_event_port_setup;
> >  +	rte_event_port_dequeue_depth;
> >  +	rte_event_port_enqueue_depth;
> >  +	rte_event_port_count;
> >  +	rte_event_port_link;
> >  +	rte_event_port_unlink;
> >  +	rte_event_port_links_get;
> >  +
> >  +	rte_event_queue_default_conf_get
> >  +	rte_event_queue_setup;
> >  +	rte_event_queue_count;
> >  +	rte_event_queue_priority;
> >  +
> >  +	rte_event_dequeue_wait_time;
> >  +
> >  +	rte_eventdev_pmd_allocate;
> >  +	rte_eventdev_pmd_release;
> >  +	rte_eventdev_pmd_vdev_init;
> >  +	rte_eventdev_pmd_pci_probe;
> >  +	rte_eventdev_pmd_pci_remove;
> >  +
> >  +	local: *;
> >  +};
> >  diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> >  index f75f0e2..716725a 100644
> >  --- a/mk/rte.app.mk
> >  +++ b/mk/rte.app.mk
> >  @@ -93,6 +93,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -
> >  lrte_mbuf
> >   _LDLIBS-$(CONFIG_RTE_LIBRTE_NET)            += -lrte_net
> >   _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lrte_ethdev
> >   _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
> >  +_LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
> >   _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
> >   _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
> >   _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
> >  --
> >  2.5.5
> 

^ permalink raw reply

* [PATCH v2 2/2] net: align ethdev and eal driver names
From: David Marchand @ 2016-11-21 18:06 UTC (permalink / raw)
  To: thomas.monjalon
  Cc: dev, ferruh.yigit, jblunck, linville, declan.doherty, zlu, lsun,
	alejandro.lucero, mtetsuyah, nicolas.pernas.maradei, harish.patil,
	rasesh.mody, sony.chacko, bruce.richardson, huawei.xie,
	yuanhan.liu, jianfeng.tan
In-Reply-To: <1479751574-5704-1-git-send-email-david.marchand@6wind.com>

Some virtual pmds report a different name than the vdev driver name
registered in eal.
While it does not hurt, let's try to be consistent.

Signed-off-by: David Marchand <david.marchand@6wind.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 drivers/net/af_packet/rte_eth_af_packet.c  |  4 +++-
 drivers/net/bonding/rte_eth_bond_api.c     |  7 +++----
 drivers/net/bonding/rte_eth_bond_pmd.c     |  4 ++--
 drivers/net/bonding/rte_eth_bond_private.h |  2 +-
 drivers/net/mpipe/mpipe_tilegx.c           | 21 ++++++++++++++++-----
 drivers/net/null/rte_eth_null.c            |  4 +++-
 drivers/net/pcap/rte_eth_pcap.c            |  4 +++-
 drivers/net/ring/rte_eth_ring.c            |  4 +++-
 drivers/net/vhost/rte_eth_vhost.c          |  4 +++-
 drivers/net/virtio/virtio_ethdev.c         |  6 +++++-
 drivers/net/virtio/virtio_ethdev.h         |  2 ++
 drivers/net/virtio/virtio_user_ethdev.c    |  2 +-
 drivers/net/xenvirt/rte_eth_xenvirt.c      |  3 ++-
 13 files changed, 47 insertions(+), 20 deletions(-)

diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c
index a66a657..8cae165 100644
--- a/drivers/net/af_packet/rte_eth_af_packet.c
+++ b/drivers/net/af_packet/rte_eth_af_packet.c
@@ -437,6 +437,8 @@ open_packet_iface(const char *key __rte_unused,
 	return 0;
 }
 
+static struct rte_vdev_driver pmd_af_packet_drv;
+
 static int
 rte_pmd_init_internals(const char *name,
                        const int sockfd,
@@ -690,7 +692,7 @@ rte_pmd_init_internals(const char *name,
 	(*eth_dev)->dev_ops = &ops;
 	(*eth_dev)->driver = NULL;
 	(*eth_dev)->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
-	(*eth_dev)->data->drv_name = "AF_PACKET PMD";
+	(*eth_dev)->data->drv_name = pmd_af_packet_drv.driver.name;
 	(*eth_dev)->data->kdrv = RTE_KDRV_NONE;
 	(*eth_dev)->data->numa_node = numa_node;
 
diff --git a/drivers/net/bonding/rte_eth_bond_api.c b/drivers/net/bonding/rte_eth_bond_api.c
index 2a3893a..a4e86ae 100644
--- a/drivers/net/bonding/rte_eth_bond_api.c
+++ b/drivers/net/bonding/rte_eth_bond_api.c
@@ -37,6 +37,7 @@
 #include <rte_malloc.h>
 #include <rte_ethdev.h>
 #include <rte_tcp.h>
+#include <rte_vdev.h>
 
 #include "rte_eth_bond.h"
 #include "rte_eth_bond_private.h"
@@ -44,8 +45,6 @@
 
 #define DEFAULT_POLLING_INTERVAL_10_MS (10)
 
-const char pmd_bond_driver_name[] = "rte_bond_pmd";
-
 int
 check_for_bonded_ethdev(const struct rte_eth_dev *eth_dev)
 {
@@ -54,7 +53,7 @@ check_for_bonded_ethdev(const struct rte_eth_dev *eth_dev)
 		return -1;
 
 	/* return 0 if driver name matches */
-	return eth_dev->data->drv_name != pmd_bond_driver_name;
+	return eth_dev->data->drv_name != pmd_bond_drv.driver.name;
 }
 
 int
@@ -221,7 +220,7 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
 		RTE_ETH_DEV_DETACHABLE;
 	eth_dev->driver = NULL;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
-	eth_dev->data->drv_name = pmd_bond_driver_name;
+	eth_dev->data->drv_name = pmd_bond_drv.driver.name;
 	eth_dev->data->numa_node =  socket_id;
 
 	rte_spinlock_init(&internals->lock);
diff --git a/drivers/net/bonding/rte_eth_bond_pmd.c b/drivers/net/bonding/rte_eth_bond_pmd.c
index a80b6fa..9bfd9f6 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -2566,12 +2566,12 @@ bond_ethdev_configure(struct rte_eth_dev *dev)
 	return 0;
 }
 
-static struct rte_vdev_driver bond_drv = {
+struct rte_vdev_driver pmd_bond_drv = {
 	.probe = bond_probe,
 	.remove = bond_remove,
 };
 
-RTE_PMD_REGISTER_VDEV(net_bonding, bond_drv);
+RTE_PMD_REGISTER_VDEV(net_bonding, pmd_bond_drv);
 RTE_PMD_REGISTER_ALIAS(net_bonding, eth_bond);
 
 RTE_PMD_REGISTER_PARAM_STRING(net_bonding,
diff --git a/drivers/net/bonding/rte_eth_bond_private.h b/drivers/net/bonding/rte_eth_bond_private.h
index d95d440..5a411e2 100644
--- a/drivers/net/bonding/rte_eth_bond_private.h
+++ b/drivers/net/bonding/rte_eth_bond_private.h
@@ -63,7 +63,7 @@
 
 extern const char *pmd_bond_init_valid_arguments[];
 
-extern const char pmd_bond_driver_name[];
+extern struct rte_vdev_driver pmd_bond_drv;
 
 /** Port Queue Mapping Structure */
 struct bond_rx_queue {
diff --git a/drivers/net/mpipe/mpipe_tilegx.c b/drivers/net/mpipe/mpipe_tilegx.c
index fbbbb00..f0ba91e 100644
--- a/drivers/net/mpipe/mpipe_tilegx.c
+++ b/drivers/net/mpipe/mpipe_tilegx.c
@@ -87,7 +87,6 @@ struct mpipe_local {
 static __thread struct mpipe_local mpipe_local;
 static struct mpipe_context mpipe_contexts[GXIO_MPIPE_INSTANCE_MAX];
 static int mpipe_instances;
-static const char *drivername = "MPIPE PMD";
 
 /* Per queue statistics. */
 struct mpipe_queue_stats {
@@ -1549,7 +1548,7 @@ mpipe_link_mac(const char *ifname, uint8_t *mac)
 }
 
 static int
-rte_pmd_mpipe_probe(const char *ifname,
+rte_pmd_mpipe_probe_common(struct rte_vdev_driver *drv, const char *ifname,
 		      const char *params __rte_unused)
 {
 	gxio_mpipe_context_t *context;
@@ -1606,7 +1605,7 @@ rte_pmd_mpipe_probe(const char *ifname,
 	eth_dev->data->dev_flags = 0;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
 	eth_dev->driver = NULL;
-	eth_dev->data->drv_name = drivername;
+	eth_dev->data->drv_name = drv->driver.name;
 	eth_dev->data->numa_node = instance;
 
 	eth_dev->dev_ops      = &mpipe_dev_ops;
@@ -1623,12 +1622,24 @@ rte_pmd_mpipe_probe(const char *ifname,
 	return 0;
 }
 
+static int
+rte_pmd_mpipe_xgbe_probe(const char *ifname, const char *params __rte_unused)
+{
+	return rte_pmd_mpipe_probe_common(&pmd_mpipe_xgbe_drv, ifname, params);
+}
+
+static int
+rte_pmd_mpipe_gbe_probe(const char *ifname, const char *params __rte_unused)
+{
+	return rte_pmd_mpipe_probe_common(&pmd_mpipe_gbe_drv, ifname, params);
+}
+
 static struct rte_vdev_driver pmd_mpipe_xgbe_drv = {
-	.probe = rte_pmd_mpipe_probe,
+	.probe = rte_pmd_mpipe_xgbe_probe,
 };
 
 static struct rte_vdev_driver pmd_mpipe_gbe_drv = {
-	.probe = rte_pmd_mpipe_probe,
+	.probe = rte_pmd_mpipe_gbe_probe,
 };
 
 RTE_PMD_REGISTER_VDEV(net_mpipe_xgbe, pmd_mpipe_xgbe_drv);
diff --git a/drivers/net/null/rte_eth_null.c b/drivers/net/null/rte_eth_null.c
index 09d77fd..e4fd68f 100644
--- a/drivers/net/null/rte_eth_null.c
+++ b/drivers/net/null/rte_eth_null.c
@@ -478,6 +478,8 @@ static const struct eth_dev_ops ops = {
 	.rss_hash_conf_get = eth_rss_hash_conf_get
 };
 
+static struct rte_vdev_driver pmd_null_drv;
+
 int
 eth_dev_null_create(const char *name,
 		const unsigned numa_node,
@@ -553,7 +555,7 @@ eth_dev_null_create(const char *name,
 	eth_dev->driver = NULL;
 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	data->kdrv = RTE_KDRV_NONE;
-	data->drv_name = "Null PMD";
+	data->drv_name = pmd_null_drv.driver.name;
 	data->numa_node = numa_node;
 
 	/* finally assign rx and tx ops */
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c
index 8b4fba7..58c326a 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/rte_eth_pcap.c
@@ -788,6 +788,8 @@ open_tx_iface(const char *key, const char *value, void *extra_args)
 	return 0;
 }
 
+static struct rte_vdev_driver pmd_pcap_drv;
+
 static int
 pmd_init_internals(const char *name, const unsigned int nb_rx_queues,
 		const unsigned int nb_tx_queues,
@@ -840,7 +842,7 @@ pmd_init_internals(const char *name, const unsigned int nb_rx_queues,
 	(*eth_dev)->driver = NULL;
 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	data->kdrv = RTE_KDRV_NONE;
-	data->drv_name = "Pcap PMD";
+	data->drv_name = pmd_pcap_drv.driver.name;
 	data->numa_node = numa_node;
 
 	return 0;
diff --git a/drivers/net/ring/rte_eth_ring.c b/drivers/net/ring/rte_eth_ring.c
index 56afaf2..31034cf 100644
--- a/drivers/net/ring/rte_eth_ring.c
+++ b/drivers/net/ring/rte_eth_ring.c
@@ -257,6 +257,8 @@ static const struct eth_dev_ops ops = {
 	.mac_addr_add = eth_mac_addr_add,
 };
 
+static struct rte_vdev_driver pmd_ring_drv;
+
 static int
 do_eth_dev_ring_create(const char *name,
 		struct rte_ring * const rx_queues[], const unsigned nb_rx_queues,
@@ -341,7 +343,7 @@ do_eth_dev_ring_create(const char *name,
 	eth_dev->dev_ops = &ops;
 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	data->kdrv = RTE_KDRV_NONE;
-	data->drv_name = "Rings PMD";
+	data->drv_name = pmd_ring_drv.driver.name;
 	data->numa_node = numa_node;
 
 	TAILQ_INIT(&(eth_dev->link_intr_cbs));
diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index 96bf391..059a74f 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -984,6 +984,8 @@ static const struct eth_dev_ops ops = {
 	.xstats_get_names = vhost_dev_xstats_get_names,
 };
 
+static struct rte_vdev_driver pmd_vhost_drv;
+
 static int
 eth_dev_vhost_create(const char *name, char *iface_name, int16_t queues,
 		     const unsigned numa_node, uint64_t flags)
@@ -1071,7 +1073,7 @@ eth_dev_vhost_create(const char *name, char *iface_name, int16_t queues,
 	data->dev_flags =
 		RTE_ETH_DEV_DETACHABLE | RTE_ETH_DEV_INTR_LSC;
 	data->kdrv = RTE_KDRV_NONE;
-	data->drv_name = internal->dev_name;
+	data->drv_name = pmd_vhost_drv.driver.name;
 	data->numa_node = numa_node;
 
 	/* finally assign rx and tx ops */
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 741688e..dbc4ddb 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -52,6 +52,7 @@
 #include <rte_memory.h>
 #include <rte_eal.h>
 #include <rte_dev.h>
+#include <rte_vdev.h>
 
 #include "virtio_ethdev.h"
 #include "virtio_pci.h"
@@ -1210,7 +1211,10 @@ virtio_init_device(struct rte_eth_dev *eth_dev, uint64_t req_features)
 	else
 		eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 
-	rte_eth_copy_pci_info(eth_dev, pci_dev);
+	if (pci_dev)
+		rte_eth_copy_pci_info(eth_dev, pci_dev);
+	else
+		eth_dev->data->drv_name = virtio_user_driver.driver.name;
 
 	rx_func_get(eth_dev);
 
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index 27d9a19..94b4f43 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -104,4 +104,6 @@ uint16_t virtio_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
 
 int eth_virtio_dev_init(struct rte_eth_dev *eth_dev);
 
+extern struct rte_vdev_driver virtio_user_driver;
+
 #endif /* _VIRTIO_ETHDEV_H_ */
diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c
index 406beea..d3b595b 100644
--- a/drivers/net/virtio/virtio_user_ethdev.c
+++ b/drivers/net/virtio/virtio_user_ethdev.c
@@ -473,7 +473,7 @@ virtio_user_pmd_remove(const char *name)
 	return 0;
 }
 
-static struct rte_vdev_driver virtio_user_driver = {
+struct rte_vdev_driver virtio_user_driver = {
 	.probe = virtio_user_pmd_probe,
 	.remove = virtio_user_pmd_remove,
 };
diff --git a/drivers/net/xenvirt/rte_eth_xenvirt.c b/drivers/net/xenvirt/rte_eth_xenvirt.c
index f74d72c..8321a0b 100644
--- a/drivers/net/xenvirt/rte_eth_xenvirt.c
+++ b/drivers/net/xenvirt/rte_eth_xenvirt.c
@@ -617,6 +617,7 @@ enum dev_action {
 	DEV_ATTACH
 };
 
+static struct rte_vdev_driver pmd_xenvirt_drv;
 
 static int
 eth_dev_xenvirt_create(const char *name, const char *params,
@@ -672,7 +673,7 @@ eth_dev_xenvirt_create(const char *name, const char *params,
 
 	eth_dev->data->dev_flags = RTE_PCI_DRV_DETACHABLE;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
-	eth_dev->data->drv_name = "xen virtio PMD";
+	eth_dev->data->drv_name = pmd_xenvirt_drv.driver.name;
 	eth_dev->driver = NULL;
 	eth_dev->data->numa_node = numa_node;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 1/2] net: remove dead driver names
From: David Marchand @ 2016-11-21 18:06 UTC (permalink / raw)
  To: thomas.monjalon
  Cc: dev, ferruh.yigit, jblunck, linville, declan.doherty, zlu, lsun,
	alejandro.lucero, mtetsuyah, nicolas.pernas.maradei, harish.patil,
	rasesh.mody, sony.chacko, bruce.richardson, huawei.xie,
	yuanhan.liu, jianfeng.tan
In-Reply-To: <1478785884-29273-1-git-send-email-david.marchand@6wind.com>

Since commit b1fb53a39d88 ("ethdev: remove some PCI specific handling"),
rte_eth_dev_info_get() relies on dev->data->drv_name to report the driver
name to caller.

Having the pmds set driver_info->driver_name in the pmds is useless,
since ethdev overwrites it right after.
The only thing the pmd must do is:
- for pci drivers, call rte_eth_copy_pci_info() which then sets
  data->drv_name
- for vdev drivers, manually set data->drv_name

At this stage, virtio-user does not properly report a driver name (fixed in
next commit).

Signed-off-by: David Marchand <david.marchand@6wind.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
Reviewed-by: Jan Blunck <jblunck@infradead.org>
---

Changes since v1:
- fixed commit log (checkpatch warning)
- removed stale variable in qede driver (caught by Jan B.)
---
 drivers/net/af_packet/rte_eth_af_packet.c | 5 +----
 drivers/net/nfp/nfp_net.c                 | 1 -
 drivers/net/null/rte_eth_null.c           | 4 +---
 drivers/net/pcap/rte_eth_pcap.c           | 4 +---
 drivers/net/qede/qede_ethdev.c            | 2 --
 drivers/net/ring/rte_eth_ring.c           | 4 +---
 drivers/net/vhost/rte_eth_vhost.c         | 3 ---
 drivers/net/virtio/virtio_ethdev.c        | 4 ----
 drivers/net/xenvirt/rte_eth_xenvirt.c     | 5 +----
 9 files changed, 5 insertions(+), 27 deletions(-)

diff --git a/drivers/net/af_packet/rte_eth_af_packet.c b/drivers/net/af_packet/rte_eth_af_packet.c
index ff45068..a66a657 100644
--- a/drivers/net/af_packet/rte_eth_af_packet.c
+++ b/drivers/net/af_packet/rte_eth_af_packet.c
@@ -115,8 +115,6 @@ static const char *valid_arguments[] = {
 	NULL
 };
 
-static const char *drivername = "AF_PACKET PMD";
-
 static struct rte_eth_link pmd_link = {
 	.link_speed = ETH_SPEED_NUM_10G,
 	.link_duplex = ETH_LINK_FULL_DUPLEX,
@@ -280,7 +278,6 @@ eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
 	struct pmd_internals *internals = dev->data->dev_private;
 
-	dev_info->driver_name = drivername;
 	dev_info->if_index = internals->if_index;
 	dev_info->max_mac_addrs = 1;
 	dev_info->max_rx_pktlen = (uint32_t)ETH_FRAME_LEN;
@@ -693,7 +690,7 @@ rte_pmd_init_internals(const char *name,
 	(*eth_dev)->dev_ops = &ops;
 	(*eth_dev)->driver = NULL;
 	(*eth_dev)->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
-	(*eth_dev)->data->drv_name = drivername;
+	(*eth_dev)->data->drv_name = "AF_PACKET PMD";
 	(*eth_dev)->data->kdrv = RTE_KDRV_NONE;
 	(*eth_dev)->data->numa_node = numa_node;
 
diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index c6b1587..0c342ab 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -1006,7 +1006,6 @@ nfp_net_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 
 	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-	dev_info->driver_name = dev->driver->pci_drv.driver.name;
 	dev_info->max_rx_queues = (uint16_t)hw->max_rx_queues;
 	dev_info->max_tx_queues = (uint16_t)hw->max_tx_queues;
 	dev_info->min_rx_bufsize = ETHER_MIN_MTU;
diff --git a/drivers/net/null/rte_eth_null.c b/drivers/net/null/rte_eth_null.c
index 836d982..09d77fd 100644
--- a/drivers/net/null/rte_eth_null.c
+++ b/drivers/net/null/rte_eth_null.c
@@ -88,7 +88,6 @@ struct pmd_internals {
 
 
 static struct ether_addr eth_addr = { .addr_bytes = {0} };
-static const char *drivername = "Null PMD";
 static struct rte_eth_link pmd_link = {
 	.link_speed = ETH_SPEED_NUM_10G,
 	.link_duplex = ETH_LINK_FULL_DUPLEX,
@@ -295,7 +294,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 		return;
 
 	internals = dev->data->dev_private;
-	dev_info->driver_name = drivername;
 	dev_info->max_mac_addrs = 1;
 	dev_info->max_rx_pktlen = (uint32_t)-1;
 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
@@ -555,7 +553,7 @@ eth_dev_null_create(const char *name,
 	eth_dev->driver = NULL;
 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	data->kdrv = RTE_KDRV_NONE;
-	data->drv_name = drivername;
+	data->drv_name = "Null PMD";
 	data->numa_node = numa_node;
 
 	/* finally assign rx and tx ops */
diff --git a/drivers/net/pcap/rte_eth_pcap.c b/drivers/net/pcap/rte_eth_pcap.c
index 0162f44..8b4fba7 100644
--- a/drivers/net/pcap/rte_eth_pcap.c
+++ b/drivers/net/pcap/rte_eth_pcap.c
@@ -119,7 +119,6 @@ static struct ether_addr eth_addr = {
 	.addr_bytes = { 0, 0, 0, 0x1, 0x2, 0x3 }
 };
 
-static const char *drivername = "Pcap PMD";
 static struct rte_eth_link pmd_link = {
 		.link_speed = ETH_SPEED_NUM_10G,
 		.link_duplex = ETH_LINK_FULL_DUPLEX,
@@ -552,7 +551,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 {
 	struct pmd_internals *internals = dev->data->dev_private;
 
-	dev_info->driver_name = drivername;
 	dev_info->if_index = internals->if_index;
 	dev_info->max_mac_addrs = 1;
 	dev_info->max_rx_pktlen = (uint32_t) -1;
@@ -842,7 +840,7 @@ pmd_init_internals(const char *name, const unsigned int nb_rx_queues,
 	(*eth_dev)->driver = NULL;
 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	data->kdrv = RTE_KDRV_NONE;
-	data->drv_name = drivername;
+	data->drv_name = "Pcap PMD";
 	data->numa_node = numa_node;
 
 	return 0;
diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index d106dd0..2c600c1 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -12,7 +12,6 @@
 
 /* Globals */
 static const struct qed_eth_ops *qed_ops;
-static const char *drivername = "qede pmd";
 static int64_t timer_period = 1;
 
 struct rte_qede_xstats_name_off {
@@ -663,7 +662,6 @@ qede_dev_info_get(struct rte_eth_dev *eth_dev,
 		dev_info->max_vfs = 0;
 	else
 		dev_info->max_vfs = (uint16_t)NUM_OF_VFS(&qdev->edev);
-	dev_info->driver_name = qdev->drv_ver;
 	dev_info->reta_size = ECORE_RSS_IND_TABLE_SIZE;
 	dev_info->flow_type_rss_offloads = (uint64_t)QEDE_RSS_OFFLOAD_ALL;
 
diff --git a/drivers/net/ring/rte_eth_ring.c b/drivers/net/ring/rte_eth_ring.c
index c1767c4..56afaf2 100644
--- a/drivers/net/ring/rte_eth_ring.c
+++ b/drivers/net/ring/rte_eth_ring.c
@@ -75,7 +75,6 @@ struct pmd_internals {
 };
 
 
-static const char *drivername = "Rings PMD";
 static struct rte_eth_link pmd_link = {
 		.link_speed = ETH_SPEED_NUM_10G,
 		.link_duplex = ETH_LINK_FULL_DUPLEX,
@@ -173,7 +172,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 		struct rte_eth_dev_info *dev_info)
 {
 	struct pmd_internals *internals = dev->data->dev_private;
-	dev_info->driver_name = drivername;
 	dev_info->max_mac_addrs = 1;
 	dev_info->max_rx_pktlen = (uint32_t)-1;
 	dev_info->max_rx_queues = (uint16_t)internals->max_rx_queues;
@@ -343,7 +341,7 @@ do_eth_dev_ring_create(const char *name,
 	eth_dev->dev_ops = &ops;
 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
 	data->kdrv = RTE_KDRV_NONE;
-	data->drv_name = drivername;
+	data->drv_name = "Rings PMD";
 	data->numa_node = numa_node;
 
 	TAILQ_INIT(&(eth_dev->link_intr_cbs));
diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index 766d4ef..96bf391 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -53,8 +53,6 @@
 #define ETH_VHOST_CLIENT_ARG		"client"
 #define ETH_VHOST_DEQUEUE_ZERO_COPY	"dequeue-zero-copy"
 
-static const char *drivername = "VHOST PMD";
-
 static const char *valid_arguments[] = {
 	ETH_VHOST_IFACE_ARG,
 	ETH_VHOST_QUEUES_ARG,
@@ -861,7 +859,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 		return;
 	}
 
-	dev_info->driver_name = drivername;
 	dev_info->max_mac_addrs = 1;
 	dev_info->max_rx_pktlen = (uint32_t)-1;
 	dev_info->max_rx_queues = internal->max_queues;
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 079fd6c..741688e 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1624,10 +1624,6 @@ virtio_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	uint64_t tso_mask;
 	struct virtio_hw *hw = dev->data->dev_private;
 
-	if (dev->pci_dev)
-		dev_info->driver_name = dev->driver->pci_drv.driver.name;
-	else
-		dev_info->driver_name = "virtio_user PMD";
 	dev_info->max_rx_queues =
 		RTE_MIN(hw->max_queue_pairs, VIRTIO_MAX_RX_QUEUES);
 	dev_info->max_tx_queues =
diff --git a/drivers/net/xenvirt/rte_eth_xenvirt.c b/drivers/net/xenvirt/rte_eth_xenvirt.c
index c08a056..f74d72c 100644
--- a/drivers/net/xenvirt/rte_eth_xenvirt.c
+++ b/drivers/net/xenvirt/rte_eth_xenvirt.c
@@ -70,8 +70,6 @@
 /* virtio_idx is increased after new device is created.*/
 static int virtio_idx = 0;
 
-static const char *drivername = "xen virtio PMD";
-
 static struct rte_eth_link pmd_link = {
 		.link_speed = ETH_SPEED_NUM_10G,
 		.link_duplex = ETH_LINK_FULL_DUPLEX,
@@ -331,7 +329,6 @@ eth_dev_info(struct rte_eth_dev *dev,
 	struct pmd_internals *internals = dev->data->dev_private;
 
 	RTE_SET_USED(internals);
-	dev_info->driver_name = drivername;
 	dev_info->max_mac_addrs = 1;
 	dev_info->max_rx_pktlen = (uint32_t)2048;
 	dev_info->max_rx_queues = (uint16_t)1;
@@ -675,7 +672,7 @@ eth_dev_xenvirt_create(const char *name, const char *params,
 
 	eth_dev->data->dev_flags = RTE_PCI_DRV_DETACHABLE;
 	eth_dev->data->kdrv = RTE_KDRV_NONE;
-	eth_dev->data->drv_name = drivername;
+	eth_dev->data->drv_name = "xen virtio PMD";
 	eth_dev->driver = NULL;
 	eth_dev->data->numa_node = numa_node;
 
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH 2/4] eventdev: implement the northbound APIs
From: Eads, Gage @ 2016-11-21 17:45 UTC (permalink / raw)
  To: Jerin Jacob, dev@dpdk.org
  Cc: Richardson, Bruce, Van Haaren, Harry, hemant.agrawal@nxp.com
In-Reply-To: <1479447902-3700-3-git-send-email-jerin.jacob@caviumnetworks.com>

Hi Jerin,

I did a quick review and overall this implementation looks good. I noticed just one issue in rte_event_queue_setup(): the check of nb_atomic_order_sequences is being applied to atomic-type queues, but that field applies to ordered-type queues.

One open issue I noticed is the "typical workflow" description starting in rte_eventdev.h:204 conflicts with the centralized software PMD that Harry posted last week. Specifically, that PMD expects a single core to call the schedule function. We could extend the documentation to account for this alternative style of scheduler invocation, or discuss ways to make the software PMD work with the documented workflow. I prefer the former, but either way I think we ought to expose the scheduler's expected usage to the user -- perhaps through an RTE_EVENT_DEV_CAP flag?

Thanks,
Gage

>  -----Original Message-----
>  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
>  Sent: Thursday, November 17, 2016 11:45 PM
>  To: dev@dpdk.org
>  Cc: Richardson, Bruce <bruce.richardson@intel.com>; Van Haaren, Harry
>  <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com; Eads, Gage
>  <gage.eads@intel.com>; Jerin Jacob <jerin.jacob@caviumnetworks.com>
>  Subject: [dpdk-dev] [PATCH 2/4] eventdev: implement the northbound APIs
>  
>  This patch set defines the southbound driver interface
>  and implements the common code required for northbound
>  eventdev API interface.
>  
>  Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
>  ---
>   config/common_base                           |    6 +
>   lib/Makefile                                 |    1 +
>   lib/librte_eal/common/include/rte_log.h      |    1 +
>   lib/librte_eventdev/Makefile                 |   57 ++
>   lib/librte_eventdev/rte_eventdev.c           | 1211
>  ++++++++++++++++++++++++++
>   lib/librte_eventdev/rte_eventdev_pmd.h       |  504 +++++++++++
>   lib/librte_eventdev/rte_eventdev_version.map |   39 +
>   mk/rte.app.mk                                |    1 +
>   8 files changed, 1820 insertions(+)
>   create mode 100644 lib/librte_eventdev/Makefile
>   create mode 100644 lib/librte_eventdev/rte_eventdev.c
>   create mode 100644 lib/librte_eventdev/rte_eventdev_pmd.h
>   create mode 100644 lib/librte_eventdev/rte_eventdev_version.map
>  
>  diff --git a/config/common_base b/config/common_base
>  index 4bff83a..7a8814e 100644
>  --- a/config/common_base
>  +++ b/config/common_base
>  @@ -411,6 +411,12 @@ CONFIG_RTE_LIBRTE_PMD_ZUC_DEBUG=n
>   CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=y
>  
>   #
>  +# Compile generic event device library
>  +#
>  +CONFIG_RTE_LIBRTE_EVENTDEV=y
>  +CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
>  +CONFIG_RTE_EVENT_MAX_DEVS=16
>  +CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
>   # Compile librte_ring
>   #
>   CONFIG_RTE_LIBRTE_RING=y
>  diff --git a/lib/Makefile b/lib/Makefile
>  index 990f23a..1a067bf 100644
>  --- a/lib/Makefile
>  +++ b/lib/Makefile
>  @@ -41,6 +41,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
>   DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
>   DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
>   DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
>  +DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
>   DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
>   DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
>   DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
>  diff --git a/lib/librte_eal/common/include/rte_log.h
>  b/lib/librte_eal/common/include/rte_log.h
>  index 29f7d19..9a07d92 100644
>  --- a/lib/librte_eal/common/include/rte_log.h
>  +++ b/lib/librte_eal/common/include/rte_log.h
>  @@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
>   #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
>   #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
>   #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to
>  cryptodev. */
>  +#define RTE_LOGTYPE_EVENTDEV 0x00040000 /**< Log related to eventdev.
>  */
>  
>   /* these log types can be used in an application */
>   #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
>  diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
>  new file mode 100644
>  index 0000000..dac0663
>  --- /dev/null
>  +++ b/lib/librte_eventdev/Makefile
>  @@ -0,0 +1,57 @@
>  +#   BSD LICENSE
>  +#
>  +#   Copyright(c) 2016 Cavium networks. All rights reserved.
>  +#
>  +#   Redistribution and use in source and binary forms, with or without
>  +#   modification, are permitted provided that the following conditions
>  +#   are met:
>  +#
>  +#     * Redistributions of source code must retain the above copyright
>  +#       notice, this list of conditions and the following disclaimer.
>  +#     * Redistributions in binary form must reproduce the above copyright
>  +#       notice, this list of conditions and the following disclaimer in
>  +#       the documentation and/or other materials provided with the
>  +#       distribution.
>  +#     * Neither the name of Cavium networks nor the names of its
>  +#       contributors may be used to endorse or promote products derived
>  +#       from this software without specific prior written permission.
>  +#
>  +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
>  CONTRIBUTORS
>  +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
>  NOT
>  +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
>  FITNESS FOR
>  +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
>  COPYRIGHT
>  +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
>  INCIDENTAL,
>  +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
>  NOT
>  +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
>  OF USE,
>  +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
>  ON ANY
>  +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
>  TORT
>  +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
>  THE USE
>  +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
>  DAMAGE.
>  +
>  +include $(RTE_SDK)/mk/rte.vars.mk
>  +
>  +# library name
>  +LIB = librte_eventdev.a
>  +
>  +# library version
>  +LIBABIVER := 1
>  +
>  +# build flags
>  +CFLAGS += -O3
>  +CFLAGS += $(WERROR_FLAGS)
>  +
>  +# library source files
>  +SRCS-y += rte_eventdev.c
>  +
>  +# export include files
>  +SYMLINK-y-include += rte_eventdev.h
>  +SYMLINK-y-include += rte_eventdev_pmd.h
>  +
>  +# versioning export map
>  +EXPORT_MAP := rte_eventdev_version.map
>  +
>  +# library dependencies
>  +DEPDIRS-y += lib/librte_eal
>  +DEPDIRS-y += lib/librte_mbuf
>  +
>  +include $(RTE_SDK)/mk/rte.lib.mk
>  diff --git a/lib/librte_eventdev/rte_eventdev.c
>  b/lib/librte_eventdev/rte_eventdev.c
>  new file mode 100644
>  index 0000000..17ce5c3
>  --- /dev/null
>  +++ b/lib/librte_eventdev/rte_eventdev.c
>  @@ -0,0 +1,1211 @@
>  +/*
>  + *   BSD LICENSE
>  + *
>  + *   Copyright(c) 2016 Cavium networks. All rights reserved.
>  + *
>  + *   Redistribution and use in source and binary forms, with or without
>  + *   modification, are permitted provided that the following conditions
>  + *   are met:
>  + *
>  + *     * Redistributions of source code must retain the above copyright
>  + *       notice, this list of conditions and the following disclaimer.
>  + *     * Redistributions in binary form must reproduce the above copyright
>  + *       notice, this list of conditions and the following disclaimer in
>  + *       the documentation and/or other materials provided with the
>  + *       distribution.
>  + *     * Neither the name of Cavium networks nor the names of its
>  + *       contributors may be used to endorse or promote products derived
>  + *       from this software without specific prior written permission.
>  + *
>  + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
>  CONTRIBUTORS
>  + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
>  NOT
>  + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
>  FITNESS FOR
>  + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
>  COPYRIGHT
>  + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
>  INCIDENTAL,
>  + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
>  NOT
>  + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
>  OF USE,
>  + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
>  AND ON ANY
>  + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
>  TORT
>  + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
>  THE USE
>  + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
>  DAMAGE.
>  + */
>  +
>  +#include <ctype.h>
>  +#include <stdio.h>
>  +#include <stdlib.h>
>  +#include <string.h>
>  +#include <stdarg.h>
>  +#include <errno.h>
>  +#include <stdint.h>
>  +#include <inttypes.h>
>  +#include <sys/types.h>
>  +#include <sys/queue.h>
>  +
>  +#include <rte_byteorder.h>
>  +#include <rte_log.h>
>  +#include <rte_debug.h>
>  +#include <rte_dev.h>
>  +#include <rte_pci.h>
>  +#include <rte_memory.h>
>  +#include <rte_memcpy.h>
>  +#include <rte_memzone.h>
>  +#include <rte_eal.h>
>  +#include <rte_per_lcore.h>
>  +#include <rte_lcore.h>
>  +#include <rte_atomic.h>
>  +#include <rte_branch_prediction.h>
>  +#include <rte_common.h>
>  +#include <rte_malloc.h>
>  +#include <rte_errno.h>
>  +
>  +#include "rte_eventdev.h"
>  +#include "rte_eventdev_pmd.h"
>  +
>  +struct rte_eventdev rte_event_devices[RTE_EVENT_MAX_DEVS];
>  +
>  +struct rte_eventdev *rte_eventdevs = &rte_event_devices[0];
>  +
>  +static struct rte_eventdev_global eventdev_globals = {
>  +	.nb_devs		= 0
>  +};
>  +
>  +struct rte_eventdev_global *rte_eventdev_globals = &eventdev_globals;
>  +
>  +/* Event dev north bound API implementation */
>  +
>  +uint8_t
>  +rte_event_dev_count(void)
>  +{
>  +	return rte_eventdev_globals->nb_devs;
>  +}
>  +
>  +int
>  +rte_event_dev_get_dev_id(const char *name)
>  +{
>  +	int i;
>  +
>  +	if (!name)
>  +		return -EINVAL;
>  +
>  +	for (i = 0; i < rte_eventdev_globals->nb_devs; i++)
>  +		if ((strcmp(rte_event_devices[i].data->name, name)
>  +				== 0) &&
>  +				(rte_event_devices[i].attached ==
>  +						RTE_EVENTDEV_ATTACHED))
>  +			return i;
>  +	return -ENODEV;
>  +}
>  +
>  +int
>  +rte_event_dev_socket_id(uint8_t dev_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +
>  +	return dev->data->socket_id;
>  +}
>  +
>  +int
>  +rte_event_dev_info_get(uint8_t dev_id, struct rte_event_dev_info *dev_info)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +
>  +	if (dev_info == NULL)
>  +		return -EINVAL;
>  +
>  +	memset(dev_info, 0, sizeof(struct rte_event_dev_info));
>  +
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
>  ENOTSUP);
>  +	(*dev->dev_ops->dev_infos_get)(dev, dev_info);
>  +
>  +	dev_info->pci_dev = dev->pci_dev;
>  +	if (dev->driver)
>  +		dev_info->driver_name = dev->driver->pci_drv.driver.name;
>  +	return 0;
>  +}
>  +
>  +static inline int
>  +rte_event_dev_queue_config(struct rte_eventdev *dev, uint8_t nb_queues)
>  +{
>  +	uint8_t old_nb_queues = dev->data->nb_queues;
>  +	void **queues;
>  +	uint8_t *queues_prio;
>  +	unsigned int i;
>  +
>  +	EDEV_LOG_DEBUG("Setup %d queues on device %u", nb_queues,
>  +			 dev->data->dev_id);
>  +
>  +	/* First time configuration */
>  +	if (dev->data->queues == NULL && nb_queues != 0) {
>  +		dev->data->queues = rte_zmalloc_socket("eventdev->data-
>  >queues",
>  +				sizeof(dev->data->queues[0]) * nb_queues,
>  +				RTE_CACHE_LINE_SIZE, dev->data-
>  >socket_id);
>  +		if (dev->data->queues == NULL) {
>  +			dev->data->nb_queues = 0;
>  +			EDEV_LOG_ERR("failed to get memory for queue meta
>  data,"
>  +					"nb_queues %u", nb_queues);
>  +			return -(ENOMEM);
>  +		}
>  +		/* Allocate memory to store queue priority */
>  +		dev->data->queues_prio = rte_zmalloc_socket(
>  +				"eventdev->data->queues_prio",
>  +				sizeof(dev->data->queues_prio[0]) *
>  nb_queues,
>  +				RTE_CACHE_LINE_SIZE, dev->data-
>  >socket_id);
>  +		if (dev->data->queues_prio == NULL) {
>  +			dev->data->nb_queues = 0;
>  +			EDEV_LOG_ERR("failed to get memory for queue
>  priority,"
>  +					"nb_queues %u", nb_queues);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +	} else if (dev->data->queues != NULL && nb_queues != 0) {/* re-config
>  */
>  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
>  >queue_release, -ENOTSUP);
>  +
>  +		queues = dev->data->queues;
>  +		for (i = nb_queues; i < old_nb_queues; i++)
>  +			(*dev->dev_ops->queue_release)(queues[i]);
>  +
>  +		queues = rte_realloc(queues, sizeof(queues[0]) * nb_queues,
>  +				RTE_CACHE_LINE_SIZE);
>  +		if (queues == NULL) {
>  +			EDEV_LOG_ERR("failed to realloc queue meta data,"
>  +						" nb_queues %u",
>  nb_queues);
>  +			return -(ENOMEM);
>  +		}
>  +		dev->data->queues = queues;
>  +
>  +		/* Re allocate memory to store queue priority */
>  +		queues_prio = dev->data->queues_prio;
>  +		queues_prio = rte_realloc(queues_prio,
>  +				sizeof(queues_prio[0]) * nb_queues,
>  +				RTE_CACHE_LINE_SIZE);
>  +		if (queues_prio == NULL) {
>  +			EDEV_LOG_ERR("failed to realloc queue priority,"
>  +						" nb_queues %u",
>  nb_queues);
>  +			return -(ENOMEM);
>  +		}
>  +		dev->data->queues_prio = queues_prio;
>  +
>  +		if (nb_queues > old_nb_queues) {
>  +			uint8_t new_qs = nb_queues - old_nb_queues;
>  +
>  +			memset(queues + old_nb_queues, 0,
>  +				sizeof(queues[0]) * new_qs);
>  +			memset(queues_prio + old_nb_queues, 0,
>  +				sizeof(queues_prio[0]) * new_qs);
>  +		}
>  +	} else if (dev->data->queues != NULL && nb_queues == 0) {
>  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
>  >queue_release, -ENOTSUP);
>  +
>  +		queues = dev->data->queues;
>  +		for (i = nb_queues; i < old_nb_queues; i++)
>  +			(*dev->dev_ops->queue_release)(queues[i]);
>  +	}
>  +
>  +	dev->data->nb_queues = nb_queues;
>  +	return 0;
>  +}
>  +
>  +static inline int
>  +rte_event_dev_port_config(struct rte_eventdev *dev, uint8_t nb_ports)
>  +{
>  +	uint8_t old_nb_ports = dev->data->nb_ports;
>  +	void **ports;
>  +	uint16_t *links_map;
>  +	uint8_t *ports_dequeue_depth;
>  +	uint8_t *ports_enqueue_depth;
>  +	unsigned int i;
>  +
>  +	EDEV_LOG_DEBUG("Setup %d ports on device %u", nb_ports,
>  +			 dev->data->dev_id);
>  +
>  +	/* First time configuration */
>  +	if (dev->data->ports == NULL && nb_ports != 0) {
>  +		dev->data->ports = rte_zmalloc_socket("eventdev->data-
>  >ports",
>  +				sizeof(dev->data->ports[0]) * nb_ports,
>  +				RTE_CACHE_LINE_SIZE, dev->data-
>  >socket_id);
>  +		if (dev->data->ports == NULL) {
>  +			dev->data->nb_ports = 0;
>  +			EDEV_LOG_ERR("failed to get memory for port meta
>  data,"
>  +					"nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +		/* Allocate memory to store ports dequeue depth */
>  +		dev->data->ports_dequeue_depth =
>  +			rte_zmalloc_socket("eventdev-
>  >ports_dequeue_depth",
>  +			sizeof(dev->data->ports_dequeue_depth[0]) *
>  nb_ports,
>  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
>  +		if (dev->data->ports_dequeue_depth == NULL) {
>  +			dev->data->nb_ports = 0;
>  +			EDEV_LOG_ERR("failed to get memory for port deq
>  meta,"
>  +					"nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +		/* Allocate memory to store ports enqueue depth */
>  +		dev->data->ports_enqueue_depth =
>  +			rte_zmalloc_socket("eventdev-
>  >ports_enqueue_depth",
>  +			sizeof(dev->data->ports_enqueue_depth[0]) *
>  nb_ports,
>  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
>  +		if (dev->data->ports_enqueue_depth == NULL) {
>  +			dev->data->nb_ports = 0;
>  +			EDEV_LOG_ERR("failed to get memory for port enq
>  meta,"
>  +					"nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +		/* Allocate memory to store queue to port link connection */
>  +		dev->data->links_map =
>  +			rte_zmalloc_socket("eventdev->links_map",
>  +			sizeof(dev->data->links_map[0]) * nb_ports *
>  +			RTE_EVENT_MAX_QUEUES_PER_DEV,
>  +			RTE_CACHE_LINE_SIZE, dev->data->socket_id);
>  +		if (dev->data->links_map == NULL) {
>  +			dev->data->nb_ports = 0;
>  +			EDEV_LOG_ERR("failed to get memory for port_map
>  area,"
>  +					"nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +	} else if (dev->data->ports != NULL && nb_ports != 0) {/* re-config */
>  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release,
>  -ENOTSUP);
>  +
>  +		ports = dev->data->ports;
>  +		ports_dequeue_depth = dev->data->ports_dequeue_depth;
>  +		ports_enqueue_depth = dev->data->ports_enqueue_depth;
>  +		links_map = dev->data->links_map;
>  +
>  +		for (i = nb_ports; i < old_nb_ports; i++)
>  +			(*dev->dev_ops->port_release)(ports[i]);
>  +
>  +		/* Realloc memory for ports */
>  +		ports = rte_realloc(ports, sizeof(ports[0]) * nb_ports,
>  +				RTE_CACHE_LINE_SIZE);
>  +		if (ports == NULL) {
>  +			EDEV_LOG_ERR("failed to realloc port meta data,"
>  +						" nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +		/* Realloc memory for ports_dequeue_depth */
>  +		ports_dequeue_depth = rte_realloc(ports_dequeue_depth,
>  +			sizeof(ports_dequeue_depth[0]) * nb_ports,
>  +			RTE_CACHE_LINE_SIZE);
>  +		if (ports_dequeue_depth == NULL) {
>  +			EDEV_LOG_ERR("failed to realloc port deqeue meta
>  data,"
>  +						" nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +		/* Realloc memory for ports_enqueue_depth */
>  +		ports_enqueue_depth = rte_realloc(ports_enqueue_depth,
>  +			sizeof(ports_enqueue_depth[0]) * nb_ports,
>  +			RTE_CACHE_LINE_SIZE);
>  +		if (ports_enqueue_depth == NULL) {
>  +			EDEV_LOG_ERR("failed to realloc port enqueue meta
>  data,"
>  +						" nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +		/* Realloc memory to store queue to port link connection */
>  +		links_map = rte_realloc(links_map,
>  +			sizeof(dev->data->links_map[0]) * nb_ports *
>  +			RTE_EVENT_MAX_QUEUES_PER_DEV,
>  +			RTE_CACHE_LINE_SIZE);
>  +		if (dev->data->links_map == NULL) {
>  +			dev->data->nb_ports = 0;
>  +			EDEV_LOG_ERR("failed to realloc mem for port_map
>  area,"
>  +					"nb_ports %u", nb_ports);
>  +			return -(ENOMEM);
>  +		}
>  +
>  +		if (nb_ports > old_nb_ports) {
>  +			uint8_t new_ps = nb_ports - old_nb_ports;
>  +
>  +			memset(ports + old_nb_ports, 0,
>  +				sizeof(ports[0]) * new_ps);
>  +			memset(ports_dequeue_depth + old_nb_ports, 0,
>  +				sizeof(ports_dequeue_depth[0]) * new_ps);
>  +			memset(ports_enqueue_depth + old_nb_ports, 0,
>  +				sizeof(ports_enqueue_depth[0]) * new_ps);
>  +			memset(links_map +
>  +				(old_nb_ports *
>  RTE_EVENT_MAX_QUEUES_PER_DEV),
>  +				0, sizeof(ports_enqueue_depth[0]) * new_ps);
>  +		}
>  +
>  +		dev->data->ports = ports;
>  +		dev->data->ports_dequeue_depth = ports_dequeue_depth;
>  +		dev->data->ports_enqueue_depth = ports_enqueue_depth;
>  +		dev->data->links_map = links_map;
>  +	} else if (dev->data->ports != NULL && nb_ports == 0) {
>  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_release,
>  -ENOTSUP);
>  +
>  +		ports = dev->data->ports;
>  +		for (i = nb_ports; i < old_nb_ports; i++)
>  +			(*dev->dev_ops->port_release)(ports[i]);
>  +	}
>  +
>  +	dev->data->nb_ports = nb_ports;
>  +	return 0;
>  +}
>  +
>  +int
>  +rte_event_dev_configure(uint8_t dev_id, struct rte_event_dev_config
>  *dev_conf)
>  +{
>  +	struct rte_eventdev *dev;
>  +	struct rte_event_dev_info info;
>  +	int diag;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
>  ENOTSUP);
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -
>  ENOTSUP);
>  +
>  +	if (dev->data->dev_started) {
>  +		EDEV_LOG_ERR(
>  +		    "device %d must be stopped to allow configuration",
>  dev_id);
>  +		return -EBUSY;
>  +	}
>  +
>  +	if (dev_conf == NULL)
>  +		return -EINVAL;
>  +
>  +	(*dev->dev_ops->dev_infos_get)(dev, &info);
>  +
>  +	/* Check dequeue_wait_ns value is in limit */
>  +	if (!dev_conf->event_dev_cfg &
>  RTE_EVENT_DEV_CFG_PER_DEQUEUE_WAIT) {
>  +		if (dev_conf->dequeue_wait_ns < info.min_dequeue_wait_ns
>  ||
>  +			dev_conf->dequeue_wait_ns >
>  info.max_dequeue_wait_ns) {
>  +			EDEV_LOG_ERR("dev%d invalid dequeue_wait_ns=%d"
>  +			" min_dequeue_wait_ns=%d
>  max_dequeue_wait_ns=%d",
>  +			dev_id, dev_conf->dequeue_wait_ns,
>  +			info.min_dequeue_wait_ns,
>  +			info.max_dequeue_wait_ns);
>  +			return -EINVAL;
>  +		}
>  +	}
>  +
>  +	/* Check nb_events_limit is in limit */
>  +	if (dev_conf->nb_events_limit > info.max_num_events) {
>  +		EDEV_LOG_ERR("dev%d nb_events_limit=%d >
>  max_num_events=%d",
>  +		dev_id, dev_conf->nb_events_limit, info.max_num_events);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check nb_event_queues is in limit */
>  +	if (!dev_conf->nb_event_queues) {
>  +		EDEV_LOG_ERR("dev%d nb_event_queues cannot be zero",
>  dev_id);
>  +		return -EINVAL;
>  +	}
>  +	if (dev_conf->nb_event_queues > info.max_event_queues) {
>  +		EDEV_LOG_ERR("dev%d nb_event_queues=%d >
>  max_event_queues=%d",
>  +		dev_id, dev_conf->nb_event_queues,
>  info.max_event_queues);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check nb_event_ports is in limit */
>  +	if (!dev_conf->nb_event_ports) {
>  +		EDEV_LOG_ERR("dev%d nb_event_ports cannot be zero",
>  dev_id);
>  +		return -EINVAL;
>  +	}
>  +	if (dev_conf->nb_event_ports > info.max_event_ports) {
>  +		EDEV_LOG_ERR("dev%d nb_event_ports=%d >
>  max_event_ports= %d",
>  +		dev_id, dev_conf->nb_event_ports, info.max_event_ports);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check nb_event_queue_flows is in limit */
>  +	if (!dev_conf->nb_event_queue_flows) {
>  +		EDEV_LOG_ERR("dev%d nb_flows cannot be zero", dev_id);
>  +		return -EINVAL;
>  +	}
>  +	if (dev_conf->nb_event_queue_flows > info.max_event_queue_flows)
>  {
>  +		EDEV_LOG_ERR("dev%d nb_flows=%x > max_flows=%x",
>  +		dev_id, dev_conf->nb_event_queue_flows,
>  +		info.max_event_queue_flows);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check nb_event_port_dequeue_depth is in limit */
>  +	if (!dev_conf->nb_event_port_dequeue_depth) {
>  +		EDEV_LOG_ERR("dev%d nb_dequeue_depth cannot be zero",
>  dev_id);
>  +		return -EINVAL;
>  +	}
>  +	if (dev_conf->nb_event_port_dequeue_depth >
>  +			 info.max_event_port_dequeue_depth) {
>  +		EDEV_LOG_ERR("dev%d nb_dequeue_depth=%d >
>  max_dequeue_depth=%d",
>  +		dev_id, dev_conf->nb_event_port_dequeue_depth,
>  +		info.max_event_port_dequeue_depth);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check nb_event_port_enqueue_depth is in limit */
>  +	if (!dev_conf->nb_event_port_enqueue_depth) {
>  +		EDEV_LOG_ERR("dev%d nb_enqueue_depth cannot be zero",
>  dev_id);
>  +		return -EINVAL;
>  +	}
>  +	if (dev_conf->nb_event_port_enqueue_depth >
>  +			 info.max_event_port_enqueue_depth) {
>  +		EDEV_LOG_ERR("dev%d nb_enqueue_depth=%d >
>  max_enqueue_depth=%d",
>  +		dev_id, dev_conf->nb_event_port_enqueue_depth,
>  +		info.max_event_port_enqueue_depth);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Copy the dev_conf parameter into the dev structure */
>  +	memcpy(&dev->data->dev_conf, dev_conf, sizeof(dev->data-
>  >dev_conf));
>  +
>  +	/* Setup new number of queues and reconfigure device. */
>  +	diag = rte_event_dev_queue_config(dev, dev_conf-
>  >nb_event_queues);
>  +	if (diag != 0) {
>  +		EDEV_LOG_ERR("dev%d rte_event_dev_queue_config = %d",
>  +				dev_id, diag);
>  +		return diag;
>  +	}
>  +
>  +	/* Setup new number of ports and reconfigure device. */
>  +	diag = rte_event_dev_port_config(dev, dev_conf->nb_event_ports);
>  +	if (diag != 0) {
>  +		rte_event_dev_queue_config(dev, 0);
>  +		EDEV_LOG_ERR("dev%d rte_event_dev_port_config = %d",
>  +				dev_id, diag);
>  +		return diag;
>  +	}
>  +
>  +	/* Configure the device */
>  +	diag = (*dev->dev_ops->dev_configure)(dev);
>  +	if (diag != 0) {
>  +		EDEV_LOG_ERR("dev%d dev_configure = %d", dev_id, diag);
>  +		rte_event_dev_queue_config(dev, 0);
>  +		rte_event_dev_port_config(dev, 0);
>  +	}
>  +
>  +	dev->data->event_dev_cap = info.event_dev_cap;
>  +	return diag;
>  +}
>  +
>  +static inline int
>  +is_valid_queue(struct rte_eventdev *dev, uint8_t queue_id)
>  +{
>  +	if (queue_id < dev->data->nb_queues && queue_id <
>  +				RTE_EVENT_MAX_QUEUES_PER_DEV)
>  +		return 1;
>  +	else
>  +		return 0;
>  +}
>  +
>  +int
>  +rte_event_queue_default_conf_get(uint8_t dev_id, uint8_t queue_id,
>  +				 struct rte_event_queue_conf *queue_conf)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +
>  +	if (queue_conf == NULL)
>  +		return -EINVAL;
>  +
>  +	if (!is_valid_queue(dev, queue_id)) {
>  +		EDEV_LOG_ERR("Invalid queue_id=%" PRIu8, queue_id);
>  +		return -EINVAL;
>  +	}
>  +
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_def_conf, -
>  ENOTSUP);
>  +	memset(queue_conf, 0, sizeof(struct rte_event_queue_conf));
>  +	(*dev->dev_ops->queue_def_conf)(dev, queue_id, queue_conf);
>  +	return 0;
>  +}
>  +
>  +static inline int
>  +is_valid_atomic_queue_conf(struct rte_event_queue_conf *queue_conf)
>  +{
>  +	if (queue_conf && (
>  +		((queue_conf->event_queue_cfg &
>  RTE_EVENT_QUEUE_CFG_TYPE_MASK)
>  +			== RTE_EVENT_QUEUE_CFG_ALL_TYPES) ||
>  +		((queue_conf->event_queue_cfg &
>  RTE_EVENT_QUEUE_CFG_TYPE_MASK)
>  +			== RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY)
>  +		))
>  +		return 1;
>  +	else
>  +		return 0;
>  +}
>  +
>  +int
>  +rte_event_queue_setup(uint8_t dev_id, uint8_t queue_id,
>  +		      struct rte_event_queue_conf *queue_conf)
>  +{
>  +	struct rte_eventdev *dev;
>  +	struct rte_event_queue_conf def_conf;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +
>  +	if (!is_valid_queue(dev, queue_id)) {
>  +		EDEV_LOG_ERR("Invalid queue_id=%" PRIu8, queue_id);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check nb_atomic_flows limit */
>  +	if (is_valid_atomic_queue_conf(queue_conf)) {
>  +		if (queue_conf->nb_atomic_flows == 0 ||
>  +		    queue_conf->nb_atomic_flows >
>  +			dev->data->dev_conf.nb_event_queue_flows) {
>  +			EDEV_LOG_ERR(
>  +		"dev%d queue%d Invalid nb_atomic_flows=%d
>  max_flows=%d",
>  +			dev_id, queue_id, queue_conf->nb_atomic_flows,
>  +			dev->data->dev_conf.nb_event_queue_flows);
>  +			return -EINVAL;
>  +		}
>  +	}
>  +
>  +	/* Check nb_atomic_order_sequences limit */
>  +	if (is_valid_atomic_queue_conf(queue_conf)) {
>  +		if (queue_conf->nb_atomic_order_sequences == 0 ||
>  +		    queue_conf->nb_atomic_order_sequences >
>  +			dev->data->dev_conf.nb_event_queue_flows) {
>  +			EDEV_LOG_ERR(
>  +		"dev%d queue%d Invalid nb_atomic_order_seq=%d
>  max_flows=%d",
>  +			dev_id, queue_id, queue_conf-
>  >nb_atomic_order_sequences,
>  +			dev->data->dev_conf.nb_event_queue_flows);
>  +			return -EINVAL;
>  +		}
>  +	}
>  +
>  +	if (dev->data->dev_started) {
>  +		EDEV_LOG_ERR(
>  +		    "device %d must be stopped to allow queue setup", dev_id);
>  +		return -EBUSY;
>  +	}
>  +
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_setup, -
>  ENOTSUP);
>  +
>  +	if (queue_conf == NULL) {
>  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
>  >queue_def_conf,
>  +					-ENOTSUP);
>  +		(*dev->dev_ops->queue_def_conf)(dev, queue_id, &def_conf);
>  +		def_conf.event_queue_cfg =
>  RTE_EVENT_QUEUE_CFG_DEFAULT;
>  +		queue_conf = &def_conf;
>  +	}
>  +
>  +	dev->data->queues_prio[queue_id] = queue_conf->priority;
>  +	return (*dev->dev_ops->queue_setup)(dev, queue_id, queue_conf);
>  +}
>  +
>  +uint8_t
>  +rte_event_queue_count(uint8_t dev_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	dev = &rte_eventdevs[dev_id];
>  +	return dev->data->nb_queues;
>  +}
>  +
>  +uint8_t
>  +rte_event_queue_priority(uint8_t dev_id, uint8_t queue_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	dev = &rte_eventdevs[dev_id];
>  +	if (dev->data->event_dev_cap & RTE_EVENT_DEV_CAP_QUEUE_QOS)
>  +		return dev->data->queues_prio[queue_id];
>  +	else
>  +		return RTE_EVENT_QUEUE_PRIORITY_NORMAL;
>  +}
>  +
>  +static inline int
>  +is_valid_port(struct rte_eventdev *dev, uint8_t port_id)
>  +{
>  +	if (port_id < dev->data->nb_ports)
>  +		return 1;
>  +	else
>  +		return 0;
>  +}
>  +
>  +int
>  +rte_event_port_default_conf_get(uint8_t dev_id, uint8_t port_id,
>  +				 struct rte_event_port_conf *port_conf)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +
>  +	if (port_conf == NULL)
>  +		return -EINVAL;
>  +
>  +	if (!is_valid_port(dev, port_id)) {
>  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
>  +		return -EINVAL;
>  +	}
>  +
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_def_conf, -
>  ENOTSUP);
>  +	memset(port_conf, 0, sizeof(struct rte_event_port_conf));
>  +	(*dev->dev_ops->port_def_conf)(dev, port_id, port_conf);
>  +	return 0;
>  +}
>  +
>  +int
>  +rte_event_port_setup(uint8_t dev_id, uint8_t port_id,
>  +		      struct rte_event_port_conf *port_conf)
>  +{
>  +	struct rte_eventdev *dev;
>  +	struct rte_event_port_conf def_conf;
>  +	int diag;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +
>  +	if (!is_valid_port(dev, port_id)) {
>  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check new_event_threshold limit */
>  +	if ((port_conf && !port_conf->new_event_threshold) ||
>  +			(port_conf && port_conf->new_event_threshold >
>  +				 dev->data->dev_conf.nb_events_limit)) {
>  +		EDEV_LOG_ERR(
>  +		   "dev%d port%d Invalid event_threshold=%d
>  nb_events_limit=%d",
>  +			dev_id, port_id, port_conf->new_event_threshold,
>  +			dev->data->dev_conf.nb_events_limit);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check dequeue_depth limit */
>  +	if ((port_conf && !port_conf->dequeue_depth) ||
>  +			(port_conf && port_conf->dequeue_depth >
>  +		dev->data->dev_conf.nb_event_port_dequeue_depth)) {
>  +		EDEV_LOG_ERR(
>  +		   "dev%d port%d Invalid dequeue depth=%d
>  max_dequeue_depth=%d",
>  +			dev_id, port_id, port_conf->dequeue_depth,
>  +			dev->data-
>  >dev_conf.nb_event_port_dequeue_depth);
>  +		return -EINVAL;
>  +	}
>  +
>  +	/* Check enqueue_depth limit */
>  +	if ((port_conf && !port_conf->enqueue_depth) ||
>  +			(port_conf && port_conf->enqueue_depth >
>  +		dev->data->dev_conf.nb_event_port_enqueue_depth)) {
>  +		EDEV_LOG_ERR(
>  +		   "dev%d port%d Invalid enqueue depth=%d
>  max_enqueue_depth=%d",
>  +			dev_id, port_id, port_conf->enqueue_depth,
>  +			dev->data-
>  >dev_conf.nb_event_port_enqueue_depth);
>  +		return -EINVAL;
>  +	}
>  +
>  +	if (dev->data->dev_started) {
>  +		EDEV_LOG_ERR(
>  +		    "device %d must be stopped to allow port setup", dev_id);
>  +		return -EBUSY;
>  +	}
>  +
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_setup, -
>  ENOTSUP);
>  +
>  +	if (port_conf == NULL) {
>  +		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
>  >port_def_conf,
>  +					-ENOTSUP);
>  +		(*dev->dev_ops->port_def_conf)(dev, port_id, &def_conf);
>  +		port_conf = &def_conf;
>  +	}
>  +
>  +	dev->data->ports_dequeue_depth[port_id] =
>  +			port_conf->dequeue_depth;
>  +	dev->data->ports_enqueue_depth[port_id] =
>  +			port_conf->enqueue_depth;
>  +
>  +	diag = (*dev->dev_ops->port_setup)(dev, port_id, port_conf);
>  +
>  +	/* Unlink all the queues from this port(default state after setup) */
>  +	if (!diag)
>  +		diag = rte_event_port_unlink(dev_id, port_id, NULL, 0);
>  +
>  +	if (diag < 0)
>  +		return diag;
>  +
>  +	return 0;
>  +}
>  +
>  +uint8_t
>  +rte_event_port_dequeue_depth(uint8_t dev_id, uint8_t port_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	dev = &rte_eventdevs[dev_id];
>  +	return dev->data->ports_dequeue_depth[port_id];
>  +}
>  +
>  +uint8_t
>  +rte_event_port_enqueue_depth(uint8_t dev_id, uint8_t port_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	dev = &rte_eventdevs[dev_id];
>  +	return dev->data->ports_enqueue_depth[port_id];
>  +}
>  +
>  +uint8_t
>  +rte_event_port_count(uint8_t dev_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	dev = &rte_eventdevs[dev_id];
>  +	return dev->data->nb_ports;
>  +}
>  +
>  +int
>  +rte_event_port_link(uint8_t dev_id, uint8_t port_id,
>  +		    struct rte_event_queue_link link[], uint16_t nb_links)
>  +{
>  +	struct rte_eventdev *dev;
>  +	struct rte_event_queue_link
>  all_queues[RTE_EVENT_MAX_QUEUES_PER_DEV];
>  +	uint16_t *links_map;
>  +	int i, diag;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_link, -ENOTSUP);
>  +
>  +	if (!is_valid_port(dev, port_id)) {
>  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
>  +		return -EINVAL;
>  +	}
>  +
>  +	if (link == NULL) {
>  +		for (i = 0; i < dev->data->nb_queues; i++) {
>  +			all_queues[i].queue_id = i;
>  +			all_queues[i].priority =
>  +
>  	RTE_EVENT_QUEUE_SERVICE_PRIORITY_NORMAL;
>  +		}
>  +		link = all_queues;
>  +		nb_links = dev->data->nb_queues;
>  +	}
>  +
>  +	for (i = 0; i < nb_links; i++)
>  +		if (link[i].queue_id >= RTE_EVENT_MAX_QUEUES_PER_DEV)
>  +			return -EINVAL;
>  +
>  +	diag = (*dev->dev_ops->port_link)(dev->data->ports[port_id], link,
>  +						 nb_links);
>  +	if (diag < 0)
>  +		return diag;
>  +
>  +	links_map = dev->data->links_map;
>  +	/* Point links_map to this port specific area */
>  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
>  +	for (i = 0; i < diag; i++)
>  +		links_map[link[i].queue_id] = (uint8_t)link[i].priority;
>  +
>  +	return diag;
>  +}
>  +
>  +#define EVENT_QUEUE_SERVICE_PRIORITY_INVALID (0xdead)
>  +
>  +int
>  +rte_event_port_unlink(uint8_t dev_id, uint8_t port_id,
>  +		      uint8_t queues[], uint16_t nb_unlinks)
>  +{
>  +	struct rte_eventdev *dev;
>  +	uint8_t all_queues[RTE_EVENT_MAX_QUEUES_PER_DEV];
>  +	int i, diag;
>  +	uint16_t *links_map;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->port_unlink, -
>  ENOTSUP);
>  +
>  +	if (!is_valid_port(dev, port_id)) {
>  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
>  +		return -EINVAL;
>  +	}
>  +
>  +	if (queues == NULL) {
>  +		for (i = 0; i < dev->data->nb_queues; i++)
>  +			all_queues[i] = i;
>  +		queues = all_queues;
>  +		nb_unlinks = dev->data->nb_queues;
>  +	}
>  +
>  +	for (i = 0; i < nb_unlinks; i++)
>  +		if (queues[i] >= RTE_EVENT_MAX_QUEUES_PER_DEV)
>  +			return -EINVAL;
>  +
>  +	diag = (*dev->dev_ops->port_unlink)(dev->data->ports[port_id],
>  queues,
>  +					nb_unlinks);
>  +
>  +	if (diag < 0)
>  +		return diag;
>  +
>  +	links_map = dev->data->links_map;
>  +	/* Point links_map to this port specific area */
>  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
>  +	for (i = 0; i < diag; i++)
>  +		links_map[queues[i]] =
>  EVENT_QUEUE_SERVICE_PRIORITY_INVALID;
>  +
>  +	return diag;
>  +}
>  +
>  +int
>  +rte_event_port_links_get(uint8_t dev_id, uint8_t port_id,
>  +			struct rte_event_queue_link link[])
>  +{
>  +	struct rte_eventdev *dev;
>  +	uint16_t *links_map;
>  +	int i, count = 0;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +	if (!is_valid_port(dev, port_id)) {
>  +		EDEV_LOG_ERR("Invalid port_id=%" PRIu8, port_id);
>  +		return -EINVAL;
>  +	}
>  +
>  +	links_map = dev->data->links_map;
>  +	/* Point links_map to this port specific area */
>  +	links_map += (port_id * RTE_EVENT_MAX_QUEUES_PER_DEV);
>  +	for (i = 0; i < RTE_EVENT_MAX_QUEUES_PER_DEV; i++) {
>  +		if (links_map[i] !=
>  EVENT_QUEUE_SERVICE_PRIORITY_INVALID) {
>  +			link[count].queue_id = i;
>  +			link[count].priority = (uint8_t)links_map[i];
>  +			++count;
>  +		}
>  +	}
>  +	return count;
>  +}
>  +
>  +int
>  +rte_event_dequeue_wait_time(uint8_t dev_id, uint64_t ns, uint64_t
>  *wait_ticks)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->wait_time, -
>  ENOTSUP);
>  +
>  +	if (wait_ticks == NULL)
>  +		return -EINVAL;
>  +
>  +	(*dev->dev_ops->wait_time)(dev, ns, wait_ticks);
>  +	return 0;
>  +}
>  +
>  +int
>  +rte_event_dev_dump(uint8_t dev_id, FILE *f)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dump, -ENOTSUP);
>  +
>  +	(*dev->dev_ops->dump)(dev, f);
>  +	return 0;
>  +
>  +}
>  +
>  +int
>  +rte_event_dev_start(uint8_t dev_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +	int diag;
>  +
>  +	EDEV_LOG_DEBUG("Start dev_id=%" PRIu8, dev_id);
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_start, -ENOTSUP);
>  +
>  +	if (dev->data->dev_started != 0) {
>  +		EDEV_LOG_ERR("Device with dev_id=%" PRIu8 " already
>  started",
>  +			dev_id);
>  +		return 0;
>  +	}
>  +
>  +	diag = (*dev->dev_ops->dev_start)(dev);
>  +	if (diag == 0)
>  +		dev->data->dev_started = 1;
>  +	else
>  +		return diag;
>  +
>  +	return 0;
>  +}
>  +
>  +void
>  +rte_event_dev_stop(uint8_t dev_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	EDEV_LOG_DEBUG("Stop dev_id=%" PRIu8, dev_id);
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_RET(dev_id);
>  +	dev = &rte_eventdevs[dev_id];
>  +	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_stop);
>  +
>  +	if (dev->data->dev_started == 0) {
>  +		EDEV_LOG_ERR("Device with dev_id=%" PRIu8 " already
>  stopped",
>  +			dev_id);
>  +		return;
>  +	}
>  +
>  +	dev->data->dev_started = 0;
>  +	(*dev->dev_ops->dev_stop)(dev);
>  +}
>  +
>  +int
>  +rte_event_dev_close(uint8_t dev_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
>  +	dev = &rte_eventdevs[dev_id];
>  +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -
>  ENOTSUP);
>  +
>  +	/* Device must be stopped before it can be closed */
>  +	if (dev->data->dev_started == 1) {
>  +		EDEV_LOG_ERR("Device %u must be stopped before closing",
>  +				dev_id);
>  +		return -EBUSY;
>  +	}
>  +
>  +	return (*dev->dev_ops->dev_close)(dev);
>  +}
>  +
>  +static inline int
>  +rte_eventdev_data_alloc(uint8_t dev_id, struct rte_eventdev_data **data,
>  +		int socket_id)
>  +{
>  +	char mz_name[RTE_EVENTDEV_NAME_MAX_LEN];
>  +	const struct rte_memzone *mz;
>  +	int n;
>  +
>  +	/* Generate memzone name */
>  +	n = snprintf(mz_name, sizeof(mz_name), "rte_eventdev_data_%u",
>  dev_id);
>  +	if (n >= (int)sizeof(mz_name))
>  +		return -EINVAL;
>  +
>  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
>  +		mz = rte_memzone_reserve(mz_name,
>  +				sizeof(struct rte_eventdev_data),
>  +				socket_id, 0);
>  +	} else
>  +		mz = rte_memzone_lookup(mz_name);
>  +
>  +	if (mz == NULL)
>  +		return -ENOMEM;
>  +
>  +	*data = mz->addr;
>  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>  +		memset(*data, 0, sizeof(struct rte_eventdev_data));
>  +
>  +	return 0;
>  +}
>  +
>  +static uint8_t
>  +rte_eventdev_find_free_device_index(void)
>  +{
>  +	uint8_t dev_id;
>  +
>  +	for (dev_id = 0; dev_id < RTE_EVENT_MAX_DEVS; dev_id++) {
>  +		if (rte_eventdevs[dev_id].attached ==
>  +				RTE_EVENTDEV_DETACHED)
>  +			return dev_id;
>  +	}
>  +	return RTE_EVENT_MAX_DEVS;
>  +}
>  +
>  +struct rte_eventdev *
>  +rte_eventdev_pmd_allocate(const char *name, int socket_id)
>  +{
>  +	struct rte_eventdev *eventdev;
>  +	uint8_t dev_id;
>  +
>  +	if (rte_eventdev_pmd_get_named_dev(name) != NULL) {
>  +		EDEV_LOG_ERR("Event device with name %s already "
>  +				"allocated!", name);
>  +		return NULL;
>  +	}
>  +
>  +	dev_id = rte_eventdev_find_free_device_index();
>  +	if (dev_id == RTE_EVENT_MAX_DEVS) {
>  +		EDEV_LOG_ERR("Reached maximum number of event
>  devices");
>  +		return NULL;
>  +	}
>  +
>  +	eventdev = &rte_eventdevs[dev_id];
>  +
>  +	if (eventdev->data == NULL) {
>  +		struct rte_eventdev_data *eventdev_data = NULL;
>  +
>  +		int retval = rte_eventdev_data_alloc(dev_id, &eventdev_data,
>  +				socket_id);
>  +
>  +		if (retval < 0 || eventdev_data == NULL)
>  +			return NULL;
>  +
>  +		eventdev->data = eventdev_data;
>  +
>  +		snprintf(eventdev->data->name,
>  RTE_EVENTDEV_NAME_MAX_LEN,
>  +				"%s", name);
>  +
>  +		eventdev->data->dev_id = dev_id;
>  +		eventdev->data->socket_id = socket_id;
>  +		eventdev->data->dev_started = 0;
>  +
>  +		eventdev->attached = RTE_EVENTDEV_ATTACHED;
>  +
>  +		eventdev_globals.nb_devs++;
>  +	}
>  +
>  +	return eventdev;
>  +}
>  +
>  +int
>  +rte_eventdev_pmd_release(struct rte_eventdev *eventdev)
>  +{
>  +	int ret;
>  +
>  +	if (eventdev == NULL)
>  +		return -EINVAL;
>  +
>  +	ret = rte_event_dev_close(eventdev->data->dev_id);
>  +	if (ret < 0)
>  +		return ret;
>  +
>  +	eventdev->attached = RTE_EVENTDEV_DETACHED;
>  +	eventdev_globals.nb_devs--;
>  +	eventdev->data = NULL;
>  +
>  +	return 0;
>  +}
>  +
>  +struct rte_eventdev *
>  +rte_eventdev_pmd_vdev_init(const char *name, size_t dev_private_size,
>  +		int socket_id)
>  +{
>  +	struct rte_eventdev *eventdev;
>  +
>  +	/* Allocate device structure */
>  +	eventdev = rte_eventdev_pmd_allocate(name, socket_id);
>  +	if (eventdev == NULL)
>  +		return NULL;
>  +
>  +	/* Allocate private device structure */
>  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
>  +		eventdev->data->dev_private =
>  +				rte_zmalloc_socket("eventdev device private",
>  +						dev_private_size,
>  +						RTE_CACHE_LINE_SIZE,
>  +						socket_id);
>  +
>  +		if (eventdev->data->dev_private == NULL)
>  +			rte_panic("Cannot allocate memzone for private
>  device"
>  +					" data");
>  +	}
>  +
>  +	return eventdev;
>  +}
>  +
>  +int
>  +rte_eventdev_pmd_pci_probe(struct rte_pci_driver *pci_drv,
>  +			struct rte_pci_device *pci_dev)
>  +{
>  +	struct rte_eventdev_driver *eventdrv;
>  +	struct rte_eventdev *eventdev;
>  +
>  +	char eventdev_name[RTE_EVENTDEV_NAME_MAX_LEN];
>  +
>  +	int retval;
>  +
>  +	eventdrv = (struct rte_eventdev_driver *)pci_drv;
>  +	if (eventdrv == NULL)
>  +		return -ENODEV;
>  +
>  +	rte_eal_pci_device_name(&pci_dev->addr, eventdev_name,
>  +			sizeof(eventdev_name));
>  +
>  +	eventdev = rte_eventdev_pmd_allocate(eventdev_name,
>  +			 pci_dev->device.numa_node);
>  +	if (eventdev == NULL)
>  +		return -ENOMEM;
>  +
>  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
>  +		eventdev->data->dev_private =
>  +				rte_zmalloc_socket(
>  +						"eventdev private structure",
>  +						eventdrv->dev_private_size,
>  +						RTE_CACHE_LINE_SIZE,
>  +						rte_socket_id());
>  +
>  +		if (eventdev->data->dev_private == NULL)
>  +			rte_panic("Cannot allocate memzone for private "
>  +					"device data");
>  +	}
>  +
>  +	eventdev->pci_dev = pci_dev;
>  +	eventdev->driver = eventdrv;
>  +
>  +	/* Invoke PMD device initialization function */
>  +	retval = (*eventdrv->eventdev_init)(eventdev);
>  +	if (retval == 0)
>  +		return 0;
>  +
>  +	EDEV_LOG_ERR("driver %s: event_dev_init(vendor_id=0x%x
>  device_id=0x%x)"
>  +			" failed", pci_drv->driver.name,
>  +			(unsigned int) pci_dev->id.vendor_id,
>  +			(unsigned int) pci_dev->id.device_id);
>  +
>  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>  +		rte_free(eventdev->data->dev_private);
>  +
>  +	eventdev->attached = RTE_EVENTDEV_DETACHED;
>  +	eventdev_globals.nb_devs--;
>  +
>  +	return -ENXIO;
>  +}
>  +
>  +int
>  +rte_eventdev_pmd_pci_remove(struct rte_pci_device *pci_dev)
>  +{
>  +	const struct rte_eventdev_driver *eventdrv;
>  +	struct rte_eventdev *eventdev;
>  +	char eventdev_name[RTE_EVENTDEV_NAME_MAX_LEN];
>  +	int ret;
>  +
>  +	if (pci_dev == NULL)
>  +		return -EINVAL;
>  +
>  +	rte_eal_pci_device_name(&pci_dev->addr, eventdev_name,
>  +			sizeof(eventdev_name));
>  +
>  +	eventdev = rte_eventdev_pmd_get_named_dev(eventdev_name);
>  +	if (eventdev == NULL)
>  +		return -ENODEV;
>  +
>  +	eventdrv = (const struct rte_eventdev_driver *)pci_dev->driver;
>  +	if (eventdrv == NULL)
>  +		return -ENODEV;
>  +
>  +	/* Invoke PMD device uninit function */
>  +	if (*eventdrv->eventdev_uninit) {
>  +		ret = (*eventdrv->eventdev_uninit)(eventdev);
>  +		if (ret)
>  +			return ret;
>  +	}
>  +
>  +	/* Free event device */
>  +	rte_eventdev_pmd_release(eventdev);
>  +
>  +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>  +		rte_free(eventdev->data->dev_private);
>  +
>  +	eventdev->pci_dev = NULL;
>  +	eventdev->driver = NULL;
>  +
>  +	return 0;
>  +}
>  diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h
>  b/lib/librte_eventdev/rte_eventdev_pmd.h
>  new file mode 100644
>  index 0000000..e9d9b83
>  --- /dev/null
>  +++ b/lib/librte_eventdev/rte_eventdev_pmd.h
>  @@ -0,0 +1,504 @@
>  +/*
>  + *
>  + *   Copyright(c) 2016 Cavium networks. All rights reserved.
>  + *
>  + *   Redistribution and use in source and binary forms, with or without
>  + *   modification, are permitted provided that the following conditions
>  + *   are met:
>  + *
>  + *     * Redistributions of source code must retain the above copyright
>  + *       notice, this list of conditions and the following disclaimer.
>  + *     * Redistributions in binary form must reproduce the above copyright
>  + *       notice, this list of conditions and the following disclaimer in
>  + *       the documentation and/or other materials provided with the
>  + *       distribution.
>  + *     * Neither the name of Cavium networks nor the names of its
>  + *       contributors may be used to endorse or promote products derived
>  + *       from this software without specific prior written permission.
>  + *
>  + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
>  CONTRIBUTORS
>  + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
>  NOT
>  + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
>  FITNESS FOR
>  + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
>  COPYRIGHT
>  + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
>  INCIDENTAL,
>  + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
>  NOT
>  + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
>  OF USE,
>  + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
>  AND ON ANY
>  + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
>  TORT
>  + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
>  THE USE
>  + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
>  DAMAGE.
>  + */
>  +
>  +#ifndef _RTE_EVENTDEV_PMD_H_
>  +#define _RTE_EVENTDEV_PMD_H_
>  +
>  +/** @file
>  + * RTE Event PMD APIs
>  + *
>  + * @note
>  + * These API are from event PMD only and user applications should not call
>  + * them directly.
>  + */
>  +
>  +#ifdef __cplusplus
>  +extern "C" {
>  +#endif
>  +
>  +#include <string.h>
>  +
>  +#include <rte_dev.h>
>  +#include <rte_pci.h>
>  +#include <rte_malloc.h>
>  +#include <rte_log.h>
>  +#include <rte_common.h>
>  +
>  +#include "rte_eventdev.h"
>  +
>  +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
>  +#define RTE_PMD_DEBUG_TRACE(...) \
>  +	rte_pmd_debug_trace(__func__, __VA_ARGS__)
>  +#else
>  +#define RTE_PMD_DEBUG_TRACE(...)
>  +#endif
>  +
>  +/* Logging Macros */
>  +#define EDEV_LOG_ERR(fmt, args...) \
>  +	RTE_LOG(ERR, EVENTDEV, "%s() line %u: " fmt "\n",  \
>  +			__func__, __LINE__, ## args)
>  +
>  +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
>  +#define EDEV_LOG_DEBUG(fmt, args...) \
>  +	RTE_LOG(DEBUG, EVENTDEV, "%s() line %u: " fmt "\n",  \
>  +			__func__, __LINE__, ## args)
>  +#else
>  +#define EDEV_LOG_DEBUG(fmt, args...) (void)0
>  +#endif
>  +
>  +/* Macros to check for valid device */
>  +#define RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, retval) do { \
>  +	if (!rte_eventdev_pmd_is_valid_dev((dev_id))) { \
>  +		EDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
>  +		return retval; \
>  +	} \
>  +} while (0)
>  +
>  +#define RTE_EVENTDEV_VALID_DEVID_OR_RET(dev_id) do { \
>  +	if (!rte_eventdev_pmd_is_valid_dev((dev_id))) { \
>  +		EDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
>  +		return; \
>  +	} \
>  +} while (0)
>  +
>  +#define RTE_EVENTDEV_DETACHED  (0)
>  +#define RTE_EVENTDEV_ATTACHED  (1)
>  +
>  +/**
>  + * Initialisation function of a event driver invoked for each matching
>  + * event PCI device detected during the PCI probing phase.
>  + *
>  + * @param dev
>  + *   The dev pointer is the address of the *rte_eventdev* structure associated
>  + *   with the matching device and which has been [automatically] allocated in
>  + *   the *rte_event_devices* array.
>  + *
>  + * @return
>  + *   - 0: Success, the device is properly initialised by the driver.
>  + *        In particular, the driver MUST have set up the *dev_ops* pointer
>  + *        of the *dev* structure.
>  + *   - <0: Error code of the device initialisation failure.
>  + */
>  +typedef int (*eventdev_init_t)(struct rte_eventdev *dev);
>  +
>  +/**
>  + * Finalisation function of a driver invoked for each matching
>  + * PCI device detected during the PCI closing phase.
>  + *
>  + * @param dev
>  + *   The dev pointer is the address of the *rte_eventdev* structure associated
>  + *   with the matching device and which	has been [automatically] allocated in
>  + *   the *rte_event_devices* array.
>  + *
>  + * @return
>  + *   - 0: Success, the device is properly finalised by the driver.
>  + *        In particular, the driver MUST free the *dev_ops* pointer
>  + *        of the *dev* structure.
>  + *   - <0: Error code of the device initialisation failure.
>  + */
>  +typedef int (*eventdev_uninit_t)(struct rte_eventdev *dev);
>  +
>  +/**
>  + * The structure associated with a PMD driver.
>  + *
>  + * Each driver acts as a PCI driver and is represented by a generic
>  + * *event_driver* structure that holds:
>  + *
>  + * - An *rte_pci_driver* structure (which must be the first field).
>  + *
>  + * - The *eventdev_init* function invoked for each matching PCI device.
>  + *
>  + * - The size of the private data to allocate for each matching device.
>  + */
>  +struct rte_eventdev_driver {
>  +	struct rte_pci_driver pci_drv;	/**< The PMD is also a PCI driver. */
>  +	unsigned int dev_private_size;	/**< Size of device private data. */
>  +
>  +	eventdev_init_t eventdev_init;	/**< Device init function. */
>  +	eventdev_uninit_t eventdev_uninit; /**< Device uninit function. */
>  +};
>  +
>  +/** Global structure used for maintaining state of allocated event devices */
>  +struct rte_eventdev_global {
>  +	uint8_t nb_devs;	/**< Number of devices found */
>  +	uint8_t max_devs;	/**< Max number of devices */
>  +};
>  +
>  +extern struct rte_eventdev_global *rte_eventdev_globals;
>  +/** Pointer to global event devices data structure. */
>  +extern struct rte_eventdev *rte_eventdevs;
>  +/** The pool of rte_eventdev structures. */
>  +
>  +/**
>  + * Get the rte_eventdev structure device pointer for the named device.
>  + *
>  + * @param name
>  + *   device name to select the device structure.
>  + *
>  + * @return
>  + *   - The rte_eventdev structure pointer for the given device ID.
>  + */
>  +static inline struct rte_eventdev *
>  +rte_eventdev_pmd_get_named_dev(const char *name)
>  +{
>  +	struct rte_eventdev *dev;
>  +	unsigned int i;
>  +
>  +	if (name == NULL)
>  +		return NULL;
>  +
>  +	for (i = 0, dev = &rte_eventdevs[i];
>  +			i < rte_eventdev_globals->max_devs; i++) {
>  +		if ((dev->attached == RTE_EVENTDEV_ATTACHED) &&
>  +				(strcmp(dev->data->name, name) == 0))
>  +			return dev;
>  +	}
>  +
>  +	return NULL;
>  +}
>  +
>  +/**
>  + * Validate if the event device index is valid attached event device.
>  + *
>  + * @param dev_id
>  + *   Event device index.
>  + *
>  + * @return
>  + *   - If the device index is valid (1) or not (0).
>  + */
>  +static inline unsigned
>  +rte_eventdev_pmd_is_valid_dev(uint8_t dev_id)
>  +{
>  +	struct rte_eventdev *dev;
>  +
>  +	if (dev_id >= rte_eventdev_globals->nb_devs)
>  +		return 0;
>  +
>  +	dev = &rte_eventdevs[dev_id];
>  +	if (dev->attached != RTE_EVENTDEV_ATTACHED)
>  +		return 0;
>  +	else
>  +		return 1;
>  +}
>  +
>  +/**
>  + * Definitions of all functions exported by a driver through the
>  + * the generic structure of type *event_dev_ops* supplied in the
>  + * *rte_eventdev* structure associated with a device.
>  + */
>  +
>  +/**
>  + * Get device information of a device.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + * @param dev_info
>  + *   Event device information structure
>  + *
>  + * @return
>  + *   Returns 0 on success
>  + */
>  +typedef void (*eventdev_info_get_t)(struct rte_eventdev *dev,
>  +		struct rte_event_dev_info *dev_info);
>  +
>  +/**
>  + * Configure a device.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + *
>  + * @return
>  + *   Returns 0 on success
>  + */
>  +typedef int (*eventdev_configure_t)(struct rte_eventdev *dev);
>  +
>  +/**
>  + * Start a configured device.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + *
>  + * @return
>  + *   Returns 0 on success
>  + */
>  +typedef int (*eventdev_start_t)(struct rte_eventdev *dev);
>  +
>  +/**
>  + * Stop a configured device.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + */
>  +typedef void (*eventdev_stop_t)(struct rte_eventdev *dev);
>  +
>  +/**
>  + * Close a configured device.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + *
>  + * @return
>  + * - 0 on success
>  + * - (-EAGAIN) if can't close as device is busy
>  + */
>  +typedef int (*eventdev_close_t)(struct rte_eventdev *dev);
>  +
>  +/**
>  + * Retrieve the default event queue configuration.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + * @param queue_id
>  + *   Event queue index
>  + * @param[out] queue_conf
>  + *   Event queue configuration structure
>  + *
>  + */
>  +typedef void (*eventdev_queue_default_conf_get_t)(struct rte_eventdev
>  *dev,
>  +		uint8_t queue_id, struct rte_event_queue_conf *queue_conf);
>  +
>  +/**
>  + * Setup an event queue.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + * @param queue_id
>  + *   Event queue index
>  + * @param queue_conf
>  + *   Event queue configuration structure
>  + *
>  + * @return
>  + *   Returns 0 on success.
>  + */
>  +typedef int (*eventdev_queue_setup_t)(struct rte_eventdev *dev,
>  +		uint8_t queue_id, struct rte_event_queue_conf *queue_conf);
>  +
>  +/**
>  + * Release memory resources allocated by given event queue.
>  + *
>  + * @param queue
>  + *   Event queue pointer
>  + *
>  + */
>  +typedef void (*eventdev_queue_release_t)(void *queue);
>  +
>  +/**
>  + * Retrieve the default event port configuration.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + * @param port_id
>  + *   Event port index
>  + * @param[out] port_conf
>  + *   Event port configuration structure
>  + *
>  + */
>  +typedef void (*eventdev_port_default_conf_get_t)(struct rte_eventdev *dev,
>  +		uint8_t port_id, struct rte_event_port_conf *port_conf);
>  +
>  +/**
>  + * Setup an event port.
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + * @param port_id
>  + *   Event port index
>  + * @param port_conf
>  + *   Event port configuration structure
>  + *
>  + * @return
>  + *   Returns 0 on success.
>  + */
>  +typedef int (*eventdev_port_setup_t)(struct rte_eventdev *dev,
>  +		uint8_t port_id, struct rte_event_port_conf *port_conf);
>  +
>  +/**
>  + * Release memory resources allocated by given event port.
>  + *
>  + * @param port
>  + *   Event port pointer
>  + *
>  + */
>  +typedef void (*eventdev_port_release_t)(void *port);
>  +
>  +/**
>  + * Link multiple source event queues to destination event port.
>  + *
>  + * @param port
>  + *   Event port pointer
>  + * @param link
>  + *   An array of *nb_links* pointers to *rte_event_queue_link* structure
>  + * @param nb_links
>  + *   The number of links to establish
>  + *
>  + * @return
>  + *   Returns 0 on success.
>  + *
>  + */
>  +typedef int (*eventdev_port_link_t)(void *port,
>  +		struct rte_event_queue_link link[], uint16_t nb_links);
>  +
>  +/**
>  + * Unlink multiple source event queues from destination event port.
>  + *
>  + * @param port
>  + *   Event port pointer
>  + * @param queues
>  + *   An array of *nb_unlinks* event queues to be unlinked from the event port.
>  + * @param nb_unlinks
>  + *   The number of unlinks to establish
>  + *
>  + * @return
>  + *   Returns 0 on success.
>  + *
>  + */
>  +typedef int (*eventdev_port_unlink_t)(void *port,
>  +		uint8_t queues[], uint16_t nb_unlinks);
>  +
>  +/**
>  + * Converts nanoseconds to *wait* value for rte_event_dequeue()
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + * @param ns
>  + *   Wait time in nanosecond
>  + * @param[out] wait_ticks
>  + *   Value for the *wait* parameter in rte_event_dequeue() function
>  + *
>  + */
>  +typedef void (*eventdev_dequeue_wait_time_t)(struct rte_eventdev *dev,
>  +		uint64_t ns, uint64_t *wait_ticks);
>  +
>  +/**
>  + * Dump internal information
>  + *
>  + * @param dev
>  + *   Event device pointer
>  + * @param f
>  + *   A pointer to a file for output
>  + *
>  + */
>  +typedef void (*eventdev_dump_t)(struct rte_eventdev *dev, FILE *f);
>  +
>  +/** Event device operations function pointer table */
>  +struct rte_eventdev_ops {
>  +	eventdev_info_get_t dev_infos_get;	/**< Get device info. */
>  +	eventdev_configure_t dev_configure;	/**< Configure device. */
>  +	eventdev_start_t dev_start;		/**< Start device. */
>  +	eventdev_stop_t dev_stop;		/**< Stop device. */
>  +	eventdev_close_t dev_close;		/**< Close device. */
>  +
>  +	eventdev_queue_default_conf_get_t queue_def_conf;
>  +	/**< Get default queue configuration. */
>  +	eventdev_queue_setup_t queue_setup;
>  +	/**< Set up an event queue. */
>  +	eventdev_queue_release_t queue_release;
>  +	/**< Release an event queue. */
>  +
>  +	eventdev_port_default_conf_get_t port_def_conf;
>  +	/**< Get default port configuration. */
>  +	eventdev_port_setup_t port_setup;
>  +	/**< Set up an event port. */
>  +	eventdev_port_release_t port_release;
>  +	/**< Release an event port. */
>  +
>  +	eventdev_port_link_t port_link;
>  +	/**< Link event queues to an event port. */
>  +	eventdev_port_unlink_t port_unlink;
>  +	/**< Unlink event queues from an event port. */
>  +	eventdev_dequeue_wait_time_t wait_time;
>  +	/**< Converts nanoseconds to *wait* value for rte_event_dequeue()
>  */
>  +	eventdev_dump_t dump;
>  +	/* Dump internal information */
>  +};
>  +
>  +/**
>  + * Allocates a new eventdev slot for an event device and returns the pointer
>  + * to that slot for the driver to use.
>  + *
>  + * @param name
>  + *   Unique identifier name for each device
>  + * @param socket_id
>  + *   Socket to allocate resources on.
>  + * @return
>  + *   - Slot in the rte_dev_devices array for a new device;
>  + */
>  +struct rte_eventdev *
>  +rte_eventdev_pmd_allocate(const char *name, int socket_id);
>  +
>  +/**
>  + * Release the specified eventdev device.
>  + *
>  + * @param eventdev
>  + * The *eventdev* pointer is the address of the *rte_eventdev* structure.
>  + * @return
>  + *   - 0 on success, negative on error
>  + */
>  +int
>  +rte_eventdev_pmd_release(struct rte_eventdev *eventdev);
>  +
>  +/**
>  + * Creates a new virtual event device and returns the pointer to that device.
>  + *
>  + * @param name
>  + *   PMD type name
>  + * @param dev_private_size
>  + *   Size of event PMDs private data
>  + * @param socket_id
>  + *   Socket to allocate resources on.
>  + *
>  + * @return
>  + *   - Eventdev pointer if device is successfully created.
>  + *   - NULL if device cannot be created.
>  + */
>  +struct rte_eventdev *
>  +rte_eventdev_pmd_vdev_init(const char *name, size_t dev_private_size,
>  +		int socket_id);
>  +
>  +
>  +/**
>  + * Wrapper for use by pci drivers as a .probe function to attach to a event
>  + * interface.
>  + */
>  +int rte_eventdev_pmd_pci_probe(struct rte_pci_driver *pci_drv,
>  +			    struct rte_pci_device *pci_dev);
>  +
>  +/**
>  + * Wrapper for use by pci drivers as a .remove function to detach a event
>  + * interface.
>  + */
>  +int rte_eventdev_pmd_pci_remove(struct rte_pci_device *pci_dev);
>  +
>  +#ifdef __cplusplus
>  +}
>  +#endif
>  +
>  +#endif /* _RTE_EVENTDEV_PMD_H_ */
>  diff --git a/lib/librte_eventdev/rte_eventdev_version.map
>  b/lib/librte_eventdev/rte_eventdev_version.map
>  new file mode 100644
>  index 0000000..ef40aae
>  --- /dev/null
>  +++ b/lib/librte_eventdev/rte_eventdev_version.map
>  @@ -0,0 +1,39 @@
>  +DPDK_17.02 {
>  +	global:
>  +
>  +	rte_eventdevs;
>  +
>  +	rte_event_dev_count;
>  +	rte_event_dev_get_dev_id;
>  +	rte_event_dev_socket_id;
>  +	rte_event_dev_info_get;
>  +	rte_event_dev_configure;
>  +	rte_event_dev_start;
>  +	rte_event_dev_stop;
>  +	rte_event_dev_close;
>  +	rte_event_dev_dump;
>  +
>  +	rte_event_port_default_conf_get;
>  +	rte_event_port_setup;
>  +	rte_event_port_dequeue_depth;
>  +	rte_event_port_enqueue_depth;
>  +	rte_event_port_count;
>  +	rte_event_port_link;
>  +	rte_event_port_unlink;
>  +	rte_event_port_links_get;
>  +
>  +	rte_event_queue_default_conf_get
>  +	rte_event_queue_setup;
>  +	rte_event_queue_count;
>  +	rte_event_queue_priority;
>  +
>  +	rte_event_dequeue_wait_time;
>  +
>  +	rte_eventdev_pmd_allocate;
>  +	rte_eventdev_pmd_release;
>  +	rte_eventdev_pmd_vdev_init;
>  +	rte_eventdev_pmd_pci_probe;
>  +	rte_eventdev_pmd_pci_remove;
>  +
>  +	local: *;
>  +};
>  diff --git a/mk/rte.app.mk b/mk/rte.app.mk
>  index f75f0e2..716725a 100644
>  --- a/mk/rte.app.mk
>  +++ b/mk/rte.app.mk
>  @@ -93,6 +93,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -
>  lrte_mbuf
>   _LDLIBS-$(CONFIG_RTE_LIBRTE_NET)            += -lrte_net
>   _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lrte_ethdev
>   _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
>  +_LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
>   _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
>   _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
>   _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
>  --
>  2.5.5

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox