DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 2/4] eventdev: implement the northbound APIs
From: Jerin Jacob @ 2016-11-22 20:00 UTC (permalink / raw)
  To: Eads, Gage
  Cc: dev@dpdk.org, Richardson, Bruce, Van Haaren, Harry,
	hemant.agrawal@nxp.com
In-Reply-To: <9184057F7FC11744A2107296B6B8EB1E01E32F3E@FMSMSX108.amr.corp.intel.com>

On Tue, Nov 22, 2016 at 07:43:03PM +0000, Eads, Gage wrote:
> >  > >  > > 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.
> >  >
> >  > Sure, proposal follows. The "typical workflow" isn't the most optimal by
> >  having a conditional in the fast-path, of course, but it demonstrates the idea
> >  simply.
> >  >
> >  > (line 204)
> >  >  * An event driven based application has following typical workflow on
> >  fastpath:
> >  >  * \code{.c}
> >  >  *      while (1) {
> >  >  *
> >  >  *              if (dev_info.event_dev_cap &
> >  >  *                      RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED)
> >  >  *                      rte_event_schedule(dev_id);
> >  
> >  Yes, I like the idea of RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED.
> >  It  can be input to application/subsystem to
> >  launch separate core(s) for schedule functions.
> >  But, I think, the "dev_info.event_dev_cap &
> >  RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED"
> >  check can be moved inside the implementation(to make the better decisions
> >  and
> >  avoiding consuming cycles on HW based schedulers.
> 
> How would this check work? Wouldn't it prevent any core from running the software scheduler in the centralized case?

I guess you may not need RTE_EVENT_DEV_CAP here, instead need flag for device
configure here

#define RTE_EVENT_DEV_CFG_DISTRIBUTED_SCHED (1ULL << 1)

struct rte_event_dev_config config;
config.event_dev_cfg = RTE_EVENT_DEV_CFG_DISTRIBUTED_SCHED;
rte_event_dev_configure(.., &config);

on the driver side on configure,
if (config.event_dev_cfg & RTE_EVENT_DEV_CFG_DISTRIBUTED_SCHED)
	eventdev->schedule = NULL;
else // centralized case
	eventdev->schedule = your_centrized_schedule_function;

Does that work?

> 
> >  
> >  >  *
> >  >  *              rte_event_dequeue(...);
> >  >  *
> >  >  *              (event processing)
> >  >  *
> >  >  *              rte_event_enqueue(...);
> >  >  *      }
> >  >  * \endcode
> >  >  *
> >  >  * The *schedule* operation is intended to do event scheduling, and the
> >  >  * *dequeue* operation returns the scheduled events. An implementation
> >  >  * is free to define the semantics between *schedule* and *dequeue*. For
> >  >  * example, a system based on a hardware scheduler can define its
> >  >  * rte_event_schedule() to be an NOOP, whereas a software scheduler can
> >  use
> >  >  * the *schedule* operation to schedule events. The
> >  >  * RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED capability flag indicates
> >  whether
> >  >  * rte_event_schedule() should be called by all cores or by a single (typically
> >  >  * dedicated) core.
> >  >
> >  > (line 308)
> >  > #define RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED (1ULL < 2)
> >  > /**< Event scheduling implementation is distributed and all cores must
> >  execute
> >  >  *  rte_event_schedule(). If unset, the implementation is centralized and
> >  >  *  a single core must execute the schedule operation.
> >  >  *
> >  >  *  \see rte_event_schedule()
> >  >  */
> >  >
> >  > >  >
> >  > >  > 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
> >  >
> >  > An API for controlling the scheduler coremask instead of (or perhaps in
> >  addition to) the vdev argument would be good, to allow runtime control. I can
> >  imagine apps that scale the number of cores based on load, and in doing so
> >  may want to migrate the scheduler to a different core.
> >  
> >  Yes, an API for number of scheduler core looks OK. But if we are going to
> >  have service core approach then we just need to specify at one place as
> >  application will not creating the service functions.
> >  
> >  >
> >  > >
> >  > >  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.
> >  > >
> >  >
> >  > That's an interesting idea. As you suggested in the other thread, this concept
> >  could be extended to the "producer" code in the example for configurations
> >  where the NIC requires software to feed into the eventdev. And to the other
> >  subsystems mentioned in your original PDF, crypto and timer.
> >  
> >  Yes. Producers should come in service core category. I think, that
> >  enables us to have better NPU integration.(same application code for
> >  NPU vs non NPU)
> >  

^ permalink raw reply

* Re: Proposal for a new Committer model
From: Neil Horman @ 2016-11-22 19:52 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Mcnamara, John
In-Reply-To: <1855350.07sWV4iMZa@xps13>

On Mon, Nov 21, 2016 at 09:52:41AM +0100, Thomas Monjalon wrote:
> 2016-11-18 13:09, Neil Horman:
> > A) Further promote subtree maintainership.  This was a conversation that I
> > proposed some time ago, but my proposed granularity was discarded in favor
> > of something that hasn't worked as well (in my opinion).  That is to say a
> > few driver pmds (i40e and fm10k come to mind) have their own tree that
> > send pull requests to Thomas.
> 
> Yes we tried this fine granularity and stated that it was not working well.
> We are now using the bigger granularity that you describe below.
> 
Ok, thats good, but that must be _very_ new.  Looking at your git tree, I see no
merge commits.  How are you pulling from those subtrees?


> > We should be sharding that at a much higher
> > granularity and using it much more consistently.  That is to say, that we
> > should have a maintainer for all the ethernet pmds, and another for the
> > crypto pmds, another for the core eal layer, another for misc libraries
> > that have low patch volumes, etc.
> 
> Yes we could open a tree for EAL and another one for the core libraries.
> 
That could be worthwhile.  Lets see how the net and crypto subtrees work out
(assuming again that these trees are newly founded)


> > Each of those subdivisions should have
> > their own list to communicate on, and each should have a tree that
> > integrates patches for their own subsystem, and they should on a regular
> > cycle send pull requests to Thomas.
> 
> Yes I think it is now a good idea to split the mailing list traffic,
> at least for netdev and cryptodev.
> 
Agreed, that serves two purposes, it lowers the volume for people with a
specific interest (i.e. its a rudimentary filter), and it avoids confusion
between you and the subtree maintainer (that is to say, you don't have to even
consider pulling patches that go to the crypo and net lists, you just have to
trust that they pull those patches in and send you appropriate pull requests).

> > Thomas in turn should by and large,
> > only be integrating pull requests.  This should address our high-
> > throughput issue, in that it will allow multiple maintainers to share the
> > workload, and integration should be relatively easy.
> 
> Yes in an ideal organization, the last committer does only a last check
> that technical plan and fairness are respected.
> So it gives more time to coordinate the plans :)
> 
Correct.  Thats never 100% accurate of course, some things will still have to
come to you directly, simply by virtue of the fact that they don't completely
fit anywhere else, but thats ok, the goal is really just to get your total patch
volume lower, and replace it with pull requests that you can either trivialy
mere or figure out with the help of the subtree maintainer.

> > B) Designate alternates to serve as backups for the maintainer when they
> > are unavailable.  This provides high-availablility, and sounds very much
> > like your proposal, but in the interests of clarity, there is still a
> > single maintainer at any one time, it just may change to ensure the
> > continued merging of patches, if the primary maintainer isn't available.
> > Ideally however, those backup alternates arent needed, because most of the
> > primary maintainers work in merging pull requests, which are done based on
> > the trust of the submaintainer, and done during a very limited window of
> > time.  This also partially addreses multi-vendor fairness if your subtree
> > maintainers come from multiple participating companies.
> 
> About the merge window, I do not have a strong opinion about how it can be
> improved. However, I know that closing the window too early makes developer
> unhappy because it makes wait - between development start and its release -
> longer.

This is a fair point, but I'm not talking about closing it early here, all
I'm suggesting is that, if you do proper pull requests from subtrees, your tree
Thomas will only need a reasonably small window of time to accept new features,
because you'll just merge the subtrees, rather than integrating individual
patches.  E.g. you won't be constantly merging patches over the course of a
development cycle, your tree's HEAD will mostly consist of merge commits as
subtree maintainers send you pull requests, and ideally they will send those
near the start of a window.  How long you keep your merge window open after that
is up to you.

Neil


 
> 

^ permalink raw reply

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



>  -----Original Message-----
>  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
>  Sent: Tuesday, November 22, 2016 12:19 PM
>  To: Eads, Gage <gage.eads@intel.com>
>  Cc: dev@dpdk.org; Richardson, Bruce <bruce.richardson@intel.com>; Van
>  Haaren, Harry <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com
>  Subject: Re: [dpdk-dev] [PATCH 2/4] eventdev: implement the northbound APIs
>  
>  On Tue, Nov 22, 2016 at 03:15:52PM +0000, Eads, Gage wrote:
>  >
>  >
>  > >  -----Original Message-----
>  > >  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
>  > >  Sent: Monday, November 21, 2016 1:32 PM
>  > >  To: Eads, Gage <gage.eads@intel.com>
>  > >  Cc: dev@dpdk.org; Richardson, Bruce <bruce.richardson@intel.com>; Van
>  > >  Haaren, Harry <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com
>  > >  Subject: Re: [dpdk-dev] [PATCH 2/4] eventdev: implement the northbound
>  APIs
>  > >
>  > >  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.
>  >
>  > Sure, proposal follows. The "typical workflow" isn't the most optimal by
>  having a conditional in the fast-path, of course, but it demonstrates the idea
>  simply.
>  >
>  > (line 204)
>  >  * An event driven based application has following typical workflow on
>  fastpath:
>  >  * \code{.c}
>  >  *      while (1) {
>  >  *
>  >  *              if (dev_info.event_dev_cap &
>  >  *                      RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED)
>  >  *                      rte_event_schedule(dev_id);
>  
>  Yes, I like the idea of RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED.
>  It  can be input to application/subsystem to
>  launch separate core(s) for schedule functions.
>  But, I think, the "dev_info.event_dev_cap &
>  RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED"
>  check can be moved inside the implementation(to make the better decisions
>  and
>  avoiding consuming cycles on HW based schedulers.

How would this check work? Wouldn't it prevent any core from running the software scheduler in the centralized case?

>  
>  >  *
>  >  *              rte_event_dequeue(...);
>  >  *
>  >  *              (event processing)
>  >  *
>  >  *              rte_event_enqueue(...);
>  >  *      }
>  >  * \endcode
>  >  *
>  >  * The *schedule* operation is intended to do event scheduling, and the
>  >  * *dequeue* operation returns the scheduled events. An implementation
>  >  * is free to define the semantics between *schedule* and *dequeue*. For
>  >  * example, a system based on a hardware scheduler can define its
>  >  * rte_event_schedule() to be an NOOP, whereas a software scheduler can
>  use
>  >  * the *schedule* operation to schedule events. The
>  >  * RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED capability flag indicates
>  whether
>  >  * rte_event_schedule() should be called by all cores or by a single (typically
>  >  * dedicated) core.
>  >
>  > (line 308)
>  > #define RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED (1ULL < 2)
>  > /**< Event scheduling implementation is distributed and all cores must
>  execute
>  >  *  rte_event_schedule(). If unset, the implementation is centralized and
>  >  *  a single core must execute the schedule operation.
>  >  *
>  >  *  \see rte_event_schedule()
>  >  */
>  >
>  > >  >
>  > >  > 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
>  >
>  > An API for controlling the scheduler coremask instead of (or perhaps in
>  addition to) the vdev argument would be good, to allow runtime control. I can
>  imagine apps that scale the number of cores based on load, and in doing so
>  may want to migrate the scheduler to a different core.
>  
>  Yes, an API for number of scheduler core looks OK. But if we are going to
>  have service core approach then we just need to specify at one place as
>  application will not creating the service functions.
>  
>  >
>  > >
>  > >  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.
>  > >
>  >
>  > That's an interesting idea. As you suggested in the other thread, this concept
>  could be extended to the "producer" code in the example for configurations
>  where the NIC requires software to feed into the eventdev. And to the other
>  subsystems mentioned in your original PDF, crypto and timer.
>  
>  Yes. Producers should come in service core category. I think, that
>  enables us to have better NPU integration.(same application code for
>  NPU vs non NPU)
>  
>  >
>  > >  >
>  > >  > >
>  > >  > > 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 v2] i40e: Fix eth_i40e_dev_init sequence on ThunderX
From: Jerin Jacob @ 2016-11-22 18:49 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: Ananyev, Konstantin, Satha Rao, Zhang, Helin, Wu, Jingjing,
	jianbo.liu@linaro.org, dev@dpdk.org
In-Reply-To: <20161122134654.GA58712@bricha3-MOBL3.ger.corp.intel.com>

On Tue, Nov 22, 2016 at 01:46:54PM +0000, Bruce Richardson wrote:
> On Tue, Nov 22, 2016 at 03:46:38AM +0530, Jerin Jacob wrote:
> > 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 ?
> > 
> 
> That seems like a lot of API calls!
> Perhaps you can clarify - why would the rte_smp_rmb() not work for you?

Currently arm64 mapped DMB as rte_smp_rmb() for smp case.

Ideally for io barrier and non smp case, we need to map it as DSB and it is
bit heavier than DMB

The linux kernel arm64 mappings
http://lxr.free-electrons.com/source/arch/arm64/include/asm/io.h#L142

DMB vs DSB
https://community.arm.com/thread/3833

The relaxed one are without any barriers.(the use case like accessing on
chip peripherals may need only relaxed versions)

Thoughts on new rte EAL abstraction?

> 
> /Bruce

^ permalink raw reply

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

On Tue, Nov 22, 2016 at 03:15:52PM +0000, Eads, Gage wrote:
> 
> 
> >  -----Original Message-----
> >  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> >  Sent: Monday, November 21, 2016 1:32 PM
> >  To: Eads, Gage <gage.eads@intel.com>
> >  Cc: dev@dpdk.org; Richardson, Bruce <bruce.richardson@intel.com>; Van
> >  Haaren, Harry <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com
> >  Subject: Re: [dpdk-dev] [PATCH 2/4] eventdev: implement the northbound APIs
> >  
> >  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.
> 
> Sure, proposal follows. The "typical workflow" isn't the most optimal by having a conditional in the fast-path, of course, but it demonstrates the idea simply.
> 
> (line 204)
>  * An event driven based application has following typical workflow on fastpath:
>  * \code{.c}                                                                        
>  *      while (1) {                                                                 
>  *                                                                                  
>  *              if (dev_info.event_dev_cap &                                        
>  *                      RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED)                        
>  *                      rte_event_schedule(dev_id);                                 

Yes, I like the idea of RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED.
It  can be input to application/subsystem to
launch separate core(s) for schedule functions.
But, I think, the "dev_info.event_dev_cap & RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED"
check can be moved inside the implementation(to make the better decisions and
avoiding consuming cycles on HW based schedulers.

>  *                                                                                  
>  *              rte_event_dequeue(...);                                             
>  *                                                                                  
>  *              (event processing)                                                  
>  *                                                                                  
>  *              rte_event_enqueue(...);                                             
>  *      }                                                                           
>  * \endcode                                                                         
>  *                                                                                  
>  * The *schedule* operation is intended to do event scheduling, and the             
>  * *dequeue* operation returns the scheduled events. An implementation              
>  * is free to define the semantics between *schedule* and *dequeue*. For            
>  * example, a system based on a hardware scheduler can define its                   
>  * rte_event_schedule() to be an NOOP, whereas a software scheduler can use         
>  * the *schedule* operation to schedule events. The                                 
>  * RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED capability flag indicates whether
>  * rte_event_schedule() should be called by all cores or by a single (typically 
>  * dedicated) core.
> 
> (line 308)
> #define RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED (1ULL < 2)                          
> /**< Event scheduling implementation is distributed and all cores must execute       
>  *  rte_event_schedule(). If unset, the implementation is centralized and     
>  *  a single core must execute the schedule operation.                        
>  *                                                                              
>  *  \see rte_event_schedule()                                                   
>  */
> 
> >  >
> >  > 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
> 
> An API for controlling the scheduler coremask instead of (or perhaps in addition to) the vdev argument would be good, to allow runtime control. I can imagine apps that scale the number of cores based on load, and in doing so may want to migrate the scheduler to a different core.

Yes, an API for number of scheduler core looks OK. But if we are going to
have service core approach then we just need to specify at one place as
application will not creating the service functions.

> 
> >  
> >  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.
> >  
> 
> That's an interesting idea. As you suggested in the other thread, this concept could be extended to the "producer" code in the example for configurations where the NIC requires software to feed into the eventdev. And to the other subsystems mentioned in your original PDF, crypto and timer.

Yes. Producers should come in service core category. I think, that 
enables us to have better NPU integration.(same application code for
NPU vs non NPU)

> 
> >  >
> >  > >
> >  > > 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: Eads, Gage @ 2016-11-22 15:15 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: dev@dpdk.org, Richardson, Bruce, Van Haaren, Harry,
	hemant.agrawal@nxp.com
In-Reply-To: <20161121193133.GA9895@svelivela-lt.caveonetworks.com>



>  -----Original Message-----
>  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
>  Sent: Monday, November 21, 2016 1:32 PM
>  To: Eads, Gage <gage.eads@intel.com>
>  Cc: dev@dpdk.org; Richardson, Bruce <bruce.richardson@intel.com>; Van
>  Haaren, Harry <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com
>  Subject: Re: [dpdk-dev] [PATCH 2/4] eventdev: implement the northbound APIs
>  
>  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.

Sure, proposal follows. The "typical workflow" isn't the most optimal by having a conditional in the fast-path, of course, but it demonstrates the idea simply.

(line 204)
 * An event driven based application has following typical workflow on fastpath:
 * \code{.c}                                                                        
 *      while (1) {                                                                 
 *                                                                                  
 *              if (dev_info.event_dev_cap &                                        
 *                      RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED)                        
 *                      rte_event_schedule(dev_id);                                 
 *                                                                                  
 *              rte_event_dequeue(...);                                             
 *                                                                                  
 *              (event processing)                                                  
 *                                                                                  
 *              rte_event_enqueue(...);                                             
 *      }                                                                           
 * \endcode                                                                         
 *                                                                                  
 * The *schedule* operation is intended to do event scheduling, and the             
 * *dequeue* operation returns the scheduled events. An implementation              
 * is free to define the semantics between *schedule* and *dequeue*. For            
 * example, a system based on a hardware scheduler can define its                   
 * rte_event_schedule() to be an NOOP, whereas a software scheduler can use         
 * the *schedule* operation to schedule events. The                                 
 * RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED capability flag indicates whether
 * rte_event_schedule() should be called by all cores or by a single (typically 
 * dedicated) core.

(line 308)
#define RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED (1ULL < 2)                          
/**< Event scheduling implementation is distributed and all cores must execute       
 *  rte_event_schedule(). If unset, the implementation is centralized and     
 *  a single core must execute the schedule operation.                        
 *                                                                              
 *  \see rte_event_schedule()                                                   
 */

>  >
>  > 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

An API for controlling the scheduler coremask instead of (or perhaps in addition to) the vdev argument would be good, to allow runtime control. I can imagine apps that scale the number of cores based on load, and in doing so may want to migrate the scheduler to a different core.

>  
>  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.
>  

That's an interesting idea. As you suggested in the other thread, this concept could be extended to the "producer" code in the example for configurations where the NIC requires software to feed into the eventdev. And to the other subsystems mentioned in your original PDF, crypto and timer.

>  >
>  > >
>  > > 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: dpdk/vpp and cross-version migration for vhost
From: Michael S. Tsirkin @ 2016-11-22 14:53 UTC (permalink / raw)
  To: Yuanhan Liu
  Cc: Maxime Coquelin, dev, Stephen Hemminger, qemu-devel, libvir-list,
	vpp-dev, Marc-André Lureau
In-Reply-To: <20161122130223.GW5048@yliu-dev.sh.intel.com>

On Tue, Nov 22, 2016 at 09:02:23PM +0800, Yuanhan Liu wrote:
> On Thu, Nov 17, 2016 at 07:37:09PM +0200, Michael S. Tsirkin wrote:
> > On Thu, Nov 17, 2016 at 05:49:36PM +0800, Yuanhan Liu wrote:
> > > On Thu, Nov 17, 2016 at 09:47:09AM +0100, Maxime Coquelin wrote:
> > > > 
> > > > 
> > > > On 11/17/2016 09:29 AM, Yuanhan Liu wrote:
> > > > >As usaual, sorry for late response :/
> > > > >
> > > > >On Thu, Oct 13, 2016 at 08:50:52PM +0300, Michael S. Tsirkin wrote:
> > > > >>Hi!
> > > > >>So it looks like we face a problem with cross-version
> > > > >>migration when using vhost. It's not new but became more
> > > > >>acute with the advent of vhost user.
> > > > >>
> > > > >>For users to be able to migrate between different versions
> > > > >>of the hypervisor the interface exposed to guests
> > > > >>by hypervisor must stay unchanged.
> > > > >>
> > > > >>The problem is that a qemu device is connected
> > > > >>to a backend in another process, so the interface
> > > > >>exposed to guests depends on the capabilities of that
> > > > >>process.
> > > > >>
> > > > >>Specifically, for vhost user interface based on virtio, this includes
> > > > >>the "host features" bitmap that defines the interface, as well as more
> > > > >>host values such as the max ring size.  Adding new features/changing
> > > > >>values to this interface is required to make progress, but on the other
> > > > >>hand we need ability to get the old host features to be compatible.
> > > > >
> > > > >It looks like to the same issue of vhost-user reconnect to me. For example,
> > > > >
> > > > >- start dpdk 16.07 & qemu 2.5
> > > > >- kill dpdk
> > > > >- start dpdk 16.11
> > > > >
> > > > >Though DPDK 16.11 has more features comparing to dpdk 16.07 (say, indirect),
> > > > >above should work. Because qemu saves the negotiated features before the
> > > > >disconnect and stores it back after the reconnection.
> > > > >
> > > > >    commit a463215b087c41d7ca94e51aa347cde523831873
> > > > >    Author: Marc-André Lureau <marcandre.lureau@redhat.com>
> > > > >    Date:   Mon Jun 6 18:45:05 2016 +0200
> > > > >
> > > > >        vhost-net: save & restore vhost-user acked features
> > > > >
> > > > >        The initial vhost-user connection sets the features to be negotiated
> > > > >        with the driver. Renegotiation isn't possible without device reset.
> > > > >
> > > > >        To handle reconnection of vhost-user backend, ensure the same set of
> > > > >        features are provided, and reuse already acked features.
> > > > >
> > > > >        Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > > > >
> > > > >
> > > > >So we could do similar to vhost-user? I mean, save the acked features
> > > > >before migration and store it back after it. This should be able to
> > > > >keep the compatibility. If user downgrades DPDK version, it also could
> > > > >be easily detected, and then exit with an error to user: migration
> > > > >failed due to un-compatible vhost features.
> > > > >
> > > > >Just some rough thoughts. Makes tiny sense?
> > > > 
> > > > My understanding is that the management tool has to know whether
> > > > versions are compatible before initiating the migration:
> > > 
> > > Makes sense. How about getting and restoring the acked features through
> > > qemu command lines then, say, through the monitor interface?
> > > 
> > > With that, it would be something like:
> > > 
> > > - start vhost-user backend (DPDK, VPP, or whatever) & qemu in the src host
> > > 
> > > - read the acked features (through monitor interface)
> > > 
> > > - start vhost-user backend in the dst host
> > > 
> > > - start qemu in the dst host with the just queried acked features
> > > 
> > >   QEMU then is expected to use this feature set for the later vhost-user
> > >   feature negotitation. Exit if features compatibility is broken.
> > > 
> > > Thoughts?
> > > 
> > > 	--yliu
> > 
> > 
> > You keep assuming that you have the VM started first and
> > figure out things afterwards, but this does not work.
> > 
> > Think about a cluster of machines. You want to start a VM in
> > a way that will ensure compatibility with all hosts
> > in a cluster.
> 
> I see. I was more considering about the case when the dst
> host (including the qemu and dpdk combo) is given, and
> then determine whether it will be a successfull migration
> or not.
> 
> And you are asking that we need to know which host could
> be a good candidate before starting the migration. In such
> case, we indeed need some inputs from both the qemu and
> vhost-user backend.
> 
> For DPDK, I think it could be simple, just as you said, it
> could be either a tiny script, or even a macro defined in
> the source code file (we extend it every time we add a
> new feature) to let the libvirt to read it. Or something
> else.

There's the issue of APIs that tweak features as Maxime
suggested. Maybe the only thing to do is to deprecate it,
but I feel some way for application to pass info into
guest might be benefitial.


> > If you don't, guest visible interface will change
> > and you won't be able to migrate.
> > 
> > It does not make sense to discuss feature bits specifically
> > since that is not the only part of interface.
> > For example, max ring size supported might change.
> 
> I don't quite understand why we have to consider the max ring
> size here? Isn't it a virtio device attribute, that QEMU could
> provide such compatibility information?
>
> I mean, DPDK is supposed to support vary vring size, it's QEMU
> to give a specifc value.

If backend supports s/g of any size up to 2^16, there's no issue.

ATM some backends might be assuming up to 1K s/g since
QEMU never supported bigger ones. We might classify this
as a bug, or not and add a feature flag.

But it's just an example. There might be more values at issue
in the future.

> > Let me describe how it works in qemu/libvirt.
> > When you install a VM, you can specify compatibility
> > level (aka "machine type"), and you can query the supported compatibility
> > levels. Management uses that to find the supported compatibility
> > and stores the compatibility in XML that is migrated with the VM.
> > There's also a way to find the latest level which is the
> > default unless overridden by user, again this level
> > is recorded and then
> > - management can make sure migration destination is compatible
> > - management can avoid migration to hosts without that support
> 
> Thanks for the info, it helps.
> 
> ...
> > > > >>As version here is an opaque string for libvirt and qemu,
> > > > >>anything can be used - but I suggest either a list
> > > > >>of values defining the interface, e.g.
> > > > >>any_layout=on,max_ring=256
> > > > >>or a version including the name and vendor of the backend,
> > > > >>e.g. "org.dpdk.v4.5.6".
> 
> The version scheme may not be ideal here. Assume a QEMU is supposed
> to work with a specific DPDK version, however, user may disable some
> newer features through qemu command line, that it also could work with
> an elder DPDK version. Using the version scheme will not allow us doing
> such migration to an elder DPDK version. The MTU is a lively example
> here? (when MTU feature is provided by QEMU but is actually disabled
> by user, that it could also work with an elder DPDK without MTU support).
> 
> 	--yliu

OK, so does a list of values look better to you then?



> > > > >>
> > > > >>Note that typically the list of supported versions can only be
> > > > >>extended, not shrunk. Also, if the host/guest interface
> > > > >>does not change, don't change the current version as
> > > > >>this just creates work for everyone.
> > > > >>
> > > > >>Thoughts? Would this work well for management? dpdk? vpp?
> > > > >>
> > > > >>Thanks!
> > > > >>
> > > > >>--
> > > > >>MST

^ permalink raw reply

* Re: [RFC PATCH 0/7] RFC: EventDev Software PMD
From: Richardson, Bruce @ 2016-11-22 14:05 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: Van Haaren, Harry, dev@dpdk.org
In-Reply-To: <20161121201837.GA12762@svelivela-lt.caveonetworks.com>



> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Monday, November 21, 2016 8:19 PM
> To: Richardson, Bruce <bruce.richardson@intel.com>
> Cc: Van Haaren, Harry <harry.van.haaren@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [RFC PATCH 0/7] RFC: EventDev Software PMD
> 
> 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
> 

Yes, that can work. Many of the unit tests we are looking at are likely
specific to our software implementation, so we may end up doing a separate
sw-eventdev specific unit test set, as well as a general eventdev set.

/Bruce

^ permalink raw reply

* Re: [PATCH 7/7] examples/eventdev_pipeline: adding example
From: Richardson, Bruce @ 2016-11-22 14:04 UTC (permalink / raw)
  To: Jerin Jacob, Van Haaren, Harry; +Cc: dev@dpdk.org, Eads, Gage
In-Reply-To: <20161122060208.GA27648@svelivela-lt.caveonetworks.com>



> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Tuesday, November 22, 2016 6:02 AM
> To: Van Haaren, Harry <harry.van.haaren@intel.com>
> Cc: dev@dpdk.org; Eads, Gage <gage.eads@intel.com>; Richardson, Bruce
> <bruce.richardson@intel.com>
> Subject: Re: [dpdk-dev] [PATCH 7/7] examples/eventdev_pipeline: adding
> example
> 
> 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.

Hi Jerin, 

thanks for the feedback. We'll take it on board for a subsequent version
we produce. Additional comments and queries on your feedback inline below.

/Bruce

> 
> 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
> 
Yes. This is something to consider.

For the pure-software model, we also might want to look at the opposite
approach, where we register an ethdev with the scheduler for it to "pull"
new packets from. This would allow it to bypass the port logic for the new
packets. 

An alternative for this is to extend the schedule API to allow a burst of
packets to be passed in to be scheduled immediately as "NEW" packets. The end
results should be the same, saving cycles by bypassing unneeded processing
for the new packets.

> 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

Yes, comprehensive unit tests will be needed too. But an example app that
pulls packets from an external NIC I also think is needed to get a feel
for the performance of the scheduler with real traffic.

> 
> > +	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.

Yes, I agree, but unfortunately, for some tasks, distributing those tasks
across multiple cores can hurt performance overall do to resource contention.
 
> 
> > 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);
> }
>
Yes, but you still need some core to do the work of pushing the packets into
the scheduler from the NIC, if you don't have a hardware path from NIC to 
HW scheduler. [Features like RSS can obviously help here with distributing that
work if needed]

In the case you do have a HW path - which I assume is the Cavium case - I assume
that the EVENT_TYPE_ETHDEV branch above needs also to take care of desc to mbuf
processing, as is normally done by the PMD?
 
> 
> 
> > +			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 ?

Simulate some work being done by the worker, which makes the app slightly more
realistic and also helps the scheduler as there is not so much contention on the
shared cache lines.

> 
> > +
> > +			/* 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

Sure, we can look at 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?

I'd view it as app dependent. For a test app on IA, I'd expect to use the
NIC RSS value as an initial flow value.
NOTE: this is just a quick test app to demonstrate the concept for the RFC,
so not everything in it is necessarily realistic or what we'd expect in a
final version app.

> 
> > +			ev->priority = 0;
> > +			m->udata64 = mbuf_seqno++;
> 
> Why update mbuf_seqno++ here. Shouldn't be something inside the
> implementation?

I think this was to help verifying the packet ordering. Again, may not be
in a final version.

> 
> > +			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.

Possibly not. We'll check it out.

> 
> > +	/* 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/2] l2fwd/l3fwd: rework long options parsing
From: Olivier Matz @ 2016-11-22 13:59 UTC (permalink / raw)
  To: dev, bruce.richardson, pablo.de.lara.guarch
In-Reply-To: <1479822736-32399-1-git-send-email-olivier.matz@6wind.com>

Hi,

On 11/22/2016 02:52 PM, Olivier Matz wrote:
> These 2 patches were part of this RFC, which will not be integrated:
> http://dpdk.org/ml/archives/dev/2016-September/046974.html
> 
> It does not bring any functional change, it just reworks the way long
> options are parsed in l2fwd and l3fwd to avoid uneeded strcmp() calls
> and to ease the addition of a new long option in the future.
> 
> I send them in case maintainers think it is better this way, but I have
> no real need.
> 
> Olivier Matz (2):
>   l3fwd: rework long options parsing
>   l2fwd: rework long options parsing
> 
>  examples/l2fwd/main.c |  30 +++++++--
>  examples/l3fwd/main.c | 169 ++++++++++++++++++++++++++------------------------
>  2 files changed, 111 insertions(+), 88 deletions(-)
> 

Sorry, I missed some checkpatch issues. I'll fix them in v2.
I'm waiting a bit for other comments, in case of.


Olivier

^ permalink raw reply

* [PATCH 2/2] l2fwd: rework long options parsing
From: Olivier Matz @ 2016-11-22 13:52 UTC (permalink / raw)
  To: dev, bruce.richardson, pablo.de.lara.guarch
In-Reply-To: <1479822736-32399-1-git-send-email-olivier.matz@6wind.com>

Do the same than in l3fwd to avoid strcmp() for long options.

For l2fwd, there is no long option that take advantage of this new
mechanism as --mac-updating and --no-mac-updating are directly setting a
flag without needing an entry in the switch/case.

So this patch just prepares the framework in case a new long option is
added in the future.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 examples/l2fwd/main.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c
index b2f5851..97d6454 100644
--- a/examples/l2fwd/main.c
+++ b/examples/l2fwd/main.c
@@ -392,6 +392,29 @@ l2fwd_parse_timer_period(const char *q_arg)
 	return n;
 }
 
+static const char short_options[] =
+	"p:"  /* portmask */
+	"q:"  /* number of queues */
+	"T:"  /* timer period */
+	;
+
+#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
+#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
+
+enum {
+	/* long options mapped to a short option */
+
+	/* first long only option value must be >= 256, so that we won't
+	 * conflict with short options */
+	CMD_LINE_OPT_MIN_NUM = 256,
+};
+
+static const struct option lgopts[] = {
+	{ CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
+	{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
+	{NULL, 0, 0, 0}
+};
+
 /* Parse the argument given in the command line of the application */
 static int
 l2fwd_parse_args(int argc, char **argv)
@@ -400,15 +423,10 @@ l2fwd_parse_args(int argc, char **argv)
 	char **argvopt;
 	int option_index;
 	char *prgname = argv[0];
-	static struct option lgopts[] = {
-		{ "mac-updating", no_argument, &mac_updating, 1},
-		{ "no-mac-updating", no_argument, &mac_updating, 0},
-		{NULL, 0, 0, 0}
-	};
 
 	argvopt = argv;
 
-	while ((opt = getopt_long(argc, argvopt, "p:q:T:",
+	while ((opt = getopt_long(argc, argvopt, short_options,
 				  lgopts, &option_index)) != EOF) {
 
 		switch (opt) {
-- 
2.8.1

^ permalink raw reply related

* [PATCH 1/2] l3fwd: rework long options parsing
From: Olivier Matz @ 2016-11-22 13:52 UTC (permalink / raw)
  To: dev, bruce.richardson, pablo.de.lara.guarch
In-Reply-To: <1479822736-32399-1-git-send-email-olivier.matz@6wind.com>

Avoid the use of several strncpy() since getopt is able to
map a long option with an id, which can be matched in the
same switch/case than short options.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 examples/l3fwd/main.c | 169 ++++++++++++++++++++++++++------------------------
 1 file changed, 87 insertions(+), 82 deletions(-)

diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
index 7223e77..f84ef50 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -474,6 +474,13 @@ parse_eth_dest(const char *optarg)
 #define MAX_JUMBO_PKT_LEN  9600
 #define MEMPOOL_CACHE_SIZE 256
 
+static const char short_options[] =
+	"p:"  /* portmask */
+	"P"   /* promiscuous */
+	"L"   /* enable long prefix match */
+	"E"   /* enable exact match */
+	;
+
 #define CMD_LINE_OPT_CONFIG "config"
 #define CMD_LINE_OPT_ETH_DEST "eth-dest"
 #define CMD_LINE_OPT_NO_NUMA "no-numa"
@@ -481,6 +488,31 @@ parse_eth_dest(const char *optarg)
 #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
 #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
 #define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
+enum {
+	/* long options mapped to a short option */
+
+	/* first long only option value must be >= 256, so that we won't
+	 * conflict with short options */
+	CMD_LINE_OPT_MIN_NUM = 256,
+	CMD_LINE_OPT_CONFIG_NUM,
+	CMD_LINE_OPT_ETH_DEST_NUM,
+	CMD_LINE_OPT_NO_NUMA_NUM,
+	CMD_LINE_OPT_IPV6_NUM,
+	CMD_LINE_OPT_ENABLE_JUMBO_NUM,
+	CMD_LINE_OPT_HASH_ENTRY_NUM_NUM,
+	CMD_LINE_OPT_PARSE_PTYPE_NUM,
+};
+
+static const struct option lgopts[] = {
+	{CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM},
+	{CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM},
+	{CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM},
+	{CMD_LINE_OPT_IPV6, 0, 0, CMD_LINE_OPT_IPV6_NUM},
+	{CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, CMD_LINE_OPT_ENABLE_JUMBO_NUM},
+	{CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, CMD_LINE_OPT_HASH_ENTRY_NUM_NUM},
+	{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, CMD_LINE_OPT_PARSE_PTYPE_NUM},
+	{NULL, 0, 0, 0}
+};
 
 /*
  * This expression is used to calculate the number of mbufs needed
@@ -504,16 +536,6 @@ parse_args(int argc, char **argv)
 	char **argvopt;
 	int option_index;
 	char *prgname = argv[0];
-	static struct option lgopts[] = {
-		{CMD_LINE_OPT_CONFIG, 1, 0, 0},
-		{CMD_LINE_OPT_ETH_DEST, 1, 0, 0},
-		{CMD_LINE_OPT_NO_NUMA, 0, 0, 0},
-		{CMD_LINE_OPT_IPV6, 0, 0, 0},
-		{CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0},
-		{CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0},
-		{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0},
-		{NULL, 0, 0, 0}
-	};
 
 	argvopt = argv;
 
@@ -534,7 +556,7 @@ parse_args(int argc, char **argv)
 		"L3FWD: LPM and EM are mutually exclusive, select only one";
 	const char *str13 = "L3FWD: LPM or EM none selected, default LPM on";
 
-	while ((opt = getopt_long(argc, argvopt, "p:PLE",
+	while ((opt = getopt_long(argc, argvopt, short_options,
 				lgopts, &option_index)) != EOF) {
 
 		switch (opt) {
@@ -547,6 +569,7 @@ parse_args(int argc, char **argv)
 				return -1;
 			}
 			break;
+
 		case 'P':
 			printf("%s\n", str2);
 			promiscuous_on = 1;
@@ -563,89 +586,71 @@ parse_args(int argc, char **argv)
 			break;
 
 		/* long options */
-		case 0:
-			if (!strncmp(lgopts[option_index].name,
-					CMD_LINE_OPT_CONFIG,
-					sizeof(CMD_LINE_OPT_CONFIG))) {
-
-				ret = parse_config(optarg);
-				if (ret) {
-					printf("%s\n", str5);
-					print_usage(prgname);
-					return -1;
-				}
-			}
-
-			if (!strncmp(lgopts[option_index].name,
-					CMD_LINE_OPT_ETH_DEST,
-					sizeof(CMD_LINE_OPT_ETH_DEST))) {
-					parse_eth_dest(optarg);
-			}
-
-			if (!strncmp(lgopts[option_index].name,
-					CMD_LINE_OPT_NO_NUMA,
-					sizeof(CMD_LINE_OPT_NO_NUMA))) {
-				printf("%s\n", str6);
-				numa_on = 0;
+		case CMD_LINE_OPT_CONFIG_NUM:
+			ret = parse_config(optarg);
+			if (ret) {
+				printf("%s\n", str5);
+				print_usage(prgname);
+				return -1;
 			}
+			break;
 
-			if (!strncmp(lgopts[option_index].name,
-				CMD_LINE_OPT_IPV6,
-				sizeof(CMD_LINE_OPT_IPV6))) {
-				printf("%sn", str7);
-				ipv6 = 1;
-			}
+		case CMD_LINE_OPT_ETH_DEST_NUM:
+			parse_eth_dest(optarg);
+			break;
 
-			if (!strncmp(lgopts[option_index].name,
-					CMD_LINE_OPT_ENABLE_JUMBO,
-					sizeof(CMD_LINE_OPT_ENABLE_JUMBO))) {
-				struct option lenopts = {
-					"max-pkt-len", required_argument, 0, 0
-				};
-
-				printf("%s\n", str8);
-				port_conf.rxmode.jumbo_frame = 1;
-
-				/*
-				 * if no max-pkt-len set, use the default
-				 * value ETHER_MAX_LEN.
-				 */
-				if (0 == getopt_long(argc, argvopt, "",
-						&lenopts, &option_index)) {
-					ret = parse_max_pkt_len(optarg);
-					if ((ret < 64) ||
-						(ret > MAX_JUMBO_PKT_LEN)) {
-						printf("%s\n", str9);
-						print_usage(prgname);
-						return -1;
-					}
-					port_conf.rxmode.max_rx_pkt_len = ret;
-				}
-				printf("%s %u\n", str10,
-				(unsigned int)port_conf.rxmode.max_rx_pkt_len);
-			}
+		case CMD_LINE_OPT_NO_NUMA_NUM:
+			printf("%s\n", str6);
+			numa_on = 0;
+			break;
 
-			if (!strncmp(lgopts[option_index].name,
-				CMD_LINE_OPT_HASH_ENTRY_NUM,
-				sizeof(CMD_LINE_OPT_HASH_ENTRY_NUM))) {
+		case CMD_LINE_OPT_IPV6_NUM:
+			printf("%sn", str7);
+			ipv6 = 1;
+			break;
 
-				ret = parse_hash_entry_number(optarg);
-				if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) {
-					hash_entry_number = ret;
-				} else {
-					printf("%s\n", str11);
+		case CMD_LINE_OPT_ENABLE_JUMBO_NUM: {
+			struct option lenopts = {
+				"max-pkt-len", required_argument, 0, 0
+			};
+
+			printf("%s\n", str8);
+			port_conf.rxmode.jumbo_frame = 1;
+
+			/*
+			 * if no max-pkt-len set, use the default
+			 * value ETHER_MAX_LEN.
+			 */
+			if (0 == getopt_long(argc, argvopt, "",
+					&lenopts, &option_index)) {
+				ret = parse_max_pkt_len(optarg);
+				if ((ret < 64) ||
+					(ret > MAX_JUMBO_PKT_LEN)) {
+					printf("%s\n", str9);
 					print_usage(prgname);
 					return -1;
 				}
+				port_conf.rxmode.max_rx_pkt_len = ret;
 			}
+			printf("%s %u\n", str10,
+				(unsigned int)port_conf.rxmode.max_rx_pkt_len);
+			break;
+		}
 
-			if (!strncmp(lgopts[option_index].name,
-				     CMD_LINE_OPT_PARSE_PTYPE,
-				     sizeof(CMD_LINE_OPT_PARSE_PTYPE))) {
-				printf("soft parse-ptype is enabled\n");
-				parse_ptype = 1;
+		case CMD_LINE_OPT_HASH_ENTRY_NUM_NUM:
+			ret = parse_hash_entry_number(optarg);
+			if ((ret > 0) && (ret <= L3FWD_HASH_ENTRIES)) {
+				hash_entry_number = ret;
+			} else {
+				printf("%s\n", str11);
+				print_usage(prgname);
+				return -1;
 			}
+			break;
 
+		case CMD_LINE_OPT_PARSE_PTYPE_NUM:
+			printf("soft parse-ptype is enabled\n");
+			parse_ptype = 1;
 			break;
 
 		default:
-- 
2.8.1

^ permalink raw reply related

* [PATCH 0/2] l2fwd/l3fwd: rework long options parsing
From: Olivier Matz @ 2016-11-22 13:52 UTC (permalink / raw)
  To: dev, bruce.richardson, pablo.de.lara.guarch

These 2 patches were part of this RFC, which will not be integrated:
http://dpdk.org/ml/archives/dev/2016-September/046974.html

It does not bring any functional change, it just reworks the way long
options are parsed in l2fwd and l3fwd to avoid uneeded strcmp() calls
and to ease the addition of a new long option in the future.

I send them in case maintainers think it is better this way, but I have
no real need.

Olivier Matz (2):
  l3fwd: rework long options parsing
  l2fwd: rework long options parsing

 examples/l2fwd/main.c |  30 +++++++--
 examples/l3fwd/main.c | 169 ++++++++++++++++++++++++++------------------------
 2 files changed, 111 insertions(+), 88 deletions(-)

-- 
2.8.1

^ permalink raw reply

* Re: [PATCH v2] i40e: Fix eth_i40e_dev_init sequence on ThunderX
From: Bruce Richardson @ 2016-11-22 13:46 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: Ananyev, Konstantin, Satha Rao, Zhang, Helin, Wu, Jingjing,
	jianbo.liu@linaro.org, dev@dpdk.org
In-Reply-To: <20161121221638.GA17380@svelivela-lt.caveonetworks.com>

On Tue, Nov 22, 2016 at 03:46:38AM +0530, Jerin Jacob wrote:
> 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 ?
> 

That seems like a lot of API calls!
Perhaps you can clarify - why would the rte_smp_rmb() not work for you?

/Bruce

^ permalink raw reply

* Re: [PATCH] virtio: tx with can_push when VERSION_1 is set
From: Maxime Coquelin @ 2016-11-22 13:17 UTC (permalink / raw)
  To: Pierre Pfister (ppfister); +Cc: Yuanhan Liu, dev@dpdk.org
In-Reply-To: <A0EE9DE0-C82E-44CF-BB85-245488B78034@cisco.com>

Hi Pierre,

On 11/22/2016 10:54 AM, Pierre Pfister (ppfister) wrote:
> 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.
I also think it makes sense to have a single descriptor, but I had to
highlight that I noticed a significant performance degradation when
using single descriptor on my setup.

I'm fine we take your patch in virtio-next, so that more testing is 
conducted.

Thanks,
Maxime

>
> 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

* Re: dpdk/vpp and cross-version migration for vhost
From: Yuanhan Liu @ 2016-11-22 13:02 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Maxime Coquelin, dev, Stephen Hemminger, qemu-devel, libvir-list,
	vpp-dev, Marc-André Lureau
In-Reply-To: <20161117192445-mutt-send-email-mst@kernel.org>

On Thu, Nov 17, 2016 at 07:37:09PM +0200, Michael S. Tsirkin wrote:
> On Thu, Nov 17, 2016 at 05:49:36PM +0800, Yuanhan Liu wrote:
> > On Thu, Nov 17, 2016 at 09:47:09AM +0100, Maxime Coquelin wrote:
> > > 
> > > 
> > > On 11/17/2016 09:29 AM, Yuanhan Liu wrote:
> > > >As usaual, sorry for late response :/
> > > >
> > > >On Thu, Oct 13, 2016 at 08:50:52PM +0300, Michael S. Tsirkin wrote:
> > > >>Hi!
> > > >>So it looks like we face a problem with cross-version
> > > >>migration when using vhost. It's not new but became more
> > > >>acute with the advent of vhost user.
> > > >>
> > > >>For users to be able to migrate between different versions
> > > >>of the hypervisor the interface exposed to guests
> > > >>by hypervisor must stay unchanged.
> > > >>
> > > >>The problem is that a qemu device is connected
> > > >>to a backend in another process, so the interface
> > > >>exposed to guests depends on the capabilities of that
> > > >>process.
> > > >>
> > > >>Specifically, for vhost user interface based on virtio, this includes
> > > >>the "host features" bitmap that defines the interface, as well as more
> > > >>host values such as the max ring size.  Adding new features/changing
> > > >>values to this interface is required to make progress, but on the other
> > > >>hand we need ability to get the old host features to be compatible.
> > > >
> > > >It looks like to the same issue of vhost-user reconnect to me. For example,
> > > >
> > > >- start dpdk 16.07 & qemu 2.5
> > > >- kill dpdk
> > > >- start dpdk 16.11
> > > >
> > > >Though DPDK 16.11 has more features comparing to dpdk 16.07 (say, indirect),
> > > >above should work. Because qemu saves the negotiated features before the
> > > >disconnect and stores it back after the reconnection.
> > > >
> > > >    commit a463215b087c41d7ca94e51aa347cde523831873
> > > >    Author: Marc-André Lureau <marcandre.lureau@redhat.com>
> > > >    Date:   Mon Jun 6 18:45:05 2016 +0200
> > > >
> > > >        vhost-net: save & restore vhost-user acked features
> > > >
> > > >        The initial vhost-user connection sets the features to be negotiated
> > > >        with the driver. Renegotiation isn't possible without device reset.
> > > >
> > > >        To handle reconnection of vhost-user backend, ensure the same set of
> > > >        features are provided, and reuse already acked features.
> > > >
> > > >        Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > > >
> > > >
> > > >So we could do similar to vhost-user? I mean, save the acked features
> > > >before migration and store it back after it. This should be able to
> > > >keep the compatibility. If user downgrades DPDK version, it also could
> > > >be easily detected, and then exit with an error to user: migration
> > > >failed due to un-compatible vhost features.
> > > >
> > > >Just some rough thoughts. Makes tiny sense?
> > > 
> > > My understanding is that the management tool has to know whether
> > > versions are compatible before initiating the migration:
> > 
> > Makes sense. How about getting and restoring the acked features through
> > qemu command lines then, say, through the monitor interface?
> > 
> > With that, it would be something like:
> > 
> > - start vhost-user backend (DPDK, VPP, or whatever) & qemu in the src host
> > 
> > - read the acked features (through monitor interface)
> > 
> > - start vhost-user backend in the dst host
> > 
> > - start qemu in the dst host with the just queried acked features
> > 
> >   QEMU then is expected to use this feature set for the later vhost-user
> >   feature negotitation. Exit if features compatibility is broken.
> > 
> > Thoughts?
> > 
> > 	--yliu
> 
> 
> You keep assuming that you have the VM started first and
> figure out things afterwards, but this does not work.
> 
> Think about a cluster of machines. You want to start a VM in
> a way that will ensure compatibility with all hosts
> in a cluster.

I see. I was more considering about the case when the dst
host (including the qemu and dpdk combo) is given, and
then determine whether it will be a successfull migration
or not.

And you are asking that we need to know which host could
be a good candidate before starting the migration. In such
case, we indeed need some inputs from both the qemu and
vhost-user backend.

For DPDK, I think it could be simple, just as you said, it
could be either a tiny script, or even a macro defined in
the source code file (we extend it every time we add a
new feature) to let the libvirt to read it. Or something
else.

> If you don't, guest visible interface will change
> and you won't be able to migrate.
> 
> It does not make sense to discuss feature bits specifically
> since that is not the only part of interface.
> For example, max ring size supported might change.

I don't quite understand why we have to consider the max ring
size here? Isn't it a virtio device attribute, that QEMU could
provide such compatibility information?

I mean, DPDK is supposed to support vary vring size, it's QEMU
to give a specifc value.

> Let me describe how it works in qemu/libvirt.
> When you install a VM, you can specify compatibility
> level (aka "machine type"), and you can query the supported compatibility
> levels. Management uses that to find the supported compatibility
> and stores the compatibility in XML that is migrated with the VM.
> There's also a way to find the latest level which is the
> default unless overridden by user, again this level
> is recorded and then
> - management can make sure migration destination is compatible
> - management can avoid migration to hosts without that support

Thanks for the info, it helps.

...
> > > >>As version here is an opaque string for libvirt and qemu,
> > > >>anything can be used - but I suggest either a list
> > > >>of values defining the interface, e.g.
> > > >>any_layout=on,max_ring=256
> > > >>or a version including the name and vendor of the backend,
> > > >>e.g. "org.dpdk.v4.5.6".

The version scheme may not be ideal here. Assume a QEMU is supposed
to work with a specific DPDK version, however, user may disable some
newer features through qemu command line, that it also could work with
an elder DPDK version. Using the version scheme will not allow us doing
such migration to an elder DPDK version. The MTU is a lively example
here? (when MTU feature is provided by QEMU but is actually disabled
by user, that it could also work with an elder DPDK without MTU support).

	--yliu

> > > >>
> > > >>Note that typically the list of supported versions can only be
> > > >>extended, not shrunk. Also, if the host/guest interface
> > > >>does not change, don't change the current version as
> > > >>this just creates work for everyone.
> > > >>
> > > >>Thoughts? Would this work well for management? dpdk? vpp?
> > > >>
> > > >>Thanks!
> > > >>
> > > >>--
> > > >>MST

^ permalink raw reply

* Re: [PATCH v2 8/8] ethdev: Decouple interrupt handling from PCI device
From: Shreyansh Jain @ 2016-11-22 12:57 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev, david.marchand
In-Reply-To: <1479747322-5774-8-git-send-email-jblunck@infradead.org>

On Monday 21 November 2016 10:25 PM, Jan Blunck wrote:
> The struct rte_intr_handle is an abstraction layer for different types of
> interrupt mechanisms. It is embedded in the low-level device (e.g. PCI).
> On allocation of a struct rte_eth_dev a reference to the intr_handle
> should be stored for devices supporting interrupts.
>
> Signed-off-by: Jan Blunck <jblunck@infradead.org>
> ---
>  lib/librte_ether/rte_ethdev.c | 18 ++++++++++++++++--
>  lib/librte_ether/rte_ethdev.h |  1 +
>  2 files changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index 4288577..4ecea50 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -258,6 +258,7 @@ rte_eth_dev_pci_probe(struct rte_pci_driver *pci_drv,
>  			rte_panic("Cannot allocate memzone for private port data\n");
>  	}
>  	eth_dev->pci_dev = pci_dev;
> +	eth_dev->intr_handle = &pci_dev->intr_handle;
>  	eth_dev->driver = eth_drv;
>  	eth_dev->data->rx_mbuf_alloc_failed = 0;
>
> @@ -2543,7 +2544,13 @@ rte_eth_dev_rx_intr_ctl(uint8_t port_id, int epfd, int op, void *data)
>  	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
>
>  	dev = &rte_eth_devices[port_id];
> -	intr_handle = &dev->pci_dev->intr_handle;
> +
> +	if (!dev->intr_handle) {
> +		RTE_PMD_DEBUG_TRACE("RX Intr handle unset\n");
> +		return -ENOTSUP;
> +	}
> +
> +	intr_handle = dev->intr_handle;
>  	if (!intr_handle->intr_vec) {
>  		RTE_PMD_DEBUG_TRACE("RX Intr vector unset\n");
>  		return -EPERM;
> @@ -2603,7 +2610,12 @@ rte_eth_dev_rx_intr_ctl_q(uint8_t port_id, uint16_t queue_id,
>  		return -EINVAL;
>  	}
>
> -	intr_handle = &dev->pci_dev->intr_handle;
> +	if (!dev->intr_handle) {
> +		RTE_PMD_DEBUG_TRACE("RX Intr handle unset\n");
> +		return -ENOTSUP;
> +	}
> +
> +	intr_handle = dev->intr_handle;
>  	if (!intr_handle->intr_vec) {
>  		RTE_PMD_DEBUG_TRACE("RX Intr vector unset\n");
>  		return -EPERM;
> @@ -3205,6 +3217,8 @@ rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev, struct rte_pci_device *pci_de
>  		return;
>  	}
>
> +	eth_dev->intr_handle = &pci_dev->intr_handle;
> +
>  	eth_dev->data->dev_flags = 0;
>  	if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)
>  		eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index 3adbb2b..f1f656a 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -1629,6 +1629,7 @@ struct rte_eth_dev {
>  	const struct eth_driver *driver;/**< Driver for this device */
>  	const struct eth_dev_ops *dev_ops; /**< Functions exported by PMD */
>  	struct rte_pci_device *pci_dev; /**< PCI info. supplied by probing */
> +	struct rte_intr_handle *intr_handle; /**< Device interrupt handle */
>  	/** User application callbacks for NIC interrupts */
>  	struct rte_eth_dev_cb_list link_intr_cbs;
>  	/**
>

Is there another patch which replaces all uses of 
eth_dev->pci_dev->intr_handle with that of eth_dev->intr_handle?

Now that eth_dev has a reference which is initialized as early as probe, 
we should use that rather than pci_dev->intr_handle for PCI PMDs.

OR maybe, ETH_DEV_INTR_HANDLE() like macro which you have introduced in 
i40e_ethdev.h.

-
Shreyansh

^ permalink raw reply

* Re: [PATCH v2 2/8] ethdev: Helper to convert to struct rte_pci_device
From: Shreyansh Jain @ 2016-11-22 12:46 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev, david.marchand
In-Reply-To: <1479747322-5774-2-git-send-email-jblunck@infradead.org>

On Monday 21 November 2016 10:25 PM, Jan Blunck wrote:
> Signed-off-by: Jan Blunck <jblunck@infradead.org>
> ---
>  lib/librte_ether/rte_ethdev.h | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index 9678179..3adbb2b 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -1644,6 +1644,12 @@ struct rte_eth_dev {
>  	uint8_t attached; /**< Flag indicating the port is attached */
>  } __rte_cache_aligned;
>
> +/**
> + * @internal
> + * Helper for drivers that need to convert from rte_eth_dev to rte_pci_device.
> + */
> +#define ETH_DEV_PCI_DEV(ptr) ((ptr)->pci_dev)
> +
>  struct rte_eth_dev_sriov {
>  	uint8_t active;               /**< SRIOV is active with 16, 32 or 64 pools */
>  	uint8_t nb_q_per_pool;        /**< rx queue number per pool */
>

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

^ permalink raw reply

* Re: [PATCH v2 1/8] eal: define container_of macro
From: Shreyansh Jain @ 2016-11-22 12:36 UTC (permalink / raw)
  To: Jan Viktorin
  Cc: Thomas Monjalon, Jan Blunck, dev@dpdk.org,
	david.marchand@6wind.com
In-Reply-To: <20161122133323.33feb23c@jvn>

> -----Original Message-----
> From: Jan Viktorin [mailto:viktorin@rehivetech.com]
> Sent: Tuesday, November 22, 2016 6:03 PM
> To: Shreyansh Jain <shreyansh.jain@nxp.com>
> Cc: Thomas Monjalon <thomas.monjalon@6wind.com>; Jan Blunck
> <jblunck@infradead.org>; dev@dpdk.org; david.marchand@6wind.com
> Subject: Re: [dpdk-dev] [PATCH v2 1/8] eal: define container_of macro
> 
> On Tue, 22 Nov 2016 11:26:50 +0000
> Shreyansh Jain <shreyansh.jain@nxp.com> wrote:
> 
> > > -----Original Message-----
> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > Sent: Tuesday, November 22, 2016 3:50 PM
> > > To: Shreyansh Jain <shreyansh.jain@nxp.com>; Jan Blunck
> > > <jblunck@infradead.org>
> > > Cc: dev@dpdk.org; david.marchand@6wind.com; Jan Viktorin
> > > <viktorin@rehivetech.com>
> > > Subject: Re: [dpdk-dev] [PATCH v2 1/8] eal: define container_of macro
> > >
> > > 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.
> >
> > I can add this patch to my series, if Jan is ok about this.
> 
> It's OK. Just merge it someday ;).

Actually, I meant Jan Blunck ;D
I have already been using your patch since long.

> 
> Jan
> 
> >
> > -
> > Shreyansh
> 
> 
> 
> --
>   Jan Viktorin                E-mail: Viktorin@RehiveTech.com
>   System Architect            Web:    www.RehiveTech.com
>   RehiveTech
>   Brno, Czech Republic

^ permalink raw reply

* Re: [PATCH v2 1/8] eal: define container_of macro
From: Jan Viktorin @ 2016-11-22 12:33 UTC (permalink / raw)
  To: Shreyansh Jain
  Cc: Thomas Monjalon, Jan Blunck, dev@dpdk.org,
	david.marchand@6wind.com
In-Reply-To: <DB5PR0401MB205403969D044DE781E84E6490B40@DB5PR0401MB2054.eurprd04.prod.outlook.com>

On Tue, 22 Nov 2016 11:26:50 +0000
Shreyansh Jain <shreyansh.jain@nxp.com> wrote:

> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Tuesday, November 22, 2016 3:50 PM
> > To: Shreyansh Jain <shreyansh.jain@nxp.com>; Jan Blunck
> > <jblunck@infradead.org>
> > Cc: dev@dpdk.org; david.marchand@6wind.com; Jan Viktorin
> > <viktorin@rehivetech.com>
> > Subject: Re: [dpdk-dev] [PATCH v2 1/8] eal: define container_of macro
> > 
> > 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.  
> 
> I can add this patch to my series, if Jan is ok about this.

It's OK. Just merge it someday ;).

Jan

> 
> -
> Shreyansh



-- 
  Jan Viktorin                E-mail: Viktorin@RehiveTech.com
  System Architect            Web:    www.RehiveTech.com
  RehiveTech
  Brno, Czech Republic

^ permalink raw reply

* Re: [PATCH] mk: remove make target for examples
From: Ferruh Yigit @ 2016-11-22 11:49 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev
In-Reply-To: <5520615.NhohP7H5Lc@xps13>

On 11/22/2016 9:38 AM, Thomas Monjalon wrote:
> 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 ?

To keep existing targets, in case somebody use them.

> It is not compatible with the old behaviour, so I'm afraid it would be
> confusing for no real benefit.

Right, not fully compatible, but still can do:
make examples / make examples_clean
make examples T=x86_64-native-linuxapp-gcc

Overall, if you believe keeping them is confusing, I am OK with it, just
may need to update doc/build-sdk-quick.txt to fix "make help" output.

Thanks,
ferruh

^ permalink raw reply

* Re: [PATCH v2 1/8] eal: define container_of macro
From: Shreyansh Jain @ 2016-11-22 11:26 UTC (permalink / raw)
  To: Thomas Monjalon, Jan Blunck
  Cc: dev@dpdk.org, david.marchand@6wind.com, Jan Viktorin
In-Reply-To: <2433517.txJaDuniYc@xps13>

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Tuesday, November 22, 2016 3:50 PM
> To: Shreyansh Jain <shreyansh.jain@nxp.com>; Jan Blunck
> <jblunck@infradead.org>
> Cc: dev@dpdk.org; david.marchand@6wind.com; Jan Viktorin
> <viktorin@rehivetech.com>
> Subject: Re: [dpdk-dev] [PATCH v2 1/8] eal: define container_of macro
> 
> 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.

I can add this patch to my series, if Jan is ok about this.

-
Shreyansh

^ permalink raw reply

* Re: [PATCH v2 3/8] drivers: Use ETH_DEV_PCI_DEV() helper
From: Shreyansh Jain @ 2016-11-22 11:21 UTC (permalink / raw)
  To: Jan Blunck; +Cc: dev, david.marchand
In-Reply-To: <1479747322-5774-3-git-send-email-jblunck@infradead.org>

On Monday 21 November 2016 10:25 PM, Jan Blunck wrote:
> The drivers should not directly access the rte_eth_dev->pci_dev but use
> a macro instead. This is a preparation for replacing the pci_dev with
> a struct rte_device member in the future.
>
> Signed-off-by: Jan Blunck <jblunck@infradead.org>
> ---
>  drivers/net/bnxt/bnxt_ethdev.c       | 19 ++++++-----
>  drivers/net/bnxt/bnxt_ring.c         | 11 +++---
>  drivers/net/cxgbe/cxgbe_ethdev.c     |  2 +-
>  drivers/net/e1000/em_ethdev.c        | 20 ++++++-----
>  drivers/net/e1000/igb_ethdev.c       | 50 +++++++++++++++------------
>  drivers/net/e1000/igb_pf.c           |  3 +-
>  drivers/net/ena/ena_ethdev.c         |  2 +-
>  drivers/net/enic/enic_ethdev.c       |  2 +-
>  drivers/net/fm10k/fm10k_ethdev.c     | 49 ++++++++++++++-------------

I found a couple of placed in the fm10k_ethdev file where pci_dev usage 
can be replaced with ETH_DEV_PCI_DEV() macro. For example,
  - fm10k_dev_tx_init() +681,
  - fm10k_set_tx_function +2774

Can you please check once again?

>  drivers/net/i40e/i40e_ethdev.c       | 44 ++++++++++++------------
>  drivers/net/i40e/i40e_ethdev.h       |  4 +++
>  drivers/net/i40e/i40e_ethdev_vf.c    | 38 ++++++++++-----------
>  drivers/net/ixgbe/ixgbe_ethdev.c     | 65 +++++++++++++++++++++---------------
>  drivers/net/ixgbe/ixgbe_pf.c         |  2 +-
>  drivers/net/qede/qede_ethdev.c       | 17 +++++-----
>  drivers/net/vmxnet3/vmxnet3_ethdev.c |  4 +--
>  16 files changed, 185 insertions(+), 147 deletions(-)

Some changes in szedata2 are also on similar lines:
  - rte_szedata2_eth_dev_init +1419, +1420, ... <More>
  - rte_szedata2_eth_dev_uninit

Some changes in nicvf_ethdev.c also are missing, I think:
  - nicvf_eth_dev_init +1980
  - nicvf_dev_info_get +1350

and nfp/nfp_net.c
  - nfp_net_init(), +2333, +2403
  - nfp_net_close, +718, +737
  - nfp_net_dev_link_status_print
  - nfp_net_irq_unmask, +1161

and bnx2x_ethdev.c
  - bnx2x_common_dev_init
  - and access to intr_handle which can replaced with
    ETH_DEV_TO_INTR_HANDLE

Is there any specific reason these changes are not part of your patch?

[...]
> diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
> index 298cef4..9d4bea7 100644
> --- a/drivers/net/i40e/i40e_ethdev.h
> +++ b/drivers/net/i40e/i40e_ethdev.h
> @@ -671,6 +671,10 @@ i40e_get_vsi_from_adapter(struct i40e_adapter *adapter)
>  #define I40E_VF_TO_HW(vf) \
>  	(&(((struct i40e_vf *)vf)->adapter->hw))
>
> +/* ETH_DEV_TO_INTR_HANDLE */
> +#define ETH_DEV_TO_INTR_HANDLE(ptr) \
> +	(&(ETH_DEV_PCI_DEV(ptr)->intr_handle))
> +

Can this be in rte_ethdev.h just like ETH_DEV_PCI_DEV?
Or, as this is specific to rte_pci_device, probably in rte_pci.h?
Many drivers can be replaced this for accessing intr_handle.

-
Shreyansh

^ permalink raw reply

* Re: [PATCH v2] drivers: advertise kmod dependencies in pmdinfo
From: Olivier Matz @ 2016-11-22 10:31 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, nhorman, thomas.monjalon, vido, fiona.trahe, stephen
In-Reply-To: <20161122102708.GH409@6wind.com>

Hi Adrien,

On 11/22/2016 11:27 AM, Adrien Mazarguil wrote:
> 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");
> 

Thank you for reviewing. I messed up in the rebase, the v1 was
closer to what you suggest, sorry. I'll send an update.

Olivier

^ permalink raw reply

* 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


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