DPDK patches and discussions
 help / color / mirror / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download: 
* Re: [dpdk-dev] [dpdk-stable] [PATCH v2] mbuf: replace zero-length marker with unnamed union
  @ 2020-04-08 15:22  3%                       ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-04-08 15:22 UTC (permalink / raw)
  To: Gavin Hu
  Cc: Kevin Traynor, Bruce Richardson, Morten Brørup,
	Ferruh Yigit, dev, nd, thomas, jerinj, Honnappa Nagarahalli,
	Ruifeng Wang, Phil Yang, Joyce Kong, stable, Olivier MATZ,
	Konstantin Ananyev, Andrew Rybchenko

On Wed, Apr 8, 2020 at 5:05 PM Gavin Hu <Gavin.Hu@arm.com> wrote:
> > -----Original Message-----
> > From: Kevin Traynor <ktraynor@redhat.com>
> > Hi Gavin, I lost track if v2 is still a candidate for merge. fwiw, it
> > compiles without giving the zero-length-bounds warning on my system.
> >
> > Kevin.
>
> Yes,  this path alone is a candidate for merge.

This patch is not mergeable, it would trigger failures in the ABI checks.

You can see in patchwork that the robot reported a warning in Travis.
http://mails.dpdk.org/archives/test-report/2020-March/119919.html
https://travis-ci.com/github/ovsrobot/dpdk/jobs/295652710#L4476


I opened a bz to libabigail.
https://sourceware.org/bugzilla/show_bug.cgi?id=25661


Either a different solution is found, or your patch will have to deal
with this issue (libabigail fix won't be ready soon afaik) and waive
this.


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-07  7:36  4% ` David Marchand
  2020-04-07 11:33  0%   ` Neil Horman
@ 2020-04-08 14:50  0%   ` Ray Kinsella
  1 sibling, 0 replies; 200+ results
From: Ray Kinsella @ 2020-04-08 14:50 UTC (permalink / raw)
  To: dev



On 07/04/2020 08:36, David Marchand wrote:
> On Mon, Apr 6, 2020 at 9:34 PM Neil Horman <nhorman@tuxdriver.com> wrote:
>>
>> Since we've moved away from our initial abi_versioning.sh script, in
> 
> abi_versioning.sh does not exist (idem with the patch title).
> I suppose you meant validate-abi.sh.
> 
>> favor of check_abi.sh, which uses libabigail, remove the old script from
> 
> check-abi.sh
> 
>> the tree, and update the docs accordingly
>>
> 
> [snip]
> 
>> diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
>> index a21f4e7a4..1c4a3f927 100644
>> --- a/doc/guides/contributing/abi_versioning.rst
>> +++ b/doc/guides/contributing/abi_versioning.rst
>> @@ -482,9 +482,9 @@ Running the ABI Validator
>>  -------------------------
>>
>>  The ``devtools`` directory in the DPDK source tree contains a utility program,
>> -``validate-abi.sh``, for validating the DPDK ABI based on the Linux `ABI
>> -Compliance Checker
>> -<http://ispras.linuxbase.org/index.php/ABI_compliance_checker>`_.
>> +``check-abi.sh``, for validating the DPDK ABI based on the libabigail abidiff
>> +utility:
>> +https://sourceware.org/libabigail/manual/abidiff.html
>>
>>  This has a dependency on the ``abi-compliance-checker`` and ``and abi-dumper``
>>  utilities which can be installed via a package manager. For example::
>> @@ -492,9 +492,9 @@ utilities which can be installed via a package manager. For example::
>>     sudo yum install abi-compliance-checker
>>     sudo yum install abi-dumper
>>
>> -The syntax of the ``validate-abi.sh`` utility is::
>> +The syntax of the ``check-abi.sh`` utility is::
>>
>> -   ./devtools/validate-abi.sh <REV1> <REV2>
>> +   ./devtools/check-abi.sh <REV1> <REV2>
> 
> The new script is not a direct replacement.
> It won't take git revisions, but build directories where versions of
> dpdk have been compiled.
> 
> devtools/test-build.sh and devtools/test-meson-builds.sh illustrate its use.
> https://git.dpdk.org/dpdk/tree/devtools/test-meson-builds.sh#n127
> 
> 
As described in my other - should we just direct contributors to use the meson/ninja build?

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-06 19:34 38% [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree Neil Horman
  2020-04-07  7:36  4% ` David Marchand
@ 2020-04-08 14:49  0% ` Ray Kinsella
  1 sibling, 0 replies; 200+ results
From: Ray Kinsella @ 2020-04-08 14:49 UTC (permalink / raw)
  To: Neil Horman, dev, Richardson, Bruce



On 06/04/2020 20:34, Neil Horman wrote:
> Since we've moved away from our initial abi_versioning.sh script, in
> favor of check_abi.sh, which uses libabigail, remove the old script from
> the tree, and update the docs accordingly
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: thomas@monjalon.net
> ---
>  MAINTAINERS                                |   1 -
>  devtools/validate-abi.sh                   | 251 ---------------------
>  doc/guides/contributing/abi_versioning.rst |  18 +-
>  3 files changed, 9 insertions(+), 261 deletions(-)
>  delete mode 100755 devtools/validate-abi.sh
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4800f6884..84b633431 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -152,7 +152,6 @@ F: devtools/gen-abi.sh
>  F: devtools/libabigail.abignore
>  F: devtools/update-abi.sh
>  F: devtools/update_version_map_abi.py
> -F: devtools/validate-abi.sh
>  F: buildtools/check-experimental-syms.sh
>  F: buildtools/map-list-symbol.sh
>  
> diff --git a/devtools/validate-abi.sh b/devtools/validate-abi.sh
> deleted file mode 100755
> index f64e19d38..000000000
> --- a/devtools/validate-abi.sh
> +++ /dev/null
> @@ -1,251 +0,0 @@
> -#!/usr/bin/env bash
> -# SPDX-License-Identifier: BSD-3-Clause
> -# Copyright(c) 2015 Neil Horman. All rights reserved.
> -# Copyright(c) 2017 6WIND S.A.
> -# All rights reserved
> -
> -set -e
> -
> -abicheck=abi-compliance-checker
> -abidump=abi-dumper
> -default_dst=abi-check
> -default_target=x86_64-native-linuxapp-gcc
> -
> -# trap on error
> -err_report() {
> -    echo "$0: error at line $1"
> -}
> -trap 'err_report $LINENO' ERR
> -
> -print_usage () {
> -	cat <<- END_OF_HELP
> -	$(basename $0) [options] <rev1> <rev2>
> -
> -	This script compares the ABI of 2 git revisions of the current
> -	workspace. The output is a html report and a compilation log.
> -
> -	The objective is to make sure that applications built against
> -	DSOs from the first revision can still run when executed using
> -	the DSOs built from the second revision.
> -
> -	<rev1> and <rev2> are git commit id or tags.
> -
> -	Options:
> -	  -h		show this help
> -	  -j <num>	enable parallel compilation with <num> threads
> -	  -v		show compilation logs on the console
> -	  -d <dir>	change working directory (default is ${default_dst})
> -	  -t <target>	the dpdk target to use (default is ${default_target})
> -	  -f		overwrite existing files in destination directory
> -
> -	The script returns 0 on success, or the value of last failing
> -	call of ${abicheck} (incompatible abi or the tool has run with errors).
> -	The errors returned by ${abidump} are ignored.
> -
> -	END_OF_HELP
> -}
> -
> -# log in the file, and on stdout if verbose
> -# $1: level string
> -# $2: string to be logged
> -log() {
> -	echo "$1: $2"
> -	if [ "${verbose}" != "true" ]; then
> -		echo "$1: $2" >&3
> -	fi
> -}
> -
> -# launch a command and log it, taking care of surrounding spaces with quotes
> -cmd() {
> -	local i s whitespace ret
> -	s=""
> -	whitespace="[[:space:]]"
> -	for i in "$@"; do
> -		if [[ $i =~ $whitespace ]]; then
> -			i=\"$i\"
> -		fi
> -		if [ -z "$s" ]; then
> -			s="$i"
> -		else
> -			s="$s $i"
> -		fi
> -	done
> -
> -	ret=0
> -	log "CMD" "$s"
> -	"$@" || ret=$?
> -	if [ "$ret" != "0" ]; then
> -		log "CMD" "previous command returned $ret"
> -	fi
> -
> -	return $ret
> -}
> -
> -# redirect or copy stderr/stdout to a file
> -# the syntax is unfamiliar, but it makes the rest of the
> -# code easier to read, avoiding the use of pipes
> -set_log_file() {
> -	# save original stdout and stderr in fd 3 and 4
> -	exec 3>&1
> -	exec 4>&2
> -	# create a new fd 5 that send to a file
> -	exec 5> >(cat > $1)
> -	# send stdout and stderr to fd 5
> -	if [ "${verbose}" = "true" ]; then
> -		exec 1> >(tee /dev/fd/5 >&3)
> -		exec 2> >(tee /dev/fd/5 >&4)
> -	else
> -		exec 1>&5
> -		exec 2>&5
> -	fi
> -}
> -
> -# Make sure we configure SHARED libraries
> -# Also turn off IGB and KNI as those require kernel headers to build
> -fixup_config() {
> -	local conf=config/defconfig_$target
> -	cmd sed -i -e"$ a\CONFIG_RTE_BUILD_SHARED_LIB=y" $conf
> -	cmd sed -i -e"$ a\CONFIG_RTE_NEXT_ABI=n" $conf
> -	cmd sed -i -e"$ a\CONFIG_RTE_EAL_IGB_UIO=n" $conf
> -	cmd sed -i -e"$ a\CONFIG_RTE_LIBRTE_KNI=n" $conf
> -	cmd sed -i -e"$ a\CONFIG_RTE_KNI_KMOD=n" $conf
> -}
> -
> -# build dpdk for the given tag and dump abi
> -# $1: hash of the revision
> -gen_abi() {
> -	local i
> -
> -	cmd git clone ${dpdkroot} ${dst}/${1}
> -	cmd cd ${dst}/${1}
> -
> -	log "INFO" "Checking out version ${1} of the dpdk"
> -	# Move to the old version of the tree
> -	cmd git checkout ${1}
> -
> -	fixup_config
> -
> -	# Now configure the build
> -	log "INFO" "Configuring DPDK ${1}"
> -	cmd make config T=$target O=$target
> -
> -	# Checking abi compliance relies on using the dwarf information in
> -	# the shared objects. Build with -g to include them.
> -	log "INFO" "Building DPDK ${1}. This might take a moment"
> -	cmd make -j$parallel O=$target V=1 EXTRA_CFLAGS="-g -Og -Wno-error" \
> -	    EXTRA_LDFLAGS="-g" || log "INFO" "The build failed"
> -
> -	# Move to the lib directory
> -	cmd cd ${PWD}/$target/lib
> -	log "INFO" "Collecting ABI information for ${1}"
> -	for i in *.so; do
> -		[ -e "$i" ] || break
> -		cmd $abidump ${i} -o $dst/${1}/${i}.dump -lver ${1} || true
> -		# hack to ignore empty SymbolsInfo section (no public ABI)
> -		if grep -q "'SymbolInfo' => {}," $dst/${1}/${i}.dump \
> -				2> /dev/null; then
> -			log "INFO" "${i} has no public ABI, remove dump file"
> -			cmd rm -f $dst/${1}/${i}.dump
> -		fi
> -	done
> -}
> -
> -verbose=false
> -parallel=1
> -dst=${default_dst}
> -target=${default_target}
> -force=0
> -while getopts j:vd:t:fh ARG ; do
> -	case $ARG in
> -		j ) parallel=$OPTARG ;;
> -		v ) verbose=true ;;
> -		d ) dst=$OPTARG ;;
> -		t ) target=$OPTARG ;;
> -		f ) force=1 ;;
> -		h ) print_usage ; exit 0 ;;
> -		? ) print_usage ; exit 1 ;;
> -	esac
> -done
> -shift $(($OPTIND - 1))
> -
> -if [ $# != 2 ]; then
> -	print_usage
> -	exit 1
> -fi
> -
> -tag1=$1
> -tag2=$2
> -
> -# convert path to absolute
> -case "${dst}" in
> -	/*) ;;
> -	*) dst=${PWD}/${dst} ;;
> -esac
> -dpdkroot=$(readlink -f $(dirname $0)/..)
> -
> -if [ -e "${dst}" -a "$force" = 0 ]; then
> -	echo "The ${dst} directory is not empty. Remove it, use another"
> -	echo "one (-d <dir>), or force overriding (-f)"
> -	exit 1
> -fi
> -
> -rm -rf ${dst}
> -mkdir -p ${dst}
> -set_log_file ${dst}/abi-check.log
> -log "INFO" "Logs available in ${dst}/abi-check.log"
> -
> -command -v ${abicheck} || log "INFO" "Can't find ${abicheck} utility"
> -command -v ${abidump} || log "INFO" "Can't find ${abidump} utility"
> -
> -hash1=$(git show -s --format=%h "$tag1" -- 2> /dev/null | tail -1)
> -hash2=$(git show -s --format=%h "$tag2" -- 2> /dev/null | tail -1)
> -
> -# Make hashes available in output for non-local reference
> -tag1="$tag1 ($hash1)"
> -tag2="$tag2 ($hash2)"
> -
> -if [ "$hash1" = "$hash2" ]; then
> -	log "ERROR" "$tag1 and $tag2 are the same revisions"
> -	exit 1
> -fi
> -
> -cmd mkdir -p ${dst}
> -
> -# dump abi for each revision
> -gen_abi ${hash1}
> -gen_abi ${hash2}
> -
> -# compare the abi dumps
> -cmd cd ${dst}
> -ret=0
> -list=""
> -for i in ${hash2}/*.dump; do
> -	name=`basename $i`
> -	libname=${name%.dump}
> -
> -	if [ ! -f ${hash1}/$name ]; then
> -		log "INFO" "$NAME does not exist in $tag1. skipping..."
> -		continue
> -	fi
> -
> -	local_ret=0
> -	cmd $abicheck -l $libname \
> -	    -old ${hash1}/$name -new ${hash2}/$name || local_ret=$?
> -	if [ $local_ret != 0 ]; then
> -		log "NOTICE" "$abicheck returned $local_ret"
> -		ret=$local_ret
> -		list="$list $libname"
> -	fi
> -done
> -
> -if [ $ret != 0 ]; then
> -	log "NOTICE" "ABI may be incompatible, check reports/logs for details."
> -	log "NOTICE" "Incompatible list: $list"
> -else
> -	log "NOTICE" "No error detected, ABI is compatible."
> -fi
> -
> -log "INFO" "Logs are in ${dst}/abi-check.log"
> -log "INFO" "HTML reports are in ${dst}/compat_reports directory"
> -
> -exit $ret
> diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
> index a21f4e7a4..1c4a3f927 100644
> --- a/doc/guides/contributing/abi_versioning.rst
> +++ b/doc/guides/contributing/abi_versioning.rst
> @@ -482,9 +482,9 @@ Running the ABI Validator
>  -------------------------
>

Could we simplify this all greatly, by telling people to use the meson/ninja build,
so they get this checking out of the box, without all the headache below?

>  The ``devtools`` directory in the DPDK source tree contains a utility program,
> -``validate-abi.sh``, for validating the DPDK ABI based on the Linux `ABI
> -Compliance Checker
> -<http://ispras.linuxbase.org/index.php/ABI_compliance_checker>`_.
> +``check-abi.sh``, for validating the DPDK ABI based on the libabigail abidiff
> +utility:
> +https://sourceware.org/libabigail/manual/abidiff.html 

Links should be in the format.
`PEP8 (Style Guide for Python Code) <https://www.python.org/dev/peps/pep-0008/>`_.

>  
>  This has a dependency on the ``abi-compliance-checker`` and ``and abi-dumper``
>  utilities which can be installed via a package manager. For example::
> @@ -492,9 +492,9 @@ utilities which can be installed via a package manager. For example::
>     sudo yum install abi-compliance-checker
>     sudo yum install abi-dumper
>  
> -The syntax of the ``validate-abi.sh`` utility is::
> +The syntax of the ``check-abi.sh`` utility is::
>  
> -   ./devtools/validate-abi.sh <REV1> <REV2>
> +   ./devtools/check-abi.sh <REV1> <REV2>
>  
>  Where ``REV1`` and ``REV2`` are valid gitrevisions(7)
>  https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html
> @@ -503,16 +503,16 @@ on the local repo.
>  For example::
>  
>     # Check between the previous and latest commit:
> -   ./devtools/validate-abi.sh HEAD~1 HEAD
> +   ./devtools/check-abi.sh HEAD~1 HEAD
>  
>     # Check on a specific compilation target:
> -   ./devtools/validate-abi.sh -t x86_64-native-linux-gcc HEAD~1 HEAD
> +   ./devtools/check-abi.sh -t x86_64-native-linux-gcc HEAD~1 HEAD
>  
>     # Check between two tags:
> -   ./devtools/validate-abi.sh v2.0.0 v2.1.0
> +   ./devtools/check-abi.sh v2.0.0 v2.1.0
>  
>     # Check between git master and local topic-branch "vhost-hacking":
> -   ./devtools/validate-abi.sh master vhost-hacking
> +   ./devtools/check-abi.sh master vhost-hacking
>  
>  After the validation script completes (it can take a while since it need to
>  compile both tags) it will create compatibility reports in the
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-07 11:58  5%     ` Thomas Monjalon
  2020-04-07 19:52  3%       ` Neil Horman
@ 2020-04-08 14:34  0%       ` Ray Kinsella
  1 sibling, 0 replies; 200+ results
From: Ray Kinsella @ 2020-04-08 14:34 UTC (permalink / raw)
  To: Thomas Monjalon, David Marchand, Neil Horman, Kevin Laatz; +Cc: dev



On 07/04/2020 12:58, Thomas Monjalon wrote:
> 07/04/2020 13:33, Neil Horman:
>> On Tue, Apr 07, 2020 at 09:36:17AM +0200, David Marchand wrote:
>>> On Mon, Apr 6, 2020 at 9:34 PM Neil Horman <nhorman@tuxdriver.com> wrote:
>>>>
>>>> Since we've moved away from our initial abi_versioning.sh script, in
>>>
>>> abi_versioning.sh does not exist (idem with the patch title).
>>> I suppose you meant validate-abi.sh.
>>>
>> Crud, you're right, I was convoluting terms, sorry.  Shall I repost with a
>> corrected changelog?
> 
> Not only the commit log, look below how you did not care about the basic
> usage of the new tool.
> 
> 
>>>> favor of check_abi.sh, which uses libabigail, remove the old script from
>>>
>>> check-abi.sh
>>>
>>>> the tree, and update the docs accordingly
> [...]
>>>> --- a/doc/guides/contributing/abi_versioning.rst
>>>> +++ b/doc/guides/contributing/abi_versioning.rst
> 
> The maintainer of doc/guides/contributing/abi_*.rst
> is Ray Kinsella so I add him as Cc.

Thanks for that ... 

> 
> [...]
>>>> -The syntax of the ``validate-abi.sh`` utility is::
>>>> +The syntax of the ``check-abi.sh`` utility is::
>>>>
>>>> -   ./devtools/validate-abi.sh <REV1> <REV2>
>>>> +   ./devtools/check-abi.sh <REV1> <REV2>
>>>
>>> The new script is not a direct replacement.
>>> It won't take git revisions, but build directories where versions of
>>> dpdk have been compiled.
>>>
>>> devtools/test-build.sh and devtools/test-meson-builds.sh illustrate its use.
>>> https://git.dpdk.org/dpdk/tree/devtools/test-meson-builds.sh#n127
> 
> David, I think Neil did not take time to understand what changed in
> ABI tooling.
> I really wonder who is the real maintainer of ABI tooling and policy.
> Neil, Ray, I was expecting a better involvement in this major
> policy enforcement.

I missed it on the ML, was check-maintainers.sh run?
I am just getting FYI'ed now, right?

> 
> This is where we are:
> 	- Neil asked first for ABI compatibility
> 	- Neil created validate-abi.sh
> 	- Ray asked for a strict policy

Feedback on that separately. 

> 	- Kevin worked on a new tooling
> 	- David completed the tooling work
> 	- David integrated ABI checks in Travis
> 
> There are many people partly involved.
> I think we need one person truly involved in ABI questions,
> someone who feels responsible and will take care of details
> like the documentation update requested above.
> 
> Please don't rely on David and myself, we are already very busy
> with making sure every patches are properly reviewed.
> We need good help on the ABI topic in general.

Always happy to help. 



 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3 07/12] service: remove rte prefix from static functions
  2020-04-08 10:36  0%         ` Van Haaren, Harry
@ 2020-04-08 10:49  0%           ` Phil Yang
  0 siblings, 0 replies; 200+ results
From: Phil Yang @ 2020-04-08 10:49 UTC (permalink / raw)
  To: Van Haaren, Harry, thomas, Ananyev, Konstantin, stephen,
	maxime.coquelin, dev
  Cc: david.marchand, jerinj, hemant.agrawal, Honnappa Nagarahalli,
	Gavin Hu, Ruifeng Wang, Joyce Kong, nd, stable, nd, nd

> -----Original Message-----
> From: Van Haaren, Harry <harry.van.haaren@intel.com>
> Sent: Wednesday, April 8, 2020 6:37 PM
> To: Phil Yang <Phil.Yang@arm.com>; thomas@monjalon.net; Ananyev,
> Konstantin <konstantin.ananyev@intel.com>;
> stephen@networkplumber.org; maxime.coquelin@redhat.com;
> dev@dpdk.org
> Cc: david.marchand@redhat.com; jerinj@marvell.com;
> hemant.agrawal@nxp.com; Honnappa Nagarahalli
> <Honnappa.Nagarahalli@arm.com>; Gavin Hu <Gavin.Hu@arm.com>;
> Ruifeng Wang <Ruifeng.Wang@arm.com>; Joyce Kong
> <Joyce.Kong@arm.com>; nd <nd@arm.com>; stable@dpdk.org; nd
> <nd@arm.com>
> Subject: RE: [PATCH v3 07/12] service: remove rte prefix from static functions
> 
> > -----Original Message-----
> > From: Phil Yang <Phil.Yang@arm.com>
> > Sent: Wednesday, April 8, 2020 11:15 AM
> > To: Van Haaren, Harry <harry.van.haaren@intel.com>;
> thomas@monjalon.net;
> > Ananyev, Konstantin <konstantin.ananyev@intel.com>;
> > stephen@networkplumber.org; maxime.coquelin@redhat.com;
> dev@dpdk.org
> > Cc: david.marchand@redhat.com; jerinj@marvell.com;
> hemant.agrawal@nxp.com;
> > Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>; Gavin Hu
> > <Gavin.Hu@arm.com>; Ruifeng Wang <Ruifeng.Wang@arm.com>; Joyce
> Kong
> > <Joyce.Kong@arm.com>; nd <nd@arm.com>; stable@dpdk.org; nd
> <nd@arm.com>
> > Subject: RE: [PATCH v3 07/12] service: remove rte prefix from static
> functions
> <snip>
> > > Is this really a "Fix"? The internal function names were not exported
> > > in the .map file, so are not part of public ABI. This is an internal
> > > naming improvement (thanks for doing cleanup), but I don't think the
> > > Fixes: tags make sense?
> > >
> > > Also I'm not sure if we want to port this patch back to stable? Changing
> > > (internal) function names seems like unnecessary churn, and hence risk
> to a
> > > stable release, without any benefit?
> > OK.
> > I will remove these tags in the next version and split the service core
> > patches from the original series into a series by itself.
> 
> Cool - good idea to split.
> 
> Perhaps we should focus on getting bugfixes in for the existing code, before
> doing cleanup? It would make backports easier if churn is minimal.
> 
> Suggesting patches order (first to last)
> 1. bugfixes/things to backport
> 2. cleanups
> 3. C11 atomic optimizations

That is a good idea. I will follow this order.

> 
> 
> > Thanks,
> > Phil
> 
> Thanks, and I'll get to reading/reviewing your and Honnappa's feedback later
> today.
> 
> -H

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3 07/12] service: remove rte prefix from static functions
  2020-04-08 10:14  0%       ` Phil Yang
@ 2020-04-08 10:36  0%         ` Van Haaren, Harry
  2020-04-08 10:49  0%           ` Phil Yang
  0 siblings, 1 reply; 200+ results
From: Van Haaren, Harry @ 2020-04-08 10:36 UTC (permalink / raw)
  To: Phil Yang, thomas, Ananyev, Konstantin, stephen, maxime.coquelin, dev
  Cc: david.marchand, jerinj, hemant.agrawal, Honnappa Nagarahalli,
	Gavin Hu, Ruifeng Wang, Joyce Kong, nd, stable, nd

> -----Original Message-----
> From: Phil Yang <Phil.Yang@arm.com>
> Sent: Wednesday, April 8, 2020 11:15 AM
> To: Van Haaren, Harry <harry.van.haaren@intel.com>; thomas@monjalon.net;
> Ananyev, Konstantin <konstantin.ananyev@intel.com>;
> stephen@networkplumber.org; maxime.coquelin@redhat.com; dev@dpdk.org
> Cc: david.marchand@redhat.com; jerinj@marvell.com; hemant.agrawal@nxp.com;
> Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>; Gavin Hu
> <Gavin.Hu@arm.com>; Ruifeng Wang <Ruifeng.Wang@arm.com>; Joyce Kong
> <Joyce.Kong@arm.com>; nd <nd@arm.com>; stable@dpdk.org; nd <nd@arm.com>
> Subject: RE: [PATCH v3 07/12] service: remove rte prefix from static functions
<snip>
> > Is this really a "Fix"? The internal function names were not exported
> > in the .map file, so are not part of public ABI. This is an internal
> > naming improvement (thanks for doing cleanup), but I don't think the
> > Fixes: tags make sense?
> >
> > Also I'm not sure if we want to port this patch back to stable? Changing
> > (internal) function names seems like unnecessary churn, and hence risk to a
> > stable release, without any benefit?
> OK.
> I will remove these tags in the next version and split the service core
> patches from the original series into a series by itself.

Cool - good idea to split.

Perhaps we should focus on getting bugfixes in for the existing code, before doing cleanup? It would make backports easier if churn is minimal.

Suggesting patches order (first to last)
1. bugfixes/things to backport
2. cleanups
3. C11 atomic optimizations


> Thanks,
> Phil

Thanks, and I'll get to reading/reviewing your and Honnappa's feedback later today.

-H 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3 07/12] service: remove rte prefix from static functions
  2020-04-03 11:57  3%     ` Van Haaren, Harry
@ 2020-04-08 10:14  0%       ` Phil Yang
  2020-04-08 10:36  0%         ` Van Haaren, Harry
  0 siblings, 1 reply; 200+ results
From: Phil Yang @ 2020-04-08 10:14 UTC (permalink / raw)
  To: Van Haaren, Harry, thomas, Ananyev, Konstantin, stephen,
	maxime.coquelin, dev
  Cc: david.marchand, jerinj, hemant.agrawal, Honnappa Nagarahalli,
	Gavin Hu, Ruifeng Wang, Joyce Kong, nd, stable, nd

> -----Original Message-----
> From: Van Haaren, Harry <harry.van.haaren@intel.com>
> Sent: Friday, April 3, 2020 7:58 PM
> To: Phil Yang <Phil.Yang@arm.com>; thomas@monjalon.net; Ananyev,
> Konstantin <konstantin.ananyev@intel.com>;
> stephen@networkplumber.org; maxime.coquelin@redhat.com;
> dev@dpdk.org
> Cc: david.marchand@redhat.com; jerinj@marvell.com;
> hemant.agrawal@nxp.com; Honnappa Nagarahalli
> <Honnappa.Nagarahalli@arm.com>; Gavin Hu <Gavin.Hu@arm.com>;
> Ruifeng Wang <Ruifeng.Wang@arm.com>; Joyce Kong
> <Joyce.Kong@arm.com>; nd <nd@arm.com>; stable@dpdk.org
> Subject: RE: [PATCH v3 07/12] service: remove rte prefix from static functions
> 
> > From: Phil Yang <phil.yang@arm.com>
> > Sent: Tuesday, March 17, 2020 1:18 AM
> > To: thomas@monjalon.net; Van Haaren, Harry
> <harry.van.haaren@intel.com>;
> > Ananyev, Konstantin <konstantin.ananyev@intel.com>;
> > stephen@networkplumber.org; maxime.coquelin@redhat.com;
> dev@dpdk.org
> > Cc: david.marchand@redhat.com; jerinj@marvell.com;
> hemant.agrawal@nxp.com;
> > Honnappa.Nagarahalli@arm.com; gavin.hu@arm.com;
> ruifeng.wang@arm.com;
> > joyce.kong@arm.com; nd@arm.com; stable@dpdk.org
> > Subject: [PATCH v3 07/12] service: remove rte prefix from static functions
> >
> > Fixes: 3cf5eb1546ed ("service: fix and refactor atomic service accesses")
> > Fixes: 21698354c832 ("service: introduce service cores concept")
> > Cc: stable@dpdk.org
> >
> > Signed-off-by: Phil Yang <phil.yang@arm.com>
> > Reviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>
> 
> 
> This patchset needs a rebase since the EAL file movement got merged,
> however I'll review here so we can include some Acks etc and make
> progress.
> 
> Is this really a "Fix"? The internal function names were not exported
> in the .map file, so are not part of public ABI. This is an internal
> naming improvement (thanks for doing cleanup), but I don't think the
> Fixes: tags make sense?
> 
> Also I'm not sure if we want to port this patch back to stable? Changing
> (internal) function names seems like unnecessary churn, and hence risk to a
> stable release, without any benefit?
OK.
I will remove these tags in the next version and split the service core patches from the original series into a series by itself.

Thanks,
Phil

> 
> ---
> 
> <snip patch diff>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-04-08  7:20  4%               ` Dodji Seketeli
@ 2020-04-08  7:52  0%                 ` Dodji Seketeli
  0 siblings, 0 replies; 200+ results
From: Dodji Seketeli @ 2020-04-08  7:52 UTC (permalink / raw)
  To: Dodji Seketeli
  Cc: Hemant Agrawal, David Marchand, Hemant Agrawal (OSS),
	Yigit, Ferruh, dev, Neil Horman, Thomas Monjalon

Hello Thomas, Hemant,

Thomas Monjalon <thomas@monjalon.net> writes:

> 07/04/2020 12:25, Hemant Agrawal:

[...]

>> [Hemant] I have commented on Neil's series.
>> It needs more changes in existing code.
>> An approach like __rte_experimental will work better.
>
> I guess you mean __rte_internal?
>
> Please Hemant don't wait for someone else filling the gap.
> If __rte_internal is the right approach, please complete and use it.

Just so that I understand, is __rte_internal an ELF version that the
symbols per_lcore_dpaa2_held_bufs, dpaa2_io_portal and
per_lcore__dpaa2_io should have in the binary?

If that is the case, then it seems to me that the __rte_internal
approach that you are suggesting would be a much better approach that
the one I replied to Hemant about below.

I didn't mean to tell Hemant what approach he should take :-) I was just
trying to help him get the syntax of a libabigail suppression
specification right.

Sorry for the confusion I might have induced.

Dodji Seketeli <dseketel@redhat.com> writes:

> Hello Hemant,
>
> Hemant Agrawal <hemant.agrawal@nxp.com> writes:
>
> [...]
>
>>> >> > > [Hemant]
>>> >> > > As per the logs:
>>> >> > >
>>> >> > > Variables changes summary: 1 Removed, 2 Changed, 0 Added
>>> >> > > variables
>>> >> > > 1 Removed variable:
>>> >> > >   'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'
>>> >> > {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
>>> >> > > 2 Changed variables:
>>> >> > >   [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at
>>> >> > dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
>>> >> > >   [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at
>>> >> > > dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16
>>> >> > >
>>> >> > > Error: ABI issue reported for 'abidiff --suppr
>>> >> > > devtools/libabigail.abignore --
>>> >> > no-added-syms --headers-dir1 reference/usr/local/include
>>> >> > --headers-dir2 install/usr/local/include
>>> >> > reference/dump/librte_bus_fslmc.dump
>>> >> > install/dump/librte_bus_fslmc.dump'
>
> [...]
>
>>> In the mean time, the tooling can be tought to ignore changes to these ELF
>>> symbols, as you you guys all know already.
>>> 
>> [Hemant] will you please help me about adding entry to libagigail.abignore 
>> I tried doing following, but it is not helping
>> --- a/devtools/libabigail.abignore
>> +++ b/devtools/libabigail.abignore
>> @@ -2,10 +2,15 @@
>>          symbol_version = EXPERIMENTAL
>>  [suppress_variable]
>>          symbol_version = EXPERIMENTAL
>> +       name = per_lcore__dpaa2_io
>> +       name = dpaa2_io_portal
>>
>>  ; Explicit ignore for driver-only ABI
>>  [suppress_type]
>>          name = rte_cryptodev_ops
>> +       name = dpaa2_io_portal_t
>
> So, I understand you want the tooling to ignore changes to the global
> arrays dpaa2_io_portal and per_lcore__dpaa2_io, right?
>
> If that is correct, then here are the entries you should add to the
> libabigail.abignore file (please make sure the comments I have added
> there is accurate):
>
>         [suppress_variable]
>           # This global variable is exported by the binary but is not part of
>           # the logical ABI.  In a perfect world, that variable should not be
>           # global, and we should access it via an accessor function.  We do
>           # that right now because of performance concerns.
>           name = dpaa2_io_portal
>
>         [suppress_variable]
>           # This global variable is exported by the binary but is not part of
>           # the logical ABI.  In a perfect world, that variable should not be
>           # global, and we should access it via an accessor function.  We do
>           # that right now because of performance concerns.
>           name = per_lcore__dpaa2_io
>
> I hope this helps.
>
> Cheers,

-- 
		Dodji


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-04-07 10:25  3%             ` Hemant Agrawal
  2020-04-07 12:20  0%               ` Thomas Monjalon
@ 2020-04-08  7:20  4%               ` Dodji Seketeli
  2020-04-08  7:52  0%                 ` Dodji Seketeli
  1 sibling, 1 reply; 200+ results
From: Dodji Seketeli @ 2020-04-08  7:20 UTC (permalink / raw)
  To: Hemant Agrawal
  Cc: Dodji Seketeli, David Marchand, Hemant Agrawal (OSS),
	Yigit, Ferruh, dev, Neil Horman, Thomas Monjalon

Hello Hemant,

Hemant Agrawal <hemant.agrawal@nxp.com> writes:

[...]

>> >> > > [Hemant]
>> >> > > As per the logs:
>> >> > >
>> >> > > Variables changes summary: 1 Removed, 2 Changed, 0 Added
>> >> > > variables
>> >> > > 1 Removed variable:
>> >> > >   'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'
>> >> > {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
>> >> > > 2 Changed variables:
>> >> > >   [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at
>> >> > dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
>> >> > >   [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at
>> >> > > dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16
>> >> > >
>> >> > > Error: ABI issue reported for 'abidiff --suppr
>> >> > > devtools/libabigail.abignore --
>> >> > no-added-syms --headers-dir1 reference/usr/local/include
>> >> > --headers-dir2 install/usr/local/include
>> >> > reference/dump/librte_bus_fslmc.dump
>> >> > install/dump/librte_bus_fslmc.dump'

[...]

>> In the mean time, the tooling can be tought to ignore changes to these ELF
>> symbols, as you you guys all know already.
>> 
> [Hemant] will you please help me about adding entry to libagigail.abignore 
> I tried doing following, but it is not helping
> --- a/devtools/libabigail.abignore
> +++ b/devtools/libabigail.abignore
> @@ -2,10 +2,15 @@
>          symbol_version = EXPERIMENTAL
>  [suppress_variable]
>          symbol_version = EXPERIMENTAL
> +       name = per_lcore__dpaa2_io
> +       name = dpaa2_io_portal
>
>  ; Explicit ignore for driver-only ABI
>  [suppress_type]
>          name = rte_cryptodev_ops
> +       name = dpaa2_io_portal_t

So, I understand you want the tooling to ignore changes to the global
arrays dpaa2_io_portal and per_lcore__dpaa2_io, right?

If that is correct, then here are the entries you should add to the
libabigail.abignore file (please make sure the comments I have added
there is accurate):

        [suppress_variable]
          # This global variable is exported by the binary but is not part of
          # the logical ABI.  In a perfect world, that variable should not be
          # global, and we should access it via an accessor function.  We do
          # that right now because of performance concerns.
          name = dpaa2_io_portal

        [suppress_variable]
          # This global variable is exported by the binary but is not part of
          # the logical ABI.  In a perfect world, that variable should not be
          # global, and we should access it via an accessor function.  We do
          # that right now because of performance concerns.
          name = per_lcore__dpaa2_io

I hope this helps.

Cheers,

-- 
		Dodji


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode
  2020-04-03 17:42  1%       ` [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode Konstantin Ananyev
  2020-04-04 17:27  0%         ` Wang, Haiyue
@ 2020-04-08  5:00  0%         ` Honnappa Nagarahalli
  1 sibling, 0 replies; 200+ results
From: Honnappa Nagarahalli @ 2020-04-08  5:00 UTC (permalink / raw)
  To: Konstantin Ananyev, dev
  Cc: david.marchand, jielong.zjl, Honnappa Nagarahalli, nd, nd

<snip>

> 
> Introduce relaxed tail sync (RTS) mode for MT ring synchronization.
> Aim to reduce stall times in case when ring is used on overcommited cpus
> (multiple active threads on the same cpu).
> The main difference from original MP/MC algorithm is that tail value is
> increased not by every thread that finished enqueue/dequeue, but only by the
> last one.
> That allows threads to avoid spinning on ring tail value, leaving actual tail
> value change to the last thread in the update queue.
> 
> check-abi.sh reports what I believe is a false-positive about ring cons/prod
> changes. As a workaround, devtools/libabigail.abignore is updated to suppress
> *struct ring* related errors.
This can be removed from the commit message.

> 
> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> ---
>  devtools/libabigail.abignore           |   7 +
>  lib/librte_ring/Makefile               |   5 +-
>  lib/librte_ring/meson.build            |   5 +-
>  lib/librte_ring/rte_ring.c             | 100 +++++++-
>  lib/librte_ring/rte_ring.h             | 110 ++++++++-
>  lib/librte_ring/rte_ring_elem.h        |  86 ++++++-
>  lib/librte_ring/rte_ring_rts.h         | 316 +++++++++++++++++++++++++
>  lib/librte_ring/rte_ring_rts_elem.h    | 205 ++++++++++++++++
>  lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++++++
>  9 files changed, 1015 insertions(+), 29 deletions(-)  create mode 100644
> lib/librte_ring/rte_ring_rts.h  create mode 100644
> lib/librte_ring/rte_ring_rts_elem.h
>  create mode 100644 lib/librte_ring/rte_ring_rts_generic.h
> 
> diff --git a/devtools/libabigail.abignore b/devtools/libabigail.abignore index
> a59df8f13..cd86d89ca 100644
> --- a/devtools/libabigail.abignore
> +++ b/devtools/libabigail.abignore
> @@ -11,3 +11,10 @@
>          type_kind = enum
>          name = rte_crypto_asym_xform_type
>          changed_enumerators = RTE_CRYPTO_ASYM_XFORM_TYPE_LIST_END
> +; Ignore updates of ring prod/cons
> +[suppress_type]
> +        type_kind = struct
> +        name = rte_ring
> +[suppress_type]
> +        type_kind = struct
> +        name = rte_event_ring
Does this block the reporting of these structures forever?

> diff --git a/lib/librte_ring/Makefile b/lib/librte_ring/Makefile index
> 917c560ad..8f5c284cc 100644
> --- a/lib/librte_ring/Makefile
> +++ b/lib/librte_ring/Makefile
> @@ -18,6 +18,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_RING) := rte_ring.c
> SYMLINK-$(CONFIG_RTE_LIBRTE_RING)-include := rte_ring.h \
>  					rte_ring_elem.h \
>  					rte_ring_generic.h \
> -					rte_ring_c11_mem.h
> +					rte_ring_c11_mem.h \
> +					rte_ring_rts.h \
> +					rte_ring_rts_elem.h \
> +					rte_ring_rts_generic.h
> 
>  include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_ring/meson.build b/lib/librte_ring/meson.build index
> f2f3ccc88..612936afb 100644
> --- a/lib/librte_ring/meson.build
> +++ b/lib/librte_ring/meson.build
> @@ -5,7 +5,10 @@ sources = files('rte_ring.c')  headers = files('rte_ring.h',
>  		'rte_ring_elem.h',
>  		'rte_ring_c11_mem.h',
> -		'rte_ring_generic.h')
> +		'rte_ring_generic.h',
> +		'rte_ring_rts.h',
> +		'rte_ring_rts_elem.h',
> +		'rte_ring_rts_generic.h')
> 
>  # rte_ring_create_elem and rte_ring_get_memsize_elem are experimental
> allow_experimental_apis = true diff --git a/lib/librte_ring/rte_ring.c
> b/lib/librte_ring/rte_ring.c index fa5733907..222eec0fb 100644
> --- a/lib/librte_ring/rte_ring.c
> +++ b/lib/librte_ring/rte_ring.c
> @@ -45,6 +45,9 @@ EAL_REGISTER_TAILQ(rte_ring_tailq)
>  /* true if x is a power of 2 */
>  #define POWEROF2(x) ((((x)-1) & (x)) == 0)
> 
> +/* by default set head/tail distance as 1/8 of ring capacity */
> +#define HTD_MAX_DEF	8
> +
>  /* return the size of memory occupied by a ring */  ssize_t
> rte_ring_get_memsize_elem(unsigned int esize, unsigned int count) @@ -
> 79,11 +82,84 @@ rte_ring_get_memsize(unsigned int count)
>  	return rte_ring_get_memsize_elem(sizeof(void *), count);  }
> 
> +/*
> + * internal helper function to reset prod/cons head-tail values.
> + */
> +static void
> +reset_headtail(void *p)
> +{
> +	struct rte_ring_headtail *ht;
> +	struct rte_ring_rts_headtail *ht_rts;
> +
> +	ht = p;
> +	ht_rts = p;
> +
> +	switch (ht->sync_type) {
> +	case RTE_RING_SYNC_MT:
> +	case RTE_RING_SYNC_ST:
> +		ht->head = 0;
> +		ht->tail = 0;
> +		break;
> +	case RTE_RING_SYNC_MT_RTS:
> +		ht_rts->head.raw = 0;
> +		ht_rts->tail.raw = 0;
> +		break;
> +	default:
> +		/* unknown sync mode */
> +		RTE_ASSERT(0);
> +	}
> +}
> +
>  void
>  rte_ring_reset(struct rte_ring *r)
>  {
> -	r->prod.head = r->cons.head = 0;
> -	r->prod.tail = r->cons.tail = 0;
> +	reset_headtail(&r->prod);
> +	reset_headtail(&r->cons);
> +}
> +
> +/*
> + * helper function, calculates sync_type values for prod and cons
> + * based on input flags. Returns zero at success or negative
> + * errno value otherwise.
> + */
> +static int
> +get_sync_type(uint32_t flags, enum rte_ring_sync_type *prod_st,
> +	enum rte_ring_sync_type *cons_st)
> +{
> +	static const uint32_t prod_st_flags =
> +		(RING_F_SP_ENQ | RING_F_MP_RTS_ENQ);
> +	static const uint32_t cons_st_flags =
> +		(RING_F_SC_DEQ | RING_F_MC_RTS_DEQ);
> +
> +	switch (flags & prod_st_flags) {
> +	case 0:
> +		*prod_st = RTE_RING_SYNC_MT;
> +		break;
> +	case RING_F_SP_ENQ:
> +		*prod_st = RTE_RING_SYNC_ST;
> +		break;
> +	case RING_F_MP_RTS_ENQ:
> +		*prod_st = RTE_RING_SYNC_MT_RTS;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	switch (flags & cons_st_flags) {
> +	case 0:
> +		*cons_st = RTE_RING_SYNC_MT;
> +		break;
> +	case RING_F_SC_DEQ:
> +		*cons_st = RTE_RING_SYNC_ST;
> +		break;
> +	case RING_F_MC_RTS_DEQ:
> +		*cons_st = RTE_RING_SYNC_MT_RTS;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
>  }
> 
>  int
> @@ -100,16 +176,20 @@ rte_ring_init(struct rte_ring *r, const char *name,
> unsigned count,
>  	RTE_BUILD_BUG_ON((offsetof(struct rte_ring, prod) &
>  			  RTE_CACHE_LINE_MASK) != 0);
> 
> +	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, sync_type) !=
> +		offsetof(struct rte_ring_rts_headtail, sync_type));
> +	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, tail) !=
> +		offsetof(struct rte_ring_rts_headtail, tail.val.pos));
> +
>  	/* init the ring structure */
>  	memset(r, 0, sizeof(*r));
>  	ret = strlcpy(r->name, name, sizeof(r->name));
>  	if (ret < 0 || ret >= (int)sizeof(r->name))
>  		return -ENAMETOOLONG;
>  	r->flags = flags;
> -	r->prod.sync_type = (flags & RING_F_SP_ENQ) ?
> -		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
> -	r->cons.sync_type = (flags & RING_F_SC_DEQ) ?
> -		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
> +	ret = get_sync_type(flags, &r->prod.sync_type, &r->cons.sync_type);
> +	if (ret != 0)
> +		return ret;
> 
>  	if (flags & RING_F_EXACT_SZ) {
>  		r->size = rte_align32pow2(count + 1); @@ -126,8 +206,12
> @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
>  		r->mask = count - 1;
>  		r->capacity = r->mask;
>  	}
> -	r->prod.head = r->cons.head = 0;
> -	r->prod.tail = r->cons.tail = 0;
> +
> +	/* set default values for head-tail distance */
> +	if (flags & RING_F_MP_RTS_ENQ)
> +		rte_ring_set_prod_htd_max(r, r->capacity / HTD_MAX_DEF);
> +	if (flags & RING_F_MC_RTS_DEQ)
> +		rte_ring_set_cons_htd_max(r, r->capacity / HTD_MAX_DEF);
> 
>  	return 0;
>  }
> diff --git a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h index
> d4775a063..f6f084d79 100644
> --- a/lib/librte_ring/rte_ring.h
> +++ b/lib/librte_ring/rte_ring.h
> @@ -48,6 +48,7 @@ extern "C" {
>  #include <rte_branch_prediction.h>
>  #include <rte_memzone.h>
>  #include <rte_pause.h>
> +#include <rte_debug.h>
> 
>  #define RTE_TAILQ_RING_NAME "RTE_RING"
> 
> @@ -65,10 +66,13 @@ enum rte_ring_queue_behavior {  enum
> rte_ring_sync_type {
>  	RTE_RING_SYNC_MT,     /**< multi-thread safe (default mode) */
>  	RTE_RING_SYNC_ST,     /**< single thread only */
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	RTE_RING_SYNC_MT_RTS, /**< multi-thread relaxed tail sync */
> #endif
>  };
> 
>  /**
> - * structure to hold a pair of head/tail values and other metadata.
> + * structures to hold a pair of head/tail values and other metadata.
>   * Depending on sync_type format of that structure might be different,
>   * but offset for *sync_type* and *tail* values should remain the same.
>   */
> @@ -84,6 +88,21 @@ struct rte_ring_headtail {
>  	};
>  };
> 
> +union rte_ring_ht_poscnt {
nit, this is specific to RTS, may be change this to rte_ring_rts_ht_poscnt?

> +	uint64_t raw;
> +	struct {
> +		uint32_t cnt; /**< head/tail reference counter */
> +		uint32_t pos; /**< head/tail position */
> +	} val;
> +};
> +
> +struct rte_ring_rts_headtail {
> +	volatile union rte_ring_ht_poscnt tail;
> +	enum rte_ring_sync_type sync_type;  /**< sync type of prod/cons */
> +	uint32_t htd_max;   /**< max allowed distance between head/tail */
> +	volatile union rte_ring_ht_poscnt head; };
> +
>  /**
>   * An RTE ring structure.
>   *
> @@ -111,11 +130,21 @@ struct rte_ring {
>  	char pad0 __rte_cache_aligned; /**< empty cache line */
> 
>  	/** Ring producer status. */
> -	struct rte_ring_headtail prod __rte_cache_aligned;
> +	RTE_STD_C11
> +	union {
> +		struct rte_ring_headtail prod;
> +		struct rte_ring_rts_headtail rts_prod;
> +	}  __rte_cache_aligned;
> +
>  	char pad1 __rte_cache_aligned; /**< empty cache line */
> 
>  	/** Ring consumer status. */
> -	struct rte_ring_headtail cons __rte_cache_aligned;
> +	RTE_STD_C11
> +	union {
> +		struct rte_ring_headtail cons;
> +		struct rte_ring_rts_headtail rts_cons;
> +	}  __rte_cache_aligned;
> +
>  	char pad2 __rte_cache_aligned; /**< empty cache line */  };
> 
> @@ -132,6 +161,9 @@ struct rte_ring {
>  #define RING_F_EXACT_SZ 0x0004
>  #define RTE_RING_SZ_MASK  (0x7fffffffU) /**< Ring size mask */
> 
> +#define RING_F_MP_RTS_ENQ 0x0008 /**< The default enqueue is "MP RTS".
> +*/ #define RING_F_MC_RTS_DEQ 0x0010 /**< The default dequeue is "MC
> +RTS". */
> +
>  #define __IS_SP RTE_RING_SYNC_ST
>  #define __IS_MP RTE_RING_SYNC_MT
>  #define __IS_SC RTE_RING_SYNC_ST
> @@ -461,6 +493,10 @@ rte_ring_sp_enqueue_bulk(struct rte_ring *r, void *
> const *obj_table,
>  			RTE_RING_SYNC_ST, free_space);
>  }
> 
> +#ifdef ALLOW_EXPERIMENTAL_API
> +#include <rte_ring_rts.h>
> +#endif
> +
>  /**
>   * Enqueue several objects on a ring.
>   *
> @@ -484,8 +520,21 @@ static __rte_always_inline unsigned int
> rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
>  		      unsigned int n, unsigned int *free_space)  {
> -	return __rte_ring_do_enqueue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -			r->prod.sync_type, free_space);
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_bulk(r, obj_table, n, free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_bulk(r, obj_table, n, free_space);
Have you validated if these affect the performance for the existing APIs?
I am also wondering why should we support these new modes in the legacy APIs?
I think users should move to use rte_ring_xxx_elem APIs. If users want to use RTS/HTS it will be a good time for them to move to new APIs. They anyway have to test their code for RTS/HTS, might as well make the change to new APIs and test both.
It will be less code to maintain for the community as well.

> #ifdef
> +ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_bulk(r, obj_table, n,
> +			free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  /**
> @@ -619,8 +668,20 @@ static __rte_always_inline unsigned int
> rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,
>  		unsigned int *available)
>  {
> -	return __rte_ring_do_dequeue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -				r->cons.sync_type, available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_bulk(r, obj_table, n, available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_bulk(r, obj_table, n, available);
> #ifdef
> +ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_bulk(r, obj_table, n,
> available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  /**
> @@ -940,8 +1001,21 @@ static __rte_always_inline unsigned
> rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table,
>  		      unsigned int n, unsigned int *free_space)  {
> -	return __rte_ring_do_enqueue(r, obj_table, n,
> RTE_RING_QUEUE_VARIABLE,
> -			r->prod.sync_type, free_space);
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_burst(r, obj_table, n,
> free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_burst(r, obj_table, n, free_space);
> #ifdef
> +ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_burst(r, obj_table, n,
> +			free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  /**
> @@ -1020,9 +1094,21 @@ static __rte_always_inline unsigned
> rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table,
>  		unsigned int n, unsigned int *available)  {
> -	return __rte_ring_do_dequeue(r, obj_table, n,
> -				RTE_RING_QUEUE_VARIABLE,
> -				r->cons.sync_type, available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_burst(r, obj_table, n, available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_burst(r, obj_table, n, available);
> #ifdef
> +ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_burst(r, obj_table, n,
> +			available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  #ifdef __cplusplus
> diff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h
> index 28f9836e6..5de0850dc 100644
> --- a/lib/librte_ring/rte_ring_elem.h
> +++ b/lib/librte_ring/rte_ring_elem.h
> @@ -542,6 +542,8 @@ rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r,
> const void *obj_table,
>  			RTE_RING_QUEUE_FIXED, __IS_SP, free_space);  }
> 
> +#include <rte_ring_rts_elem.h>
> +
>  /**
>   * Enqueue several objects on a ring.
>   *
> @@ -571,6 +573,26 @@ rte_ring_enqueue_bulk_elem(struct rte_ring *r,
> const void *obj_table,  {
>  	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
>  			RTE_RING_QUEUE_FIXED, r->prod.sync_type,
> free_space);
> +
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_bulk_elem(r, obj_table, esize, n,
> +			free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_bulk_elem(r, obj_table, esize, n,
> +			free_space);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_bulk_elem(r, obj_table,
> esize, n,
> +			free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (free_space != NULL)
> +		*free_space = 0;
> +	return 0;
>  }
> 
>  /**
> @@ -733,8 +755,25 @@ static __rte_always_inline unsigned int
> rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *available)  {
> -	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
> -			RTE_RING_QUEUE_FIXED, r->cons.sync_type,
> available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_bulk_elem(r, obj_table, esize, n,
> +			available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_bulk_elem(r, obj_table, esize, n,
> +			available);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_bulk_elem(r, obj_table,
> esize,
> +			n, available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (available != NULL)
> +		*available = 0;
> +	return 0;
>  }
> 
>  /**
> @@ -901,8 +940,25 @@ static __rte_always_inline unsigned
> rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *free_space)  {
> -	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
> -			RTE_RING_QUEUE_VARIABLE, r->prod.sync_type,
> free_space);
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_burst_elem(r, obj_table, esize, n,
> +			free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_burst_elem(r, obj_table, esize, n,
> +			free_space);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_burst_elem(r, obj_table,
> esize,
> +			n, free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (free_space != NULL)
> +		*free_space = 0;
> +	return 0;
>  }
> 
>  /**
> @@ -993,9 +1049,25 @@ static __rte_always_inline unsigned int
> rte_ring_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *available)  {
> -	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
> -				RTE_RING_QUEUE_VARIABLE,
> -				r->cons.sync_type, available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_burst_elem(r, obj_table, esize, n,
> +			available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_burst_elem(r, obj_table, esize, n,
> +			available);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_burst_elem(r, obj_table,
> esize,
> +			n, available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (available != NULL)
> +		*available = 0;
> +	return 0;
>  }
> 
>  #ifdef __cplusplus
> diff --git a/lib/librte_ring/rte_ring_rts.h b/lib/librte_ring/rte_ring_rts.h new
> file mode 100644 index 000000000..18404fe48
> --- /dev/null
> +++ b/lib/librte_ring/rte_ring_rts.h
IMO, we should not provide these APIs.

> @@ -0,0 +1,316 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * Copyright (c) 2010-2017 Intel Corporation
nit, the year should change to 2020? Look at others too.

> + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
> + * All rights reserved.
> + * Derived from FreeBSD's bufring.h
> + * Used as BSD-3 Licensed with permission from Kip Macy.
> + */
> +
> +#ifndef _RTE_RING_RTS_H_
> +#define _RTE_RING_RTS_H_
> +
> +/**
> + * @file rte_ring_rts.h
> + * @b EXPERIMENTAL: this API may change without prior notice
> + * It is not recommended to include this file directly.
> + * Please include <rte_ring.h> instead.
> + *
> + * Contains functions for Relaxed Tail Sync (RTS) ring mode.
> + * The main idea remains the same as for our original MP/MC
                                                                                 ^^^ the
> +synchronization
> + * mechanism.
> + * The main difference is that tail value is increased not
> + * by every thread that finished enqueue/dequeue,
> + * but only by the last one doing enqueue/dequeue.
should we say 'current last' or 'last thread at a given instance'?

> + * That allows threads to skip spinning on tail value,
> + * leaving actual tail value change to last thread in the update queue.
nit, I understand what you mean by 'update queue' here. IMO, we should remove it as it might confuse some.

> + * RTS requires 2 64-bit CAS for each enqueue(/dequeue) operation:
> + * one for head update, second for tail update.
> + * As a gain it allows thread to avoid spinning/waiting on tail value.
> + * In comparision original MP/MC algorithm requires one 32-bit CAS
> + * for head update and waiting/spinning on tail value.
> + *
> + * Brief outline:
> + *  - introduce refcnt for both head and tail.
Suggesting using the same names as used in the structures.

> + *  - increment head.refcnt for each head.value update
> + *  - write head:value and head:refcnt atomically (64-bit CAS)
> + *  - move tail.value ahead only when tail.refcnt + 1 == head.refcnt
May be add '(indicating that this is the last thread updating the tail)'

> + *  - increment tail.refcnt when each enqueue/dequeue op finishes
May be add 'otherwise' at the beginning.

> + *    (no matter is tail:value going to change or not)
nit                            ^^ if
> + *  - write tail.value and tail.recnt atomically (64-bit CAS)
> + *
> + * To avoid producer/consumer starvation:
> + *  - limit max allowed distance between head and tail value (HTD_MAX).
> + *    I.E. thread is allowed to proceed with changing head.value,
> + *    only when:  head.value - tail.value <= HTD_MAX
> + * HTD_MAX is an optional parameter.
> + * With HTD_MAX == 0 we'll have fully serialized ring -
> + * i.e. only one thread at a time will be able to enqueue/dequeue
> + * to/from the ring.
> + * With HTD_MAX >= ring.capacity - no limitation.
> + * By default HTD_MAX == ring.capacity / 8.
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <rte_ring_rts_generic.h>
> +
> +/**
> + * @internal Enqueue several objects on the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from
> ring
> + * @param free_space
> + *   returns the amount of space after the enqueue operation has finished
> + * @return
> + *   Actual number of objects enqueued.
> + *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_enqueue(struct rte_ring *r, void * const *obj_table,
> +		uint32_t n, enum rte_ring_queue_behavior behavior,
> +		uint32_t *free_space)
> +{
> +	uint32_t free, head;
> +
> +	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
> +
> +	if (n != 0) {
> +		ENQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
> +		__rte_ring_rts_update_tail(&r->rts_prod);
> +	}
> +
> +	if (free_space != NULL)
> +		*free_space = free - n;
> +	return n;
> +}
> +
> +/**
> + * @internal Dequeue several objects from the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to pull from the ring.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from
> ring
> + * @param available
> + *   returns the number of remaining ring entries after the dequeue has
> finished
> + * @return
> + *   - Actual number of objects dequeued.
> + *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_dequeue(struct rte_ring *r, void **obj_table,
> +		uint32_t n, enum rte_ring_queue_behavior behavior,
> +		uint32_t *available)
> +{
> +	uint32_t entries, head;
> +
> +	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
> +
> +	if (n != 0) {
> +		DEQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
> +		__rte_ring_rts_update_tail(&r->rts_cons);
> +	}
> +
> +	if (available != NULL)
> +		*available = entries - n;
> +	return n;
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   The number of objects enqueued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mp_rts_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
> +			 unsigned int n, unsigned int *free_space) {
> +	return __rte_ring_do_rts_enqueue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> +			free_space);
> +}
> +
> +/**
> + * Dequeue several objects from an RTS ring (multi-consumers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   The number of objects dequeued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mc_rts_dequeue_bulk(struct rte_ring *r, void **obj_table,
> +		unsigned int n, unsigned int *available) {
> +	return __rte_ring_do_rts_dequeue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> +			available);
> +}
> +
> +/**
> + * Return producer max Head-Tail-Distance (HTD).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   Producer HTD value, if producer is set in appropriate sync mode,
> + *   or UINT32_MAX otherwise.
> + */
> +__rte_experimental
> +static inline uint32_t
> +rte_ring_get_prod_htd_max(const struct rte_ring *r) {
> +	if (r->prod.sync_type == RTE_RING_SYNC_MT_RTS)
> +		return r->rts_prod.htd_max;
> +	return UINT32_MAX;
> +}
> +
> +/**
> + * Set producer max Head-Tail-Distance (HTD).
> + * Note that producer has to use appropriate sync mode (RTS).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param v
> + *   new HTD value to setup.
> + * @return
> + *   Zero on success, or negative error code otherwise.
> + */
> +__rte_experimental
> +static inline int
> +rte_ring_set_prod_htd_max(struct rte_ring *r, uint32_t v) {
> +	if (r->prod.sync_type != RTE_RING_SYNC_MT_RTS)
> +		return -ENOTSUP;
> +
> +	r->rts_prod.htd_max = v;
> +	return 0;
> +}
> +
> +/**
> + * Return consumer max Head-Tail-Distance (HTD).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   Consumer HTD value, if consumer is set in appropriate sync mode,
> + *   or UINT32_MAX otherwise.
> + */
> +__rte_experimental
> +static inline uint32_t
> +rte_ring_get_cons_htd_max(const struct rte_ring *r) {
> +	if (r->cons.sync_type == RTE_RING_SYNC_MT_RTS)
> +		return r->rts_cons.htd_max;
> +	return UINT32_MAX;
> +}
> +
> +/**
> + * Set consumer max Head-Tail-Distance (HTD).
> + * Note that consumer has to use appropriate sync mode (RTS).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param v
> + *   new HTD value to setup.
> + * @return
> + *   Zero on success, or negative error code otherwise.
> + */
> +__rte_experimental
> +static inline int
> +rte_ring_set_cons_htd_max(struct rte_ring *r, uint32_t v) {
> +	if (r->cons.sync_type != RTE_RING_SYNC_MT_RTS)
> +		return -ENOTSUP;
> +
> +	r->rts_cons.htd_max = v;
> +	return 0;
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   - n: Actual number of objects enqueued.
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mp_rts_enqueue_burst(struct rte_ring *r, void * const *obj_table,
> +			 unsigned int n, unsigned int *free_space) {
> +	return __rte_ring_do_rts_enqueue(r, obj_table, n,
> +			RTE_RING_QUEUE_VARIABLE, free_space); }
> +
> +/**
> + * Dequeue several objects from an RTS  ring (multi-consumers safe).
> + * When the requested objects are more than the available objects,
> + * only dequeue the actual number of objects.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   - n: Actual number of objects dequeued, 0 if ring is empty
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mc_rts_dequeue_burst(struct rte_ring *r, void **obj_table,
> +		unsigned int n, unsigned int *available) {
> +	return __rte_ring_do_rts_dequeue(r, obj_table, n,
> +			RTE_RING_QUEUE_VARIABLE, available); }
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_RING_RTS_H_ */
> diff --git a/lib/librte_ring/rte_ring_rts_elem.h
> b/lib/librte_ring/rte_ring_rts_elem.h
> new file mode 100644
> index 000000000..71a331b23
> --- /dev/null
> +++ b/lib/librte_ring/rte_ring_rts_elem.h
> @@ -0,0 +1,205 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * Copyright (c) 2010-2017 Intel Corporation
> + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
> + * All rights reserved.
> + * Derived from FreeBSD's bufring.h
> + * Used as BSD-3 Licensed with permission from Kip Macy.
> + */
> +
> +#ifndef _RTE_RING_RTS_ELEM_H_
> +#define _RTE_RING_RTS_ELEM_H_
> +
> +/**
> + * @file rte_ring_rts_elem.h
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * It is not recommended to include this file directly.
> + * Please include <rte_ring_elem.h> instead.
> + * Contains *ring_elem* functions for Relaxed Tail Sync (RTS) ring mode.
> + * for more details please refer to <rte_ring_rts.h>.
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <rte_ring_rts_generic.h>
> +
> +/**
> + * @internal Enqueue several objects on the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from
> ring
> + * @param free_space
> + *   returns the amount of space after the enqueue operation has finished
> + * @return
> + *   Actual number of objects enqueued.
> + *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_enqueue_elem(struct rte_ring *r, void * const *obj_table,
obj_table should be of type 'const void * obj_table' (looks like copy paste error). Please check the other APIs below too.

> +	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
'esize' is not documented in the comments above the function. You can copy the header from rte_ring_elem.h file. Please check other APIs as well.

> +	uint32_t *free_space)
> +{
> +	uint32_t free, head;
> +
> +	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
> +
> +	if (n != 0) {
> +		__rte_ring_enqueue_elems(r, head, obj_table, esize, n);
> +		__rte_ring_rts_update_tail(&r->rts_prod);
> +	}
> +
> +	if (free_space != NULL)
> +		*free_space = free - n;
> +	return n;
> +}
> +
> +/**
> + * @internal Dequeue several objects from the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to pull from the ring.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from
> ring
> + * @param available
> + *   returns the number of remaining ring entries after the dequeue has
> finished
> + * @return
> + *   - Actual number of objects dequeued.
> + *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_dequeue_elem(struct rte_ring *r, void **obj_table,
> +	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
> +	uint32_t *available)
> +{
> +	uint32_t entries, head;
> +
> +	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
> +
> +	if (n != 0) {
> +		__rte_ring_dequeue_elems(r, head, obj_table, esize, n);
> +		__rte_ring_rts_update_tail(&r->rts_cons);
> +	}
> +
> +	if (available != NULL)
> +		*available = entries - n;
> +	return n;
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   The number of objects enqueued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mp_rts_enqueue_bulk_elem(struct rte_ring *r, void * const
> *obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *free_space) {
> +	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
> +			RTE_RING_QUEUE_FIXED, free_space);
> +}
> +
> +/**
> + * Dequeue several objects from an RTS ring (multi-consumers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   The number of objects dequeued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mc_rts_dequeue_bulk_elem(struct rte_ring *r, void **obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *available) {
> +	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
> +		RTE_RING_QUEUE_FIXED, available);
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   - n: Actual number of objects enqueued.
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mp_rts_enqueue_burst_elem(struct rte_ring *r, void * const
> *obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *free_space) {
> +	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
> +			RTE_RING_QUEUE_VARIABLE, free_space); }
> +
> +/**
> + * Dequeue several objects from an RTS  ring (multi-consumers safe).
> + * When the requested objects are more than the available objects,
> + * only dequeue the actual number of objects.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   - n: Actual number of objects dequeued, 0 if ring is empty
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mc_rts_dequeue_burst_elem(struct rte_ring *r, void **obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *available) {
> +	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
> +			RTE_RING_QUEUE_VARIABLE, available); }
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_RING_RTS_ELEM_H_ */
> diff --git a/lib/librte_ring/rte_ring_rts_generic.h
> b/lib/librte_ring/rte_ring_rts_generic.h
> new file mode 100644
> index 000000000..f88460d47
> --- /dev/null
> +++ b/lib/librte_ring/rte_ring_rts_generic.h
I do not know the benefit to providing the generic version. Do you know why this was done in the legacy APIs?
If there is no performance difference between generic and C11 versions, should we just skip the generic version?
The oldest compiler in CI are GCC 4.8.5 and Clang 3.4.2 and C11 built-ins are supported earlier than these compiler versions.
I feel the code is growing exponentially in rte_ring library and we should try to cut non-value-ass code/APIs aggressively.

> @@ -0,0 +1,210 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * Copyright (c) 2010-2017 Intel Corporation
> + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
> + * All rights reserved.
> + * Derived from FreeBSD's bufring.h
> + * Used as BSD-3 Licensed with permission from Kip Macy.
> + */
> +
> +#ifndef _RTE_RING_RTS_GENERIC_H_
> +#define _RTE_RING_RTS_GENERIC_H_
> +
> +/**
> + * @file rte_ring_rts_generic.h
> + * It is not recommended to include this file directly,
> + * include <rte_ring.h> instead.
> + * Contains internal helper functions for Relaxed Tail Sync (RTS) ring mode.
> + * For more information please refer to <rte_ring_rts.h>.
> + */
> +
> +/**
> + * @internal This function updates tail values.
> + */
> +static __rte_always_inline void
> +__rte_ring_rts_update_tail(struct rte_ring_rts_headtail *ht) {
> +	union rte_ring_ht_poscnt h, ot, nt;
> +
> +	/*
> +	 * If there are other enqueues/dequeues in progress that
> +	 * might preceded us, then don't update tail with new value.
> +	 */
> +
> +	do {
> +		ot.raw = ht->tail.raw;
> +		rte_smp_rmb();
> +
> +		/* on 32-bit systems we have to do atomic read here */
> +		h.raw = rte_atomic64_read((rte_atomic64_t *)
> +			(uintptr_t)&ht->head.raw);
> +
> +		nt.raw = ot.raw;
> +		if (++nt.val.cnt == h.val.cnt)
> +			nt.val.pos = h.val.pos;
> +
> +	} while (rte_atomic64_cmpset(&ht->tail.raw, ot.raw, nt.raw) == 0); }
> +
> +/**
> + * @internal This function waits till head/tail distance wouldn't
> + * exceed pre-defined max value.
> + */
> +static __rte_always_inline void
> +__rte_ring_rts_head_wait(const struct rte_ring_rts_headtail *ht,
> +	union rte_ring_ht_poscnt *h)
> +{
> +	uint32_t max;
> +
> +	max = ht->htd_max;
> +	h->raw = ht->head.raw;
> +	rte_smp_rmb();
> +
> +	while (h->val.pos - ht->tail.val.pos > max) {
> +		rte_pause();
> +		h->raw = ht->head.raw;
> +		rte_smp_rmb();
> +	}
> +}
> +
> +/**
> + * @internal This function updates the producer head for enqueue.
> + *
> + * @param r
> + *   A pointer to the ring structure
> + * @param is_sp
> + *   Indicates whether multi-producer path is needed or not
> + * @param n
> + *   The number of elements we will want to enqueue, i.e. how far should the
> + *   head be moved
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from
> ring
> + * @param old_head
> + *   Returns head value as it was before the move, i.e. where enqueue starts
> + * @param new_head
> + *   Returns the current/new head value i.e. where enqueue finishes
> + * @param free_entries
> + *   Returns the amount of free space in the ring BEFORE head was moved
> + * @return
> + *   Actual number of objects enqueued.
> + *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline uint32_t
> +__rte_ring_rts_move_prod_head(struct rte_ring *r, uint32_t num,
> +	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
> +	uint32_t *free_entries)
> +{
> +	uint32_t n;
> +	union rte_ring_ht_poscnt nh, oh;
> +
> +	const uint32_t capacity = r->capacity;
> +
> +	do {
> +		/* Reset n to the initial burst count */
> +		n = num;
> +
> +		/* read prod head (may spin on prod tail) */
> +		__rte_ring_rts_head_wait(&r->rts_prod, &oh);
> +
> +		/* add rmb barrier to avoid load/load reorder in weak
> +		 * memory model. It is noop on x86
> +		 */
> +		rte_smp_rmb();
> +
> +		/*
> +		 *  The subtraction is done between two unsigned 32bits value
> +		 * (the result is always modulo 32 bits even if we have
> +		 * *old_head > cons_tail). So 'free_entries' is always between
> 0
> +		 * and capacity (which is < size).
> +		 */
> +		*free_entries = capacity + r->cons.tail - oh.val.pos;
> +
> +		/* check that we have enough room in ring */
> +		if (unlikely(n > *free_entries))
> +			n = (behavior == RTE_RING_QUEUE_FIXED) ?
> +					0 : *free_entries;
> +
> +		if (n == 0)
> +			break;
> +
> +		nh.val.pos = oh.val.pos + n;
> +		nh.val.cnt = oh.val.cnt + 1;
> +
> +	} while (rte_atomic64_cmpset(&r->rts_prod.head.raw,
> +			oh.raw, nh.raw) == 0);
> +
> +	*old_head = oh.val.pos;
> +	return n;
> +}
> +
> +/**
> + * @internal This function updates the consumer head for dequeue
> + *
> + * @param r
> + *   A pointer to the ring structure
> + * @param is_sc
> + *   Indicates whether multi-consumer path is needed or not
> + * @param n
> + *   The number of elements we will want to enqueue, i.e. how far should the
> + *   head be moved
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from
> ring
> + * @param old_head
> + *   Returns head value as it was before the move, i.e. where dequeue starts
> + * @param new_head
> + *   Returns the current/new head value i.e. where dequeue finishes
> + * @param entries
> + *   Returns the number of entries in the ring BEFORE head was moved
> + * @return
> + *   - Actual number of objects dequeued.
> + *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_rts_move_cons_head(struct rte_ring *r, uint32_t num,
> +	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
> +	uint32_t *entries)
> +{
> +	uint32_t n;
> +	union rte_ring_ht_poscnt nh, oh;
> +
> +	/* move cons.head atomically */
> +	do {
> +		/* Restore n as it may change every loop */
> +		n = num;
> +
> +		/* read cons head (may spin on cons tail) */
> +		__rte_ring_rts_head_wait(&r->rts_cons, &oh);
> +
> +
> +		/* add rmb barrier to avoid load/load reorder in weak
> +		 * memory model. It is noop on x86
> +		 */
> +		rte_smp_rmb();
> +
> +		/* The subtraction is done between two unsigned 32bits value
> +		 * (the result is always modulo 32 bits even if we have
> +		 * cons_head > prod_tail). So 'entries' is always between 0
> +		 * and size(ring)-1.
> +		 */
> +		*entries = r->prod.tail - oh.val.pos;
> +
> +		/* Set the actual entries for dequeue */
> +		if (n > *entries)
> +			n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 :
> *entries;
> +
> +		if (unlikely(n == 0))
> +			break;
> +
> +		nh.val.pos = oh.val.pos + n;
> +		nh.val.cnt = oh.val.cnt + 1;
> +
> +	} while (rte_atomic64_cmpset(&r->rts_cons.head.raw,
> +			oh.raw, nh.raw) == 0);
> +
> +	*old_head = oh.val.pos;
> +	return n;
> +}
> +
> +#endif /* _RTE_RING_RTS_GENERIC_H_ */
> --
> 2.17.1


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3 2/9] ring: prepare ring to allow new sync schemes
  @ 2020-04-08  4:59  3%         ` Honnappa Nagarahalli
  0 siblings, 0 replies; 200+ results
From: Honnappa Nagarahalli @ 2020-04-08  4:59 UTC (permalink / raw)
  To: Konstantin Ananyev, dev
  Cc: david.marchand, jielong.zjl, nd, Honnappa Nagarahalli, nd

<snip>

> Subject: [PATCH v3 2/9] ring: prepare ring to allow new sync schemes
> 
> Change from *single* to *sync_type* to allow different synchronisation
> schemes to be applied.
> Mark *single* as deprecated in comments.
> Add new functions to allow user to query ring sync types.
> Replace direct access to *single* with appopriate function call.
> 
> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> ---
>  app/test/test_pdump.c           |   6 +-
>  lib/librte_pdump/rte_pdump.c    |   2 +-
>  lib/librte_port/rte_port_ring.c |  12 ++--
>  lib/librte_ring/rte_ring.c      |   6 +-
>  lib/librte_ring/rte_ring.h      | 113 ++++++++++++++++++++++++++------
>  lib/librte_ring/rte_ring_elem.h |   8 +--
>  6 files changed, 108 insertions(+), 39 deletions(-)
> 
> diff --git a/app/test/test_pdump.c b/app/test/test_pdump.c index
> ad183184c..6a1180bcb 100644
> --- a/app/test/test_pdump.c
> +++ b/app/test/test_pdump.c
> @@ -57,8 +57,7 @@ run_pdump_client_tests(void)
>  	if (ret < 0)
>  		return -1;
>  	mp->flags = 0x0000;
> -	ring_client = rte_ring_create("SR0", RING_SIZE, rte_socket_id(),
> -				      RING_F_SP_ENQ | RING_F_SC_DEQ);
> +	ring_client = rte_ring_create("SR0", RING_SIZE, rte_socket_id(), 0);
Are you saying to get SP and SC behavior we now have to set the flags to 0? Isn't that a ABI break?

>  	if (ring_client == NULL) {
>  		printf("rte_ring_create SR0 failed");
>  		return -1;
> @@ -71,9 +70,6 @@ run_pdump_client_tests(void)
>  	}
>  	rte_eth_dev_probing_finish(eth_dev);
> 
> -	ring_client->prod.single = 0;
> -	ring_client->cons.single = 0;
Just wondering if users outside of DPDK have done the same. I hope not, otherwise, we have an API break?

> -
>  	printf("\n***** flags = RTE_PDUMP_FLAG_TX *****\n");
> 
>  	for (itr = 0; itr < NUM_ITR; itr++) {
> diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
> index 8a01ac510..65364f2c5 100644
> --- a/lib/librte_pdump/rte_pdump.c
> +++ b/lib/librte_pdump/rte_pdump.c
> @@ -380,7 +380,7 @@ pdump_validate_ring_mp(struct rte_ring *ring, struct
> rte_mempool *mp)
>  		rte_errno = EINVAL;
>  		return -1;
>  	}
> -	if (ring->prod.single || ring->cons.single) {
> +	if (rte_ring_prod_single(ring) || rte_ring_cons_single(ring)) {
>  		PDUMP_LOG(ERR, "ring with either SP or SC settings"
>  		" is not valid for pdump, should have MP and MC settings\n");
>  		rte_errno = EINVAL;
> diff --git a/lib/librte_port/rte_port_ring.c b/lib/librte_port/rte_port_ring.c
> index 47fcdd06a..2f6c050fa 100644
> --- a/lib/librte_port/rte_port_ring.c
> +++ b/lib/librte_port/rte_port_ring.c
> @@ -44,8 +44,8 @@ rte_port_ring_reader_create_internal(void *params, int
> socket_id,
>  	/* Check input parameters */
>  	if ((conf == NULL) ||
>  		(conf->ring == NULL) ||
> -		(conf->ring->cons.single && is_multi) ||
> -		(!(conf->ring->cons.single) && !is_multi)) {
> +		(rte_ring_cons_single(conf->ring) && is_multi) ||
> +		(!rte_ring_cons_single(conf->ring) && !is_multi)) {
>  		RTE_LOG(ERR, PORT, "%s: Invalid Parameters\n", __func__);
>  		return NULL;
>  	}
> @@ -171,8 +171,8 @@ rte_port_ring_writer_create_internal(void *params,
> int socket_id,
>  	/* Check input parameters */
>  	if ((conf == NULL) ||
>  		(conf->ring == NULL) ||
> -		(conf->ring->prod.single && is_multi) ||
> -		(!(conf->ring->prod.single) && !is_multi) ||
> +		(rte_ring_prod_single(conf->ring) && is_multi) ||
> +		(!rte_ring_prod_single(conf->ring) && !is_multi) ||
>  		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {
>  		RTE_LOG(ERR, PORT, "%s: Invalid Parameters\n", __func__);
>  		return NULL;
> @@ -440,8 +440,8 @@ rte_port_ring_writer_nodrop_create_internal(void
> *params, int socket_id,
>  	/* Check input parameters */
>  	if ((conf == NULL) ||
>  		(conf->ring == NULL) ||
> -		(conf->ring->prod.single && is_multi) ||
> -		(!(conf->ring->prod.single) && !is_multi) ||
> +		(rte_ring_prod_single(conf->ring) && is_multi) ||
> +		(!rte_ring_prod_single(conf->ring) && !is_multi) ||
>  		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {
>  		RTE_LOG(ERR, PORT, "%s: Invalid Parameters\n", __func__);
>  		return NULL;
> diff --git a/lib/librte_ring/rte_ring.c b/lib/librte_ring/rte_ring.c index
> 77e5de099..fa5733907 100644
> --- a/lib/librte_ring/rte_ring.c
> +++ b/lib/librte_ring/rte_ring.c
> @@ -106,8 +106,10 @@ rte_ring_init(struct rte_ring *r, const char *name,
> unsigned count,
>  	if (ret < 0 || ret >= (int)sizeof(r->name))
>  		return -ENAMETOOLONG;
>  	r->flags = flags;
> -	r->prod.single = (flags & RING_F_SP_ENQ) ? __IS_SP : __IS_MP;
> -	r->cons.single = (flags & RING_F_SC_DEQ) ? __IS_SC : __IS_MC;
> +	r->prod.sync_type = (flags & RING_F_SP_ENQ) ?
> +		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
> +	r->cons.sync_type = (flags & RING_F_SC_DEQ) ?
> +		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
> 
>  	if (flags & RING_F_EXACT_SZ) {
>  		r->size = rte_align32pow2(count + 1); diff --git
> a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h index
> 18fc5d845..d4775a063 100644
> --- a/lib/librte_ring/rte_ring.h
> +++ b/lib/librte_ring/rte_ring.h
> @@ -61,11 +61,27 @@ enum rte_ring_queue_behavior {  #define
> RTE_RING_NAMESIZE (RTE_MEMZONE_NAMESIZE - \
>  			   sizeof(RTE_RING_MZ_PREFIX) + 1)
> 
> -/* structure to hold a pair of head/tail values and other metadata */
> +/** prod/cons sync types */
> +enum rte_ring_sync_type {
> +	RTE_RING_SYNC_MT,     /**< multi-thread safe (default mode) */
> +	RTE_RING_SYNC_ST,     /**< single thread only */
> +};
> +
> +/**
> + * structure to hold a pair of head/tail values and other metadata.
> + * Depending on sync_type format of that structure might be different,
> + * but offset for *sync_type* and *tail* values should remain the same.
> + */
>  struct rte_ring_headtail {
> -	volatile uint32_t head;  /**< Prod/consumer head. */
> -	volatile uint32_t tail;  /**< Prod/consumer tail. */
> -	uint32_t single;         /**< True if single prod/cons */
> +	volatile uint32_t head;      /**< prod/consumer head. */
> +	volatile uint32_t tail;      /**< prod/consumer tail. */
> +	RTE_STD_C11
> +	union {
> +		/** sync type of prod/cons */
> +		enum rte_ring_sync_type sync_type;
> +		/** deprecated -  True if single prod/cons */
> +		uint32_t single;
> +	};
>  };
> 
>  /**
> @@ -116,11 +132,10 @@ struct rte_ring {
>  #define RING_F_EXACT_SZ 0x0004
>  #define RTE_RING_SZ_MASK  (0x7fffffffU) /**< Ring size mask */
> 
> -/* @internal defines for passing to the enqueue dequeue worker functions
> */ -#define __IS_SP 1 -#define __IS_MP 0 -#define __IS_SC 1 -#define
> __IS_MC 0
> +#define __IS_SP RTE_RING_SYNC_ST
> +#define __IS_MP RTE_RING_SYNC_MT
> +#define __IS_SC RTE_RING_SYNC_ST
> +#define __IS_MC RTE_RING_SYNC_MT
I think we can remove these #defines and use the new SYNC types

> 
>  /**
>   * Calculate the memory size needed for a ring @@ -420,7 +435,7 @@
> rte_ring_mp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
>  			 unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -			__IS_MP, free_space);
> +			RTE_RING_SYNC_MT, free_space);
>  }
> 
>  /**
> @@ -443,7 +458,7 @@ rte_ring_sp_enqueue_bulk(struct rte_ring *r, void *
> const *obj_table,
>  			 unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -			__IS_SP, free_space);
> +			RTE_RING_SYNC_ST, free_space);
>  }
> 
>  /**
> @@ -470,7 +485,7 @@ rte_ring_enqueue_bulk(struct rte_ring *r, void *
> const *obj_table,
>  		      unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -			r->prod.single, free_space);
> +			r->prod.sync_type, free_space);
>  }
> 
>  /**
> @@ -554,7 +569,7 @@ rte_ring_mc_dequeue_bulk(struct rte_ring *r, void
> **obj_table,
>  		unsigned int n, unsigned int *available)  {
>  	return __rte_ring_do_dequeue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -			__IS_MC, available);
> +			RTE_RING_SYNC_MT, available);
>  }
> 
>  /**
> @@ -578,7 +593,7 @@ rte_ring_sc_dequeue_bulk(struct rte_ring *r, void
> **obj_table,
>  		unsigned int n, unsigned int *available)  {
>  	return __rte_ring_do_dequeue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -			__IS_SC, available);
> +			RTE_RING_SYNC_ST, available);
>  }
> 
>  /**
> @@ -605,7 +620,7 @@ rte_ring_dequeue_bulk(struct rte_ring *r, void
> **obj_table, unsigned int n,
>  		unsigned int *available)
>  {
>  	return __rte_ring_do_dequeue(r, obj_table, n,
> RTE_RING_QUEUE_FIXED,
> -				r->cons.single, available);
> +				r->cons.sync_type, available);
>  }
> 
>  /**
> @@ -777,6 +792,62 @@ rte_ring_get_capacity(const struct rte_ring *r)
>  	return r->capacity;
>  }
> 
> +/**
> + * Return sync type used by producer in the ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   Producer sync type value.
> + */
> +static inline enum rte_ring_sync_type
> +rte_ring_get_prod_sync_type(const struct rte_ring *r) {
> +	return r->prod.sync_type;
> +}
> +
> +/**
> + * Check is the ring for single producer.
                     ^^ if
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   true if ring is SP, zero otherwise.
> + */
> +static inline int
> +rte_ring_prod_single(const struct rte_ring *r) {
would rte_ring_is_prod_single better?

> +	return (rte_ring_get_prod_sync_type(r) == RTE_RING_SYNC_ST); }
> +
> +/**
> + * Return sync type used by consumer in the ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   Consumer sync type value.
> + */
> +static inline enum rte_ring_sync_type
> +rte_ring_get_cons_sync_type(const struct rte_ring *r) {
> +	return r->cons.sync_type;
> +}
> +
> +/**
> + * Check is the ring for single consumer.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   true if ring is SC, zero otherwise.
> + */
> +static inline int
> +rte_ring_cons_single(const struct rte_ring *r) {
> +	return (rte_ring_get_cons_sync_type(r) == RTE_RING_SYNC_ST); }
> +
All these new functions are  not required to be called in the data path. They can be made non-inline.

>  /**
>   * Dump the status of all rings on the console
>   *
> @@ -820,7 +891,7 @@ rte_ring_mp_enqueue_burst(struct rte_ring *r, void *
> const *obj_table,
>  			 unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue(r, obj_table, n,
> -			RTE_RING_QUEUE_VARIABLE, __IS_MP, free_space);
> +			RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_MT,
> free_space);
>  }
> 
>  /**
> @@ -843,7 +914,7 @@ rte_ring_sp_enqueue_burst(struct rte_ring *r, void *
> const *obj_table,
>  			 unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue(r, obj_table, n,
> -			RTE_RING_QUEUE_VARIABLE, __IS_SP, free_space);
> +			RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_ST,
> free_space);
>  }
> 
>  /**
> @@ -870,7 +941,7 @@ rte_ring_enqueue_burst(struct rte_ring *r, void *
> const *obj_table,
>  		      unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue(r, obj_table, n,
> RTE_RING_QUEUE_VARIABLE,
> -			r->prod.single, free_space);
> +			r->prod.sync_type, free_space);
>  }
> 
>  /**
> @@ -898,7 +969,7 @@ rte_ring_mc_dequeue_burst(struct rte_ring *r, void
> **obj_table,
>  		unsigned int n, unsigned int *available)  {
>  	return __rte_ring_do_dequeue(r, obj_table, n,
> -			RTE_RING_QUEUE_VARIABLE, __IS_MC, available);
> +			RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_MT,
> available);
>  }
> 
>  /**
> @@ -923,7 +994,7 @@ rte_ring_sc_dequeue_burst(struct rte_ring *r, void
> **obj_table,
>  		unsigned int n, unsigned int *available)  {
>  	return __rte_ring_do_dequeue(r, obj_table, n,
> -			RTE_RING_QUEUE_VARIABLE, __IS_SC, available);
> +			RTE_RING_QUEUE_VARIABLE, RTE_RING_SYNC_ST,
> available);
>  }
> 
>  /**
> @@ -951,7 +1022,7 @@ rte_ring_dequeue_burst(struct rte_ring *r, void
> **obj_table,  {
>  	return __rte_ring_do_dequeue(r, obj_table, n,
>  				RTE_RING_QUEUE_VARIABLE,
> -				r->cons.single, available);
> +				r->cons.sync_type, available);
>  }
> 
>  #ifdef __cplusplus
> diff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h
> index 663addc73..28f9836e6 100644
> --- a/lib/librte_ring/rte_ring_elem.h
> +++ b/lib/librte_ring/rte_ring_elem.h
> @@ -570,7 +570,7 @@ rte_ring_enqueue_bulk_elem(struct rte_ring *r, const
> void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
> -			RTE_RING_QUEUE_FIXED, r->prod.single, free_space);
> +			RTE_RING_QUEUE_FIXED, r->prod.sync_type,
> free_space);
>  }
> 
>  /**
> @@ -734,7 +734,7 @@ rte_ring_dequeue_bulk_elem(struct rte_ring *r, void
> *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *available)  {
>  	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
> -			RTE_RING_QUEUE_FIXED, r->cons.single, available);
> +			RTE_RING_QUEUE_FIXED, r->cons.sync_type,
> available);
>  }
> 
>  /**
> @@ -902,7 +902,7 @@ rte_ring_enqueue_burst_elem(struct rte_ring *r,
> const void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *free_space)  {
>  	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
> -			RTE_RING_QUEUE_VARIABLE, r->prod.single,
> free_space);
> +			RTE_RING_QUEUE_VARIABLE, r->prod.sync_type,
> free_space);
>  }
> 
>  /**
> @@ -995,7 +995,7 @@ rte_ring_dequeue_burst_elem(struct rte_ring *r, void
> *obj_table,  {
>  	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
>  				RTE_RING_QUEUE_VARIABLE,
> -				r->cons.single, available);
> +				r->cons.sync_type, available);
>  }
> 
>  #ifdef __cplusplus
> --
> 2.17.1


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-07 11:58  5%     ` Thomas Monjalon
@ 2020-04-07 19:52  3%       ` Neil Horman
  2020-04-08 14:34  0%       ` Ray Kinsella
  1 sibling, 0 replies; 200+ results
From: Neil Horman @ 2020-04-07 19:52 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: David Marchand, Kevin Laatz, mdr, dev

On Tue, Apr 07, 2020 at 01:58:57PM +0200, Thomas Monjalon wrote:
> 07/04/2020 13:33, Neil Horman:
> > On Tue, Apr 07, 2020 at 09:36:17AM +0200, David Marchand wrote:
> > > On Mon, Apr 6, 2020 at 9:34 PM Neil Horman <nhorman@tuxdriver.com> wrote:
> > > >
> > > > Since we've moved away from our initial abi_versioning.sh script, in
> > > 
> > > abi_versioning.sh does not exist (idem with the patch title).
> > > I suppose you meant validate-abi.sh.
> > > 
> > Crud, you're right, I was convoluting terms, sorry.  Shall I repost with a
> > corrected changelog?
> 
> Not only the commit log, look below how you did not care about the basic
> usage of the new tool.
> 
> 
> > > > favor of check_abi.sh, which uses libabigail, remove the old script from
> > > 
> > > check-abi.sh
> > > 
> > > > the tree, and update the docs accordingly
> [...]
> > > > --- a/doc/guides/contributing/abi_versioning.rst
> > > > +++ b/doc/guides/contributing/abi_versioning.rst
> 
> The maintainer of doc/guides/contributing/abi_*.rst
> is Ray Kinsella so I add him as Cc.
> 
> [...]
> > > > -The syntax of the ``validate-abi.sh`` utility is::
> > > > +The syntax of the ``check-abi.sh`` utility is::
> > > >
> > > > -   ./devtools/validate-abi.sh <REV1> <REV2>
> > > > +   ./devtools/check-abi.sh <REV1> <REV2>
> > > 
> > > The new script is not a direct replacement.
> > > It won't take git revisions, but build directories where versions of
> > > dpdk have been compiled.
> > > 
> > > devtools/test-build.sh and devtools/test-meson-builds.sh illustrate its use.
> > > https://git.dpdk.org/dpdk/tree/devtools/test-meson-builds.sh#n127
> 
> David, I think Neil did not take time to understand what changed in
> ABI tooling.
> I really wonder who is the real maintainer of ABI tooling and policy.
> Neil, Ray, I was expecting a better involvement in this major
> policy enforcement.
> 
> This is where we are:
> 	- Neil asked first for ABI compatibility
> 	- Neil created validate-abi.sh
> 	- Ray asked for a strict policy
> 	- Kevin worked on a new tooling
> 	- David completed the tooling work
> 	- David integrated ABI checks in Travis
> 
> There are many people partly involved.
> I think we need one person truly involved in ABI questions,
> someone who feels responsible and will take care of details
> like the documentation update requested above.
> 
> Please don't rely on David and myself, we are already very busy
> with making sure every patches are properly reviewed.
> We need good help on the ABI topic in general.
> 
We're all very busy Thomas, theres no need to get bent out of shape.  You're
right, I thought this was easier than it was, thinking that check-abi.sh was
interface compatible, apologies. I'm going through this more carefully, and will
repost soon.

FWIW, I don't think I'll be able to fill this role full time.  I'm not sure if
anyone else is either, i'm afraid.
Neil

> 
> 

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2 0/4] introduce multi-function processing support
  @ 2020-04-07 18:05  2%     ` Trahe, Fiona
  0 siblings, 0 replies; 200+ results
From: Trahe, Fiona @ 2020-04-07 18:05 UTC (permalink / raw)
  To: Coyle, David, Yigit, Ferruh, dev
  Cc: Doherty, Declan, De Lara Guarch, Pablo, Ryan, Brendan,
	shreyansh.jain, hemant.agrawal, Akhil Goyal, Trahe, Fiona

Hi David, Ferruh,

> -----Original Message-----
> From: Coyle, David <david.coyle@intel.com>
> Sent: Tuesday, April 7, 2020 12:28 PM
> To: Yigit, Ferruh <ferruh.yigit@intel.com>; dev@dpdk.org
> Cc: Doherty, Declan <declan.doherty@intel.com>; Trahe, Fiona <fiona.trahe@intel.com>; De Lara
> Guarch, Pablo <pablo.de.lara.guarch@intel.com>; Ryan, Brendan <brendan.ryan@intel.com>;
> shreyansh.jain@nxp.com; hemant.agrawal@nxp.com; Akhil Goyal <akhil.goyal@nxp.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/4] introduce multi-function processing support
> 
> Hi Ferruh, see below
> 
> > >
> > > While DPDK's rte_cryptodev and rte_compressdev allow many
> > > cryptographic and compression algorithms to be chained together in one
> > > operation, there is no way to chain these with any error detection or
> > > checksum algorithms. And there is no way to chain crypto and
> > > compression algorithms together. The multi-function  interface will
> > > allow these chains to be created, and also allow any future type of
> > operation to be easily added.
> >
> > I was thinking if the cryptodev can be used instead but this paragraph already
> > seems explained it. But again can you please elaborate why rawdev is used?
> 
> [DC] There are a number of reasons the rawdev approach was ultimately chosen:
> 
> 1) As the paragraph above explains, our primary use-case was to chain a crypto operation with error
> detection algorithms such as CRC or BIP as this could leverage optimized multi-function
> implementations such as in the IPSec Multi-Buffer library and have a significant impact on
> performance of network access dataplane processing such as for vCMTS (DOCSIS MAC).
> However such error detection algorithms are not Crypto functions so some early advice we took was
> that it would not be suitable to add these to cryptodev.
> Also, with a view to the future, the multi-function rawdev approach allows crypto operations to be
> chained with compression operations.
> Again, neither cryptodev or compressdev allows this type chaining.
> 
> 2) An earlier version of multi-function suggested adding a new library called rte_accelerator, as
> described here http://mails.dpdk.org/archives/dev/2020-February/157045.html
> We received some comments on the dev mailing list that we should not add yet another acceleration
> library to DPDK.
> And we also subsequently felt that the rawdev approach is better - that rationale is described below.
> 
> rte_accelerator was also built on top of crypto and compress devices which already existed e.g.
> drivers/crypto/aesni_mb, drivers/crypto/qat and drivers/compress/qat .
> We subsequently realized that this was somewhat confusing when performing multi-function type
> operations. For example, for combined Crypto-Compression operations in the future, it would use
> either an existing crypto or compress device, but neither really made sense when the operations are
> combined.
> What was needed was a raw device which allowed an application to configure any type of device and
> it's queue pairs and send any type of operation to that device.
> 
> For both of these reasons, we decided to go down the rawdev route, with a multi-function interface
> which can be used by several raw device drivers.
> 
> 3) rawdev is the ideal place to try out a new approach like this to accessing devices.
> Adding it here allows potential consumers of this such as VNF solution providers to study and try out
> this approach, and take advantage of the multi-function operations already supported in the IPSec
> Multi-Buffer library such as Crypto-CRC and Crypto-CRC-BIP, all without DPDK committing to a new
> library upfront.
> We would hope that the multi-function rawdev approach will mature over time (through feedback
> from customers, new use-cases arising etc.), at which point it could be potentially be moved into the
> main DPDK library set.
> 
[Fiona] agree with above, in particular item (2). Just to expand a bit more on this: To do a crypto+compression op
one would only send one op to one device. That device could have been either a crypto device which also
implemented multi-fn, by adding compression, crc, etc to its capabilities OR a compression device which added crypto, crc, bip capabilities.
Both were confusing and both raised questions about whether one could still do "normal" ops on the device, e.g. whether
a normal crypto op could be interleaved on same qp as a multi-fn op. And how the capabilities would reflect what the device could do.
It seems better to me to have a multifn device, which does explicitly just multifn ops.

Building this on top of rawdev is a good fit in my opinion, for the following reasons:
 * avoids duplication of device APIs, as rawdev configure, start, stop, qp_setup, etc are all there already, also a nice set of stats APIs
 * no impact or dependency added to rawdev lib
 * avoids breakages on cryptodev or compressdev APIs
 * avoids code duplication where functionality is already in a lib, e.g. re-uses cryptodev and compressdev headers. This adds a dependency, but I think that's ok as multi-function inherently depends on these functions.
 * allows easy extension to add new functionality not currently available in any lib (CRC and BIP)
 * allows evolution - range of useful chains which may emerge is not yet clear.

I do have some concerns, but these are resolvable in my opinion.
    (A)    as there's no rawdev capability APIs and capabilities are essentially opaque to the rawdev API, the application uses explicit device naming to create or find a device that it knows will fulfil the multifunction APIs. I can see how this works for rawdevs which expect to have only one PMD that will fulfil the service, however I'd expect multi-fn to have at least 2 driver types, probably more eventually. To be extensible I'd suggest a naming convention for a class of devices. E.g. all devices and drivers that implement multi-fn should create a rawdev named mfn_xxx, e.g. mfn_aesni_mb, mfn_qat. The "mfn_" string should be defined in the mfn hdr. This would allow creation of apis like rte_multi_fn_count() which could find rawdevs which implement mfn_ without hardcoding specific driver names.
    (B)    version control of the multi-function APIs. Putting the multifn API into the drivers/raw/common directory gives a lot of freedom while it's experimental. But can it benefit from API/ABI breakage infrastructure once the experimental tag is removed? Is there any reason not to move the common files to a lib/librte_multi_fn API?
    (C)    xstat name strings should be moved from aesni_mb PMD to common and maybe use same naming convention, so appl can query same stats from any device, e.g. "mfn_successful_enqueues" could be implemented by all PMDs. If PMDs want to add driver-specific stats they can add their own without the mfn_, instead create their own unique stat name.
    (D)    The unit test code is not extensible - again probably as based on previous rawdevs where there's only 1 implementation. For mfn I'd suggest replacing test_rawdev_selftest_aesni_mb() with a test_rawdev_selftest_multi_function(), which finds and/or creates all the raw PMDs implementing the mfn API and runs a test on each. And move the test files from the drivers/raw/aesni_mb dir to app/test and make generic so can run against any device named mfn_xxx
    (E)    the main reason to piggyback onto crypto_perf_tool is to get the benefit of parsing and of all the crypto setup.  However this code has been inflated a lot, in part due to name diffs like rte_cryptodev_enqueue_burst() vs rte_multi_fn_enqueue_burst(). Maybe could be a lot slimmer with macros like ENQUEUE_BURST(dev, qp, void *op, burst_size) ? would mean a compile time decision to do either multifn OR cryptodev API calls, but I think that may work and simplify it.
    (F)    ok, this is a bit pedantic, (sorry David!) but should the aesni_mb rawdev be renamed aesni_mb_mfn throughout (files, fns, dev and driver name). I mean it's implementing the mfn type of rawdev. I'm thinking ahead to QAT - it can implement a sym device, an asym device, a compression device and in future a multi-fn device. I'd propose to name it qat_multifn in case there'll be some other kind of rawdev device it could also implement in future. So the name qat_raw wouldn't be so helpful. (we made that mistake with qat_crypto, which should probably have been qat_sym_crypto - in my opinion more specific names are better)

I have a few minor comment- I'll reply on specific patches.


^ permalink raw reply	[relevance 2%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-04-07 10:25  3%             ` Hemant Agrawal
@ 2020-04-07 12:20  0%               ` Thomas Monjalon
  2020-04-08  7:20  4%               ` Dodji Seketeli
  1 sibling, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-04-07 12:20 UTC (permalink / raw)
  To: Hemant Agrawal (OSS), Hemant Agrawal
  Cc: Dodji Seketeli, David Marchand, dev, Yigit, Ferruh, dev, Neil Horman

07/04/2020 12:25, Hemant Agrawal:
> > In the mean time, the tooling can be tought to ignore changes to these ELF
> > symbols, as you you guys all know already.
> > 
> [Hemant] will you please help me about adding entry to libagigail.abignore 
> I tried doing following, but it is not helping
> 
> --- a/devtools/libabigail.abignore
> +++ b/devtools/libabigail.abignore
> @@ -2,10 +2,15 @@
>          symbol_version = EXPERIMENTAL
>  [suppress_variable]
>          symbol_version = EXPERIMENTAL
> +       name = per_lcore__dpaa2_io
> +       name = dpaa2_io_portal
> 
>  ; Explicit ignore for driver-only ABI
>  [suppress_type]
>          name = rte_cryptodev_ops
> +       name = dpaa2_io_portal_t
> > 
> > > Anyway, all of those symbols in dpaa are part of the driver ABI.
> > > We are still missing a way to mark internal symbols.
> > > Neil had posted a framework for this
> > >
> > https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatchwo
> > rk.dpdk.org%2Fproject%2Fdpdk%2Flist%2F%3Fseries%3D5004&amp;data=02
> > %7C01%7Chemant.agrawal%40nxp.com%7C91a3230cfd334c28bbdb08d7c4d
> > ee590%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6371943339
> > 20186005&amp;sdata=1Is%2BqQwP%2Bn0QVJ2HYK2%2Bx7TJooEvry1sNUUN
> > fWMygkM%3D&amp;reserved=0.
> > >
> > > In order to get this series passing the checks, I recommend NXP
> > > rebasing Neil scripts (I will help reviewing this part), then mark all
> > > those symbols as internal in its drivers.
> > > Other vendor will convert their drivers later, as there is no need at
> > > the moment.
> > >
> [Hemant] I have commented on Neil's series.
> It needs more changes in existing code.
> An approach like __rte_experimental will work better.

I guess you mean __rte_internal?

Please Hemant don't wait for someone else filling the gap.
If __rte_internal is the right approach, please complete and use it.




^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-07 11:33  0%   ` Neil Horman
  2020-04-07 11:40  0%     ` David Marchand
@ 2020-04-07 11:58  5%     ` Thomas Monjalon
  2020-04-07 19:52  3%       ` Neil Horman
  2020-04-08 14:34  0%       ` Ray Kinsella
  1 sibling, 2 replies; 200+ results
From: Thomas Monjalon @ 2020-04-07 11:58 UTC (permalink / raw)
  To: David Marchand, Neil Horman, Kevin Laatz, mdr; +Cc: dev

07/04/2020 13:33, Neil Horman:
> On Tue, Apr 07, 2020 at 09:36:17AM +0200, David Marchand wrote:
> > On Mon, Apr 6, 2020 at 9:34 PM Neil Horman <nhorman@tuxdriver.com> wrote:
> > >
> > > Since we've moved away from our initial abi_versioning.sh script, in
> > 
> > abi_versioning.sh does not exist (idem with the patch title).
> > I suppose you meant validate-abi.sh.
> > 
> Crud, you're right, I was convoluting terms, sorry.  Shall I repost with a
> corrected changelog?

Not only the commit log, look below how you did not care about the basic
usage of the new tool.


> > > favor of check_abi.sh, which uses libabigail, remove the old script from
> > 
> > check-abi.sh
> > 
> > > the tree, and update the docs accordingly
[...]
> > > --- a/doc/guides/contributing/abi_versioning.rst
> > > +++ b/doc/guides/contributing/abi_versioning.rst

The maintainer of doc/guides/contributing/abi_*.rst
is Ray Kinsella so I add him as Cc.

[...]
> > > -The syntax of the ``validate-abi.sh`` utility is::
> > > +The syntax of the ``check-abi.sh`` utility is::
> > >
> > > -   ./devtools/validate-abi.sh <REV1> <REV2>
> > > +   ./devtools/check-abi.sh <REV1> <REV2>
> > 
> > The new script is not a direct replacement.
> > It won't take git revisions, but build directories where versions of
> > dpdk have been compiled.
> > 
> > devtools/test-build.sh and devtools/test-meson-builds.sh illustrate its use.
> > https://git.dpdk.org/dpdk/tree/devtools/test-meson-builds.sh#n127

David, I think Neil did not take time to understand what changed in
ABI tooling.
I really wonder who is the real maintainer of ABI tooling and policy.
Neil, Ray, I was expecting a better involvement in this major
policy enforcement.

This is where we are:
	- Neil asked first for ABI compatibility
	- Neil created validate-abi.sh
	- Ray asked for a strict policy
	- Kevin worked on a new tooling
	- David completed the tooling work
	- David integrated ABI checks in Travis

There are many people partly involved.
I think we need one person truly involved in ABI questions,
someone who feels responsible and will take care of details
like the documentation update requested above.

Please don't rely on David and myself, we are already very busy
with making sure every patches are properly reviewed.
We need good help on the ABI topic in general.



^ permalink raw reply	[relevance 5%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-07 11:33  0%   ` Neil Horman
@ 2020-04-07 11:40  0%     ` David Marchand
  2020-04-07 11:58  5%     ` Thomas Monjalon
  1 sibling, 0 replies; 200+ results
From: David Marchand @ 2020-04-07 11:40 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Thomas Monjalon, Kevin Laatz, Kinsella, Ray

On Tue, Apr 7, 2020 at 1:33 PM Neil Horman <nhorman@tuxdriver.com> wrote:
>
> On Tue, Apr 07, 2020 at 09:36:17AM +0200, David Marchand wrote:
> > On Mon, Apr 6, 2020 at 9:34 PM Neil Horman <nhorman@tuxdriver.com> wrote:
> > >
> > > Since we've moved away from our initial abi_versioning.sh script, in
> >
> > abi_versioning.sh does not exist (idem with the patch title).
> > I suppose you meant validate-abi.sh.
> >
> Crud, you're right, I was convoluting terms, sorry.  Shall I repost with a
> corrected changelog?

Yes, and with the other comment I did earlier, addressed too.


> > > favor of check_abi.sh, which uses libabigail, remove the old script from
> >
> > check-abi.sh
> >
> > > the tree, and update the docs accordingly
> > >
> >
> > [snip]
> >
> > > diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
> > > index a21f4e7a4..1c4a3f927 100644
> > > --- a/doc/guides/contributing/abi_versioning.rst
> > > +++ b/doc/guides/contributing/abi_versioning.rst
> > > @@ -482,9 +482,9 @@ Running the ABI Validator
> > >  -------------------------
> > >
> > >  The ``devtools`` directory in the DPDK source tree contains a utility program,
> > > -``validate-abi.sh``, for validating the DPDK ABI based on the Linux `ABI
> > > -Compliance Checker
> > > -<http://ispras.linuxbase.org/index.php/ABI_compliance_checker>`_.
> > > +``check-abi.sh``, for validating the DPDK ABI based on the libabigail abidiff
> > > +utility:
> > > +https://sourceware.org/libabigail/manual/abidiff.html
> > >
> > >  This has a dependency on the ``abi-compliance-checker`` and ``and abi-dumper``
> > >  utilities which can be installed via a package manager. For example::
> > > @@ -492,9 +492,9 @@ utilities which can be installed via a package manager. For example::
> > >     sudo yum install abi-compliance-checker
> > >     sudo yum install abi-dumper
> > >
> > > -The syntax of the ``validate-abi.sh`` utility is::
> > > +The syntax of the ``check-abi.sh`` utility is::
> > >
> > > -   ./devtools/validate-abi.sh <REV1> <REV2>
> > > +   ./devtools/check-abi.sh <REV1> <REV2>
> >
> > The new script is not a direct replacement.
> > It won't take git revisions, but build directories where versions of
> > dpdk have been compiled.
> >
> > devtools/test-build.sh and devtools/test-meson-builds.sh illustrate its use.
> > https://git.dpdk.org/dpdk/tree/devtools/test-meson-builds.sh#n127
> >

Thanks.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-07  7:36  4% ` David Marchand
@ 2020-04-07 11:33  0%   ` Neil Horman
  2020-04-07 11:40  0%     ` David Marchand
  2020-04-07 11:58  5%     ` Thomas Monjalon
  2020-04-08 14:50  0%   ` Ray Kinsella
  1 sibling, 2 replies; 200+ results
From: Neil Horman @ 2020-04-07 11:33 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, Thomas Monjalon, Kevin Laatz

On Tue, Apr 07, 2020 at 09:36:17AM +0200, David Marchand wrote:
> On Mon, Apr 6, 2020 at 9:34 PM Neil Horman <nhorman@tuxdriver.com> wrote:
> >
> > Since we've moved away from our initial abi_versioning.sh script, in
> 
> abi_versioning.sh does not exist (idem with the patch title).
> I suppose you meant validate-abi.sh.
> 
Crud, you're right, I was convoluting terms, sorry.  Shall I repost with a
corrected changelog?

Neil

> > favor of check_abi.sh, which uses libabigail, remove the old script from
> 
> check-abi.sh
> 
> > the tree, and update the docs accordingly
> >
> 
> [snip]
> 
> > diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
> > index a21f4e7a4..1c4a3f927 100644
> > --- a/doc/guides/contributing/abi_versioning.rst
> > +++ b/doc/guides/contributing/abi_versioning.rst
> > @@ -482,9 +482,9 @@ Running the ABI Validator
> >  -------------------------
> >
> >  The ``devtools`` directory in the DPDK source tree contains a utility program,
> > -``validate-abi.sh``, for validating the DPDK ABI based on the Linux `ABI
> > -Compliance Checker
> > -<http://ispras.linuxbase.org/index.php/ABI_compliance_checker>`_.
> > +``check-abi.sh``, for validating the DPDK ABI based on the libabigail abidiff
> > +utility:
> > +https://sourceware.org/libabigail/manual/abidiff.html
> >
> >  This has a dependency on the ``abi-compliance-checker`` and ``and abi-dumper``
> >  utilities which can be installed via a package manager. For example::
> > @@ -492,9 +492,9 @@ utilities which can be installed via a package manager. For example::
> >     sudo yum install abi-compliance-checker
> >     sudo yum install abi-dumper
> >
> > -The syntax of the ``validate-abi.sh`` utility is::
> > +The syntax of the ``check-abi.sh`` utility is::
> >
> > -   ./devtools/validate-abi.sh <REV1> <REV2>
> > +   ./devtools/check-abi.sh <REV1> <REV2>
> 
> The new script is not a direct replacement.
> It won't take git revisions, but build directories where versions of
> dpdk have been compiled.
> 
> devtools/test-build.sh and devtools/test-meson-builds.sh illustrate its use.
> https://git.dpdk.org/dpdk/tree/devtools/test-meson-builds.sh#n127
> 
> 
> 
> -- 
> David Marchand
> 
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-07  7:32  4%           ` Ray Kinsella
@ 2020-04-07 11:31  4%             ` Neil Horman
  0 siblings, 0 replies; 200+ results
From: Neil Horman @ 2020-04-07 11:31 UTC (permalink / raw)
  To: Ray Kinsella
  Cc: Thomas Monjalon, dev, Ananyev, Konstantin, david.marchand,
	honnappa.nagarahalli, Richardson, Bruce, Yigit, Ferruh,
	kevin.laatz

On Tue, Apr 07, 2020 at 08:32:15AM +0100, Ray Kinsella wrote:
> 
> 
> On 06/04/2020 15:36, Neil Horman wrote:
> > On Mon, Apr 06, 2020 at 04:02:22PM +0200, Thomas Monjalon wrote:
> >> 01/04/2020 14:52, Neil Horman:
> >>> On Tue, Mar 31, 2020 at 09:24:41PM +0200, Thomas Monjalon wrote:
> >>>> 31/03/2020 21:22, Thomas Monjalon:
> >>>>> 31/03/2020 19:05, Ananyev, Konstantin:
> >>>>>> Hi everyone,
> >>>>>>
> >>>>>> Have a question regarding validate-abi.sh.
> >>>>>
> >>>>> devtools/validate-abi.sh should be removed.
> >>>>> Please use the new devtools/check-abi.sh
> >>>>
> >>>> The file doc/guides/contributing/abi_versioning.rst
> >>>> should be updated as well.
> >>>> Neil? Ray?
> >>>>
> >>> Ack, we should remove validate_abi and update the docs
> >>
> >> Neil, are you going to do this update?
> > I can, I had though it was already in progress though.  I'll take care of it
> > this week.
> 
> Thanks Neil - don't know how I missed this thread. 
> 
No sweat, apologies, I just realized I didn't copy you, but its on the list now
Neil

> > 
> > Best
> > Neil
> > 
> >>
> >>
> >>
> >>
> 

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-03-10 10:36  3%           ` Dodji Seketeli
@ 2020-04-07 10:25  3%             ` Hemant Agrawal
  2020-04-07 12:20  0%               ` Thomas Monjalon
  2020-04-08  7:20  4%               ` Dodji Seketeli
  0 siblings, 2 replies; 200+ results
From: Hemant Agrawal @ 2020-04-07 10:25 UTC (permalink / raw)
  To: Dodji Seketeli, David Marchand
  Cc: Hemant Agrawal (OSS), Yigit, Ferruh, dev, Neil Horman, Thomas Monjalon

HI Dodji,
> 
> David Marchand <david.marchand@redhat.com> writes:
> 
> > On Thu, Mar 5, 2020 at 10:19 AM Hemant Agrawal (OSS)
> > <hemant.agrawal@oss.nxp.com> wrote:
> >> > On Thu, Mar 5, 2020 at 10:06 AM Hemant Agrawal (OSS)
> >> > <hemant.agrawal@oss.nxp.com> wrote:
> >> > >
> >> > > Hi David,
> >> > > > On Mon, Mar 2, 2020 at 10:26 AM Hemant Agrawal
> >> > > > <hemant.agrawal@nxp.com> wrote:
> >> > > > >
> >> > > > > This patch series add various patches for enhancing and
> >> > > > > fixing NXP fslmc bus, dpaa bus, and dpaax.
> >> > > > >
> >> > > > > - the main change is support to allow thread migration across
> >> > > > > lcores
> >> > > > > - improving the multi-process support
> >> > > >
> >> > > > This series triggers an ABI warning that must be investigated.
> >> > > >https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%
> >> > > >2Ftravis-
> ci.com%2Fovsrobot%2Fdpdk%2Fjobs%2F292904119%23L2233&amp
> >> > >
> >;data=02%7C01%7Chemant.agrawal%40nxp.com%7C91a3230cfd334c28bbd
> b0
> >> > >
> >8d7c4dee590%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6371
> 943
> >> > >
> >33920176015&amp;sdata=%2BViKwS2sNucwLFD9VtvwxOK1huq0g%2B6TfT6
> Fqp
> >> > > >Nyz5w%3D&amp;reserved=0
> >> > >
> >> > > [Hemant]
> >> > > As per the logs:
> >> > >
> >> > > Variables changes summary: 1 Removed, 2 Changed, 0 Added
> >> > > variables
> >> > > 1 Removed variable:
> >> > >   'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'
> >> > {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
> >> > > 2 Changed variables:
> >> > >   [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at
> >> > dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
> >> > >   [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at
> >> > > dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16
> >> > >
> >> > > Error: ABI issue reported for 'abidiff --suppr
> >> > > devtools/libabigail.abignore --
> >> > no-added-syms --headers-dir1 reference/usr/local/include
> >> > --headers-dir2 install/usr/local/include
> >> > reference/dump/librte_bus_fslmc.dump
> >> > install/dump/librte_bus_fslmc.dump'
> >> > >
> >> > > ---------------
> >> > >
> >> > > These changes are w.r.t modifications in internal structures and
> variables.
> >> > They may be ignored.
> >> >
> >> > The ABI check considers symbol exposed in headers available to final
> users.
> >> > If those are internal, why are the headers public?
> >> >
> >>
> >> [Hemant] These symbols are not part of any public header files, but
> >> they are part of *.map files to share them between different driver
> >> libs i.e bus_fslmc and net_dpaa2
> >
> > I would expect libabigail to skip those symbols, so there is something
> > I have missed in how --headers-dirX work.
> 
> In libabigail speak, we make a difference between *ELF symbols* and types.
> 
> --header-dirX is about telling the tool what the public *types* are.  As you
> rightfully implied, types that are defined in files that are not found in the
> directories specified by --header-dirX are considered to be private types and
> are thus not shown in the ABI change report.
> 
> ELF symbols however are a different matter.  Header files don't usually define
> ELF symbols, be they variable of function symbols.  Header files can at most
> declare variables or functions that would be actually defined elsewhere in
> source code, leading to the definition of ELF variable or function symbols in the
> final binary.  At this point, we aren't talking about types anymore, as the ELF
> format doesn't know what types (in C or any other language) are.  So --header-
> dirX don't deal with ELF symbols.
> 
> And from what I understand from the message quoted above, the changes we
> are talking about have to do with EFL variable symbols which size have
> changed.  So in practise, these are global arrays (exposed by at the binary level
> as an ELF variable symbol of a given size) with public visibility which size have
> changed.
> 
> So my guess would be that if you guys don't want these arrays to be part the
> binary interface of this library, they should probably be declared static at the C
> level and accessed through some accessor function or something like that.  At
> least, that's my humble uninformed opinion.

[Hemant] Actually some of these are in datapath, there is a performance impact of accessing them via function calls. 

> 
> In the mean time, the tooling can be tought to ignore changes to these ELF
> symbols, as you you guys all know already.
> 
[Hemant] will you please help me about adding entry to libagigail.abignore 
I tried doing following, but it is not helping
--- a/devtools/libabigail.abignore
+++ b/devtools/libabigail.abignore
@@ -2,10 +2,15 @@
         symbol_version = EXPERIMENTAL
 [suppress_variable]
         symbol_version = EXPERIMENTAL
+       name = per_lcore__dpaa2_io
+       name = dpaa2_io_portal

 ; Explicit ignore for driver-only ABI
 [suppress_type]
         name = rte_cryptodev_ops
+       name = dpaa2_io_portal_t
> 
> > Anyway, all of those symbols in dpaa are part of the driver ABI.
> > We are still missing a way to mark internal symbols.
> > Neil had posted a framework for this
> >
> https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatchwo
> rk.dpdk.org%2Fproject%2Fdpdk%2Flist%2F%3Fseries%3D5004&amp;data=02
> %7C01%7Chemant.agrawal%40nxp.com%7C91a3230cfd334c28bbdb08d7c4d
> ee590%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6371943339
> 20186005&amp;sdata=1Is%2BqQwP%2Bn0QVJ2HYK2%2Bx7TJooEvry1sNUUN
> fWMygkM%3D&amp;reserved=0.
> >
> > In order to get this series passing the checks, I recommend NXP
> > rebasing Neil scripts (I will help reviewing this part), then mark all
> > those symbols as internal in its drivers.
> > Other vendor will convert their drivers later, as there is no need at
> > the moment.
> >
[Hemant] I have commented on Neil's series.  It needs more changes in existing code. An approach like __rte_experimental will work better.

> > Thanks.
> 

Regards,
Hemant

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
  2020-04-06 19:34 38% [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree Neil Horman
@ 2020-04-07  7:36  4% ` David Marchand
  2020-04-07 11:33  0%   ` Neil Horman
  2020-04-08 14:50  0%   ` Ray Kinsella
  2020-04-08 14:49  0% ` Ray Kinsella
  1 sibling, 2 replies; 200+ results
From: David Marchand @ 2020-04-07  7:36 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Thomas Monjalon, Kevin Laatz

On Mon, Apr 6, 2020 at 9:34 PM Neil Horman <nhorman@tuxdriver.com> wrote:
>
> Since we've moved away from our initial abi_versioning.sh script, in

abi_versioning.sh does not exist (idem with the patch title).
I suppose you meant validate-abi.sh.

> favor of check_abi.sh, which uses libabigail, remove the old script from

check-abi.sh

> the tree, and update the docs accordingly
>

[snip]

> diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
> index a21f4e7a4..1c4a3f927 100644
> --- a/doc/guides/contributing/abi_versioning.rst
> +++ b/doc/guides/contributing/abi_versioning.rst
> @@ -482,9 +482,9 @@ Running the ABI Validator
>  -------------------------
>
>  The ``devtools`` directory in the DPDK source tree contains a utility program,
> -``validate-abi.sh``, for validating the DPDK ABI based on the Linux `ABI
> -Compliance Checker
> -<http://ispras.linuxbase.org/index.php/ABI_compliance_checker>`_.
> +``check-abi.sh``, for validating the DPDK ABI based on the libabigail abidiff
> +utility:
> +https://sourceware.org/libabigail/manual/abidiff.html
>
>  This has a dependency on the ``abi-compliance-checker`` and ``and abi-dumper``
>  utilities which can be installed via a package manager. For example::
> @@ -492,9 +492,9 @@ utilities which can be installed via a package manager. For example::
>     sudo yum install abi-compliance-checker
>     sudo yum install abi-dumper
>
> -The syntax of the ``validate-abi.sh`` utility is::
> +The syntax of the ``check-abi.sh`` utility is::
>
> -   ./devtools/validate-abi.sh <REV1> <REV2>
> +   ./devtools/check-abi.sh <REV1> <REV2>

The new script is not a direct replacement.
It won't take git revisions, but build directories where versions of
dpdk have been compiled.

devtools/test-build.sh and devtools/test-meson-builds.sh illustrate its use.
https://git.dpdk.org/dpdk/tree/devtools/test-meson-builds.sh#n127



-- 
David Marchand


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-06 14:36  4%         ` Neil Horman
@ 2020-04-07  7:32  4%           ` Ray Kinsella
  2020-04-07 11:31  4%             ` Neil Horman
  0 siblings, 1 reply; 200+ results
From: Ray Kinsella @ 2020-04-07  7:32 UTC (permalink / raw)
  To: Neil Horman, Thomas Monjalon
  Cc: dev, Ananyev, Konstantin, david.marchand, honnappa.nagarahalli,
	Richardson, Bruce, Yigit, Ferruh, kevin.laatz



On 06/04/2020 15:36, Neil Horman wrote:
> On Mon, Apr 06, 2020 at 04:02:22PM +0200, Thomas Monjalon wrote:
>> 01/04/2020 14:52, Neil Horman:
>>> On Tue, Mar 31, 2020 at 09:24:41PM +0200, Thomas Monjalon wrote:
>>>> 31/03/2020 21:22, Thomas Monjalon:
>>>>> 31/03/2020 19:05, Ananyev, Konstantin:
>>>>>> Hi everyone,
>>>>>>
>>>>>> Have a question regarding validate-abi.sh.
>>>>>
>>>>> devtools/validate-abi.sh should be removed.
>>>>> Please use the new devtools/check-abi.sh
>>>>
>>>> The file doc/guides/contributing/abi_versioning.rst
>>>> should be updated as well.
>>>> Neil? Ray?
>>>>
>>> Ack, we should remove validate_abi and update the docs
>>
>> Neil, are you going to do this update?
> I can, I had though it was already in progress though.  I'll take care of it
> this week.

Thanks Neil - don't know how I missed this thread. 

> 
> Best
> Neil
> 
>>
>>
>>
>>

^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree
@ 2020-04-06 19:34 38% Neil Horman
  2020-04-07  7:36  4% ` David Marchand
  2020-04-08 14:49  0% ` Ray Kinsella
  0 siblings, 2 replies; 200+ results
From: Neil Horman @ 2020-04-06 19:34 UTC (permalink / raw)
  To: dev

Since we've moved away from our initial abi_versioning.sh script, in
favor of check_abi.sh, which uses libabigail, remove the old script from
the tree, and update the docs accordingly

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: thomas@monjalon.net
---
 MAINTAINERS                                |   1 -
 devtools/validate-abi.sh                   | 251 ---------------------
 doc/guides/contributing/abi_versioning.rst |  18 +-
 3 files changed, 9 insertions(+), 261 deletions(-)
 delete mode 100755 devtools/validate-abi.sh

diff --git a/MAINTAINERS b/MAINTAINERS
index 4800f6884..84b633431 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -152,7 +152,6 @@ F: devtools/gen-abi.sh
 F: devtools/libabigail.abignore
 F: devtools/update-abi.sh
 F: devtools/update_version_map_abi.py
-F: devtools/validate-abi.sh
 F: buildtools/check-experimental-syms.sh
 F: buildtools/map-list-symbol.sh
 
diff --git a/devtools/validate-abi.sh b/devtools/validate-abi.sh
deleted file mode 100755
index f64e19d38..000000000
--- a/devtools/validate-abi.sh
+++ /dev/null
@@ -1,251 +0,0 @@
-#!/usr/bin/env bash
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2015 Neil Horman. All rights reserved.
-# Copyright(c) 2017 6WIND S.A.
-# All rights reserved
-
-set -e
-
-abicheck=abi-compliance-checker
-abidump=abi-dumper
-default_dst=abi-check
-default_target=x86_64-native-linuxapp-gcc
-
-# trap on error
-err_report() {
-    echo "$0: error at line $1"
-}
-trap 'err_report $LINENO' ERR
-
-print_usage () {
-	cat <<- END_OF_HELP
-	$(basename $0) [options] <rev1> <rev2>
-
-	This script compares the ABI of 2 git revisions of the current
-	workspace. The output is a html report and a compilation log.
-
-	The objective is to make sure that applications built against
-	DSOs from the first revision can still run when executed using
-	the DSOs built from the second revision.
-
-	<rev1> and <rev2> are git commit id or tags.
-
-	Options:
-	  -h		show this help
-	  -j <num>	enable parallel compilation with <num> threads
-	  -v		show compilation logs on the console
-	  -d <dir>	change working directory (default is ${default_dst})
-	  -t <target>	the dpdk target to use (default is ${default_target})
-	  -f		overwrite existing files in destination directory
-
-	The script returns 0 on success, or the value of last failing
-	call of ${abicheck} (incompatible abi or the tool has run with errors).
-	The errors returned by ${abidump} are ignored.
-
-	END_OF_HELP
-}
-
-# log in the file, and on stdout if verbose
-# $1: level string
-# $2: string to be logged
-log() {
-	echo "$1: $2"
-	if [ "${verbose}" != "true" ]; then
-		echo "$1: $2" >&3
-	fi
-}
-
-# launch a command and log it, taking care of surrounding spaces with quotes
-cmd() {
-	local i s whitespace ret
-	s=""
-	whitespace="[[:space:]]"
-	for i in "$@"; do
-		if [[ $i =~ $whitespace ]]; then
-			i=\"$i\"
-		fi
-		if [ -z "$s" ]; then
-			s="$i"
-		else
-			s="$s $i"
-		fi
-	done
-
-	ret=0
-	log "CMD" "$s"
-	"$@" || ret=$?
-	if [ "$ret" != "0" ]; then
-		log "CMD" "previous command returned $ret"
-	fi
-
-	return $ret
-}
-
-# redirect or copy stderr/stdout to a file
-# the syntax is unfamiliar, but it makes the rest of the
-# code easier to read, avoiding the use of pipes
-set_log_file() {
-	# save original stdout and stderr in fd 3 and 4
-	exec 3>&1
-	exec 4>&2
-	# create a new fd 5 that send to a file
-	exec 5> >(cat > $1)
-	# send stdout and stderr to fd 5
-	if [ "${verbose}" = "true" ]; then
-		exec 1> >(tee /dev/fd/5 >&3)
-		exec 2> >(tee /dev/fd/5 >&4)
-	else
-		exec 1>&5
-		exec 2>&5
-	fi
-}
-
-# Make sure we configure SHARED libraries
-# Also turn off IGB and KNI as those require kernel headers to build
-fixup_config() {
-	local conf=config/defconfig_$target
-	cmd sed -i -e"$ a\CONFIG_RTE_BUILD_SHARED_LIB=y" $conf
-	cmd sed -i -e"$ a\CONFIG_RTE_NEXT_ABI=n" $conf
-	cmd sed -i -e"$ a\CONFIG_RTE_EAL_IGB_UIO=n" $conf
-	cmd sed -i -e"$ a\CONFIG_RTE_LIBRTE_KNI=n" $conf
-	cmd sed -i -e"$ a\CONFIG_RTE_KNI_KMOD=n" $conf
-}
-
-# build dpdk for the given tag and dump abi
-# $1: hash of the revision
-gen_abi() {
-	local i
-
-	cmd git clone ${dpdkroot} ${dst}/${1}
-	cmd cd ${dst}/${1}
-
-	log "INFO" "Checking out version ${1} of the dpdk"
-	# Move to the old version of the tree
-	cmd git checkout ${1}
-
-	fixup_config
-
-	# Now configure the build
-	log "INFO" "Configuring DPDK ${1}"
-	cmd make config T=$target O=$target
-
-	# Checking abi compliance relies on using the dwarf information in
-	# the shared objects. Build with -g to include them.
-	log "INFO" "Building DPDK ${1}. This might take a moment"
-	cmd make -j$parallel O=$target V=1 EXTRA_CFLAGS="-g -Og -Wno-error" \
-	    EXTRA_LDFLAGS="-g" || log "INFO" "The build failed"
-
-	# Move to the lib directory
-	cmd cd ${PWD}/$target/lib
-	log "INFO" "Collecting ABI information for ${1}"
-	for i in *.so; do
-		[ -e "$i" ] || break
-		cmd $abidump ${i} -o $dst/${1}/${i}.dump -lver ${1} || true
-		# hack to ignore empty SymbolsInfo section (no public ABI)
-		if grep -q "'SymbolInfo' => {}," $dst/${1}/${i}.dump \
-				2> /dev/null; then
-			log "INFO" "${i} has no public ABI, remove dump file"
-			cmd rm -f $dst/${1}/${i}.dump
-		fi
-	done
-}
-
-verbose=false
-parallel=1
-dst=${default_dst}
-target=${default_target}
-force=0
-while getopts j:vd:t:fh ARG ; do
-	case $ARG in
-		j ) parallel=$OPTARG ;;
-		v ) verbose=true ;;
-		d ) dst=$OPTARG ;;
-		t ) target=$OPTARG ;;
-		f ) force=1 ;;
-		h ) print_usage ; exit 0 ;;
-		? ) print_usage ; exit 1 ;;
-	esac
-done
-shift $(($OPTIND - 1))
-
-if [ $# != 2 ]; then
-	print_usage
-	exit 1
-fi
-
-tag1=$1
-tag2=$2
-
-# convert path to absolute
-case "${dst}" in
-	/*) ;;
-	*) dst=${PWD}/${dst} ;;
-esac
-dpdkroot=$(readlink -f $(dirname $0)/..)
-
-if [ -e "${dst}" -a "$force" = 0 ]; then
-	echo "The ${dst} directory is not empty. Remove it, use another"
-	echo "one (-d <dir>), or force overriding (-f)"
-	exit 1
-fi
-
-rm -rf ${dst}
-mkdir -p ${dst}
-set_log_file ${dst}/abi-check.log
-log "INFO" "Logs available in ${dst}/abi-check.log"
-
-command -v ${abicheck} || log "INFO" "Can't find ${abicheck} utility"
-command -v ${abidump} || log "INFO" "Can't find ${abidump} utility"
-
-hash1=$(git show -s --format=%h "$tag1" -- 2> /dev/null | tail -1)
-hash2=$(git show -s --format=%h "$tag2" -- 2> /dev/null | tail -1)
-
-# Make hashes available in output for non-local reference
-tag1="$tag1 ($hash1)"
-tag2="$tag2 ($hash2)"
-
-if [ "$hash1" = "$hash2" ]; then
-	log "ERROR" "$tag1 and $tag2 are the same revisions"
-	exit 1
-fi
-
-cmd mkdir -p ${dst}
-
-# dump abi for each revision
-gen_abi ${hash1}
-gen_abi ${hash2}
-
-# compare the abi dumps
-cmd cd ${dst}
-ret=0
-list=""
-for i in ${hash2}/*.dump; do
-	name=`basename $i`
-	libname=${name%.dump}
-
-	if [ ! -f ${hash1}/$name ]; then
-		log "INFO" "$NAME does not exist in $tag1. skipping..."
-		continue
-	fi
-
-	local_ret=0
-	cmd $abicheck -l $libname \
-	    -old ${hash1}/$name -new ${hash2}/$name || local_ret=$?
-	if [ $local_ret != 0 ]; then
-		log "NOTICE" "$abicheck returned $local_ret"
-		ret=$local_ret
-		list="$list $libname"
-	fi
-done
-
-if [ $ret != 0 ]; then
-	log "NOTICE" "ABI may be incompatible, check reports/logs for details."
-	log "NOTICE" "Incompatible list: $list"
-else
-	log "NOTICE" "No error detected, ABI is compatible."
-fi
-
-log "INFO" "Logs are in ${dst}/abi-check.log"
-log "INFO" "HTML reports are in ${dst}/compat_reports directory"
-
-exit $ret
diff --git a/doc/guides/contributing/abi_versioning.rst b/doc/guides/contributing/abi_versioning.rst
index a21f4e7a4..1c4a3f927 100644
--- a/doc/guides/contributing/abi_versioning.rst
+++ b/doc/guides/contributing/abi_versioning.rst
@@ -482,9 +482,9 @@ Running the ABI Validator
 -------------------------
 
 The ``devtools`` directory in the DPDK source tree contains a utility program,
-``validate-abi.sh``, for validating the DPDK ABI based on the Linux `ABI
-Compliance Checker
-<http://ispras.linuxbase.org/index.php/ABI_compliance_checker>`_.
+``check-abi.sh``, for validating the DPDK ABI based on the libabigail abidiff
+utility:
+https://sourceware.org/libabigail/manual/abidiff.html 
 
 This has a dependency on the ``abi-compliance-checker`` and ``and abi-dumper``
 utilities which can be installed via a package manager. For example::
@@ -492,9 +492,9 @@ utilities which can be installed via a package manager. For example::
    sudo yum install abi-compliance-checker
    sudo yum install abi-dumper
 
-The syntax of the ``validate-abi.sh`` utility is::
+The syntax of the ``check-abi.sh`` utility is::
 
-   ./devtools/validate-abi.sh <REV1> <REV2>
+   ./devtools/check-abi.sh <REV1> <REV2>
 
 Where ``REV1`` and ``REV2`` are valid gitrevisions(7)
 https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html
@@ -503,16 +503,16 @@ on the local repo.
 For example::
 
    # Check between the previous and latest commit:
-   ./devtools/validate-abi.sh HEAD~1 HEAD
+   ./devtools/check-abi.sh HEAD~1 HEAD
 
    # Check on a specific compilation target:
-   ./devtools/validate-abi.sh -t x86_64-native-linux-gcc HEAD~1 HEAD
+   ./devtools/check-abi.sh -t x86_64-native-linux-gcc HEAD~1 HEAD
 
    # Check between two tags:
-   ./devtools/validate-abi.sh v2.0.0 v2.1.0
+   ./devtools/check-abi.sh v2.0.0 v2.1.0
 
    # Check between git master and local topic-branch "vhost-hacking":
-   ./devtools/validate-abi.sh master vhost-hacking
+   ./devtools/check-abi.sh master vhost-hacking
 
 After the validation script completes (it can take a while since it need to
 compile both tags) it will create compatibility reports in the
-- 
2.25.1


^ permalink raw reply	[relevance 38%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 14:00  0%                 ` Thomas Monjalon
@ 2020-04-06 18:53  0%                   ` Ori Kam
  0 siblings, 0 replies; 200+ results
From: Ori Kam @ 2020-04-06 18:53 UTC (permalink / raw)
  To: Thomas Monjalon, Pavan Nikhilesh Bhagavatula
  Cc: Jerin Jacob Kollanukkaran, xiang.w.wang, dev, Shahaf Shuler,
	hemant.agrawal, Opher Reviv, Alex Rosenbaum, Dovrat Zifroni,
	Prasun Kapoor, nipun.gupta, bruce.richardson, yang.a.hong,
	harry.chang, gu.jian1, shanjiangh, zhangy.yun, lixingfu, wushuai,
	yuyingxia, fanchenggang, davidfgao, liuzhong1, zhaoyong11, oc,
	jim, hongjun.ni, j.bromhead, deri, fc, arthur.su, david.marchand



> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Thomas Monjalon
> Sent: Monday, April 6, 2020 5:00 PM
> To: Pavan Nikhilesh Bhagavatula <pbhagavatula@marvell.com>; Ori Kam
> <orika@mellanox.com>
> Cc: Jerin Jacob Kollanukkaran <jerinj@marvell.com>; xiang.w.wang@intel.com;
> dev@dpdk.org; Shahaf Shuler <shahafs@mellanox.com>;
> hemant.agrawal@nxp.com; Opher Reviv <opher@mellanox.com>; Alex
> Rosenbaum <alexr@mellanox.com>; Dovrat Zifroni <dovrat@marvell.com>;
> Prasun Kapoor <pkapoor@marvell.com>; nipun.gupta@nxp.com;
> bruce.richardson@intel.com; yang.a.hong@intel.com; harry.chang@intel.com;
> gu.jian1@zte.com.cn; shanjiangh@chinatelecom.cn;
> zhangy.yun@chinatelecom.cn; lixingfu@huachentel.com; wushuai@inspur.com;
> yuyingxia@yxlink.com; fanchenggang@sunyainfo.com;
> davidfgao@tencent.com; liuzhong1@chinaunicom.cn;
> zhaoyong11@huawei.com; oc@yunify.com; jim@netgate.com;
> hongjun.ni@intel.com; j.bromhead@titan-ic.com; deri@ntop.org;
> fc@napatech.com; arthur.su@lionic.com; david.marchand@redhat.com
> Subject: Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte
> level functions
> 
> 06/04/2020 15:50, Pavan Nikhilesh Bhagavatula:
> > From: Thomas Monjalon <thomas@monjalon.net>
> > >> >06/04/2020 14:33, Pavan Nikhilesh Bhagavatula:
> > >> >> >> From: Pavan Nikhilesh Bhagavatula
> > >> >> >> > >+uint16_t
> > >> >> >> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t
> > >> >qp_id,
> > >> >> >> > >+			   struct rte_regex_ops **ops, uint16_t
> > >> >nb_ops)
> > >> >> >> > >+{
> > >> >> >> > >+	return regex_devices[dev_id]-
> > >> >> >> > >>enqueue(regex_devices[dev_id], qp_id,
> > >> >> >> > >+					      ops, nb_ops);
> > >> >> >> > >+}
> > >> >> >> >
> > >> >> >> > Move these functions to .h in-lining them.
> > >> >> >> > Also, please add debug checks @see
> > >> >> >rte_eth_rx_burst/rte_eth_tx_burst.
> > >> >> >>
> > >> >> >> O.K will update.
> > >> >> >
> > >> >> >In general, inlining is a pain for ABI compatibility.
> > >> >> >Please inline only if the gain is very significant.
> > >> >> >
> > >> >>
> > >> >> The performance gain mostly comes from hoisting
> > >> >`regex_devices[dev_id]` load above the
> > >> >> poll loop.
> > >> >> Since, the performance measurement application is still in pipeline
> > >> >and regexdev would be
> > >> >> experimental for next couple of releases I suggest inlining it now
> > >and
> > >> >worrying about ABI when
> > >> >> experimental tag needs to be removed.
> > >> >
> > >> >No, we must worry about ABI from the beginning.
> > >>
> > >> I though performance was the primary objective :-).
> > >
> > >It is.
> > >
> > >> >> We can follow the same path as done by ethdev
> > >>
> >[https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefe
> nse.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttps-
> &amp;data=02%7C01%7Corika%40mellanox.com%7Cc3e07910f52846f64b5008
> d7da32d82e%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C6372177
> 84252928490&amp;sdata=8Pxq8ciUVW7bMiB1XmQBNm%2Fsmy8m1Wa7yKXK
> JRL4d%2B4%3D&amp;reserved=0
> >
> >3A__https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fww
> w.mail-
> %2F&amp;data=02%7C01%7Corika%40mellanox.com%7Cc3e07910f52846f64b
> 5008d7da32d82e%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C637
> 217784252928490&amp;sdata=sTDsN85xShTU7WOLQQ2iF8eh%2FyoVHYwDq%
> 2FTdgdHdlbM%3D&amp;reserved=0
> > >> >2Darchive.com_dev-
> > >>
> > >>40dpdk.org_msg142392.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xt
> > >f
> > >> >Q&r=E3SgYMjtKCMVsB-fmvgGV3o-
> > >> >g_fjLhk5Pupi9ijohpc&m=7Gqb6WKmZV5uY3xa7FRVrRVDz8Usrsd-
> > >>
> > >>rDjIKr6CUQQ&s=sQo2Kx9fzTNXwiQ2Fzki3s5GSuiiAEzz2VtN68_KKXo&e
> > >=
> > >> >]
> > >> >
> > >> >ethdev is not an argument.
> > >>
> > >> What about ring?
> [https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Furldefens
> e.proofpoint.com%2Fv2%2Furl%3Fu%3Dhttp-
> &amp;data=02%7C01%7Corika%40mellanox.com%7Cc3e07910f52846f64b5008
> d7da32d82e%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C6372177
> 84252928490&amp;sdata=t2qUIj51WPzqQhJngheYh1s7DWzOxd%2FcAyAQK39C
> HgQ%3D&amp;reserved=0
> > >3A__mails.dpdk.org_archives_dev_2020-
> > >2DApril_161506.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=E3S
> > >gYMjtKCMVsB-fmvgGV3o-
> > >g_fjLhk5Pupi9ijohpc&m=u9gnM_YrOJDusN4yR8YUcUuUkri4tOjnHrQ0A
> > >Qd5zTw&s=uv6AQA-
> > >Zu7o6ugyhpGHLxFOk4SfEdkHfFGDmhzANRME&e= ]
> > >>
> > >> Why do we need to prove the same performance advantage using in-
> > >lining for datapath
> > >> critical functions again and again?
> > >
> > >Because every libraries have not the same usage and load.
> > >We should compare how much cycle is saved with inline vs
> > >how much cycles is, "in average", a regex burst?
> > >
> > >If you tell me regex processing is fast, OK, let's inline.
> > >
> >
> > Regex processing speed would still be dependent on underlying device
> capabilities.
> >
> > All we are trying to do is reduce the enqueue/dequeue completion time
> which would
> > bring down the overall latency.
> 
> Take your regex HW and do a simple regex processing burst.
> How many cycles it takes to complete?
> How many cycles you lose if not inline?
> If the ratio is lower than 1/200, I think inline is not a must.
> 
> Ori, please consider the same measure for your HW.
> 
I think that the default for data path should be inline.
In this specific case maybe the benefit is small.
I guess that by definition the RegEx is slower than the net device.
It is much harder to check the performance of RegEx device due to the 
fact that it depends on the data itself and on the rules.

I don't have HW to check the numbers right now. Even if I have them
this is for Mellanox implementation other PMD may have different values.
I suggest that we change to inline, and after getting the HW we will run some tests
and based on them we can decide if the API should be changed.
Please note that the API change will be before the first integration of this patch
so it is not real API change.

 


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-06 14:02  4%       ` Thomas Monjalon
@ 2020-04-06 14:36  4%         ` Neil Horman
  2020-04-07  7:32  4%           ` Ray Kinsella
  0 siblings, 1 reply; 200+ results
From: Neil Horman @ 2020-04-06 14:36 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: dev, mdr, Ananyev, Konstantin, david.marchand,
	honnappa.nagarahalli, Richardson, Bruce, Yigit, Ferruh,
	kevin.laatz

On Mon, Apr 06, 2020 at 04:02:22PM +0200, Thomas Monjalon wrote:
> 01/04/2020 14:52, Neil Horman:
> > On Tue, Mar 31, 2020 at 09:24:41PM +0200, Thomas Monjalon wrote:
> > > 31/03/2020 21:22, Thomas Monjalon:
> > > > 31/03/2020 19:05, Ananyev, Konstantin:
> > > > > Hi everyone,
> > > > > 
> > > > > Have a question regarding validate-abi.sh.
> > > > 
> > > > devtools/validate-abi.sh should be removed.
> > > > Please use the new devtools/check-abi.sh
> > > 
> > > The file doc/guides/contributing/abi_versioning.rst
> > > should be updated as well.
> > > Neil? Ray?
> > > 
> > Ack, we should remove validate_abi and update the docs
> 
> Neil, are you going to do this update?
I can, I had though it was already in progress though.  I'll take care of it
this week.

Best
Neil

> 
> 
> 
> 

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-01 12:52  4%     ` Neil Horman
@ 2020-04-06 14:02  4%       ` Thomas Monjalon
  2020-04-06 14:36  4%         ` Neil Horman
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-04-06 14:02 UTC (permalink / raw)
  To: Neil Horman
  Cc: dev, mdr, Ananyev, Konstantin, david.marchand,
	honnappa.nagarahalli, dev, Richardson, Bruce, Yigit, Ferruh,
	kevin.laatz

01/04/2020 14:52, Neil Horman:
> On Tue, Mar 31, 2020 at 09:24:41PM +0200, Thomas Monjalon wrote:
> > 31/03/2020 21:22, Thomas Monjalon:
> > > 31/03/2020 19:05, Ananyev, Konstantin:
> > > > Hi everyone,
> > > > 
> > > > Have a question regarding validate-abi.sh.
> > > 
> > > devtools/validate-abi.sh should be removed.
> > > Please use the new devtools/check-abi.sh
> > 
> > The file doc/guides/contributing/abi_versioning.rst
> > should be updated as well.
> > Neil? Ray?
> > 
> Ack, we should remove validate_abi and update the docs

Neil, are you going to do this update?




^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 13:50  0%               ` Pavan Nikhilesh Bhagavatula
@ 2020-04-06 14:00  0%                 ` Thomas Monjalon
  2020-04-06 18:53  0%                   ` Ori Kam
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-04-06 14:00 UTC (permalink / raw)
  To: Pavan Nikhilesh Bhagavatula, Ori Kam
  Cc: Jerin Jacob Kollanukkaran, xiang.w.wang, dev, Shahaf Shuler,
	hemant.agrawal, Opher Reviv, Alex Rosenbaum, Dovrat Zifroni,
	Prasun Kapoor, nipun.gupta, bruce.richardson, yang.a.hong,
	harry.chang, gu.jian1, shanjiangh, zhangy.yun, lixingfu, wushuai,
	yuyingxia, fanchenggang, davidfgao, liuzhong1, zhaoyong11, oc,
	jim, hongjun.ni, j.bromhead, deri, fc, arthur.su, david.marchand

06/04/2020 15:50, Pavan Nikhilesh Bhagavatula:
> From: Thomas Monjalon <thomas@monjalon.net>
> >> >06/04/2020 14:33, Pavan Nikhilesh Bhagavatula:
> >> >> >> From: Pavan Nikhilesh Bhagavatula
> >> >> >> > >+uint16_t
> >> >> >> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t
> >> >qp_id,
> >> >> >> > >+			   struct rte_regex_ops **ops, uint16_t
> >> >nb_ops)
> >> >> >> > >+{
> >> >> >> > >+	return regex_devices[dev_id]-
> >> >> >> > >>enqueue(regex_devices[dev_id], qp_id,
> >> >> >> > >+					      ops, nb_ops);
> >> >> >> > >+}
> >> >> >> >
> >> >> >> > Move these functions to .h in-lining them.
> >> >> >> > Also, please add debug checks @see
> >> >> >rte_eth_rx_burst/rte_eth_tx_burst.
> >> >> >>
> >> >> >> O.K will update.
> >> >> >
> >> >> >In general, inlining is a pain for ABI compatibility.
> >> >> >Please inline only if the gain is very significant.
> >> >> >
> >> >>
> >> >> The performance gain mostly comes from hoisting
> >> >`regex_devices[dev_id]` load above the
> >> >> poll loop.
> >> >> Since, the performance measurement application is still in pipeline
> >> >and regexdev would be
> >> >> experimental for next couple of releases I suggest inlining it now
> >and
> >> >worrying about ABI when
> >> >> experimental tag needs to be removed.
> >> >
> >> >No, we must worry about ABI from the beginning.
> >>
> >> I though performance was the primary objective :-).
> >
> >It is.
> >
> >> >> We can follow the same path as done by ethdev
> >> >[https://urldefense.proofpoint.com/v2/url?u=https-
> >3A__www.mail-
> >> >2Darchive.com_dev-
> >>
> >>40dpdk.org_msg142392.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xt
> >f
> >> >Q&r=E3SgYMjtKCMVsB-fmvgGV3o-
> >> >g_fjLhk5Pupi9ijohpc&m=7Gqb6WKmZV5uY3xa7FRVrRVDz8Usrsd-
> >>
> >>rDjIKr6CUQQ&s=sQo2Kx9fzTNXwiQ2Fzki3s5GSuiiAEzz2VtN68_KKXo&e
> >=
> >> >]
> >> >
> >> >ethdev is not an argument.
> >>
> >> What about ring? [https://urldefense.proofpoint.com/v2/url?u=http-
> >3A__mails.dpdk.org_archives_dev_2020-
> >2DApril_161506.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=E3S
> >gYMjtKCMVsB-fmvgGV3o-
> >g_fjLhk5Pupi9ijohpc&m=u9gnM_YrOJDusN4yR8YUcUuUkri4tOjnHrQ0A
> >Qd5zTw&s=uv6AQA-
> >Zu7o6ugyhpGHLxFOk4SfEdkHfFGDmhzANRME&e= ]
> >>
> >> Why do we need to prove the same performance advantage using in-
> >lining for datapath
> >> critical functions again and again?
> >
> >Because every libraries have not the same usage and load.
> >We should compare how much cycle is saved with inline vs
> >how much cycles is, "in average", a regex burst?
> >
> >If you tell me regex processing is fast, OK, let's inline.
> >
> 
> Regex processing speed would still be dependent on underlying device capabilities.
> 
> All we are trying to do is reduce the enqueue/dequeue completion time which would 
> bring down the overall latency.

Take your regex HW and do a simple regex processing burst.
How many cycles it takes to complete?
How many cycles you lose if not inline?
If the ratio is lower than 1/200, I think inline is not a must.

Ori, please consider the same measure for your HW.



^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 13:36  0%             ` Thomas Monjalon
@ 2020-04-06 13:50  0%               ` Pavan Nikhilesh Bhagavatula
  2020-04-06 14:00  0%                 ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Pavan Nikhilesh Bhagavatula @ 2020-04-06 13:50 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: Ori Kam, Jerin Jacob Kollanukkaran, xiang.w.wang, dev,
	Shahaf Shuler, hemant.agrawal, Opher Reviv, Alex Rosenbaum,
	Dovrat Zifroni, Prasun Kapoor, nipun.gupta, bruce.richardson,
	yang.a.hong, harry.chang, gu.jian1, shanjiangh, zhangy.yun,
	lixingfu, wushuai, yuyingxia, fanchenggang, davidfgao, liuzhong1,
	zhaoyong11, oc, jim, hongjun.ni, j.bromhead, deri, fc, arthur.su,
	david.marchand



>-----Original Message-----
>From: Thomas Monjalon <thomas@monjalon.net>
>Sent: Monday, April 6, 2020 7:07 PM
>To: Pavan Nikhilesh Bhagavatula <pbhagavatula@marvell.com>
>Cc: Ori Kam <orika@mellanox.com>; Jerin Jacob Kollanukkaran
><jerinj@marvell.com>; xiang.w.wang@intel.com; dev@dpdk.org;
>Shahaf Shuler <shahafs@mellanox.com>; hemant.agrawal@nxp.com;
>Opher Reviv <opher@mellanox.com>; Alex Rosenbaum
><alexr@mellanox.com>; Dovrat Zifroni <dovrat@marvell.com>; Prasun
>Kapoor <pkapoor@marvell.com>; nipun.gupta@nxp.com;
>bruce.richardson@intel.com; yang.a.hong@intel.com;
>harry.chang@intel.com; gu.jian1@zte.com.cn;
>shanjiangh@chinatelecom.cn; zhangy.yun@chinatelecom.cn;
>lixingfu@huachentel.com; wushuai@inspur.com;
>yuyingxia@yxlink.com; fanchenggang@sunyainfo.com;
>davidfgao@tencent.com; liuzhong1@chinaunicom.cn;
>zhaoyong11@huawei.com; oc@yunify.com; jim@netgate.com;
>hongjun.ni@intel.com; j.bromhead@titan-ic.com; deri@ntop.org;
>fc@napatech.com; arthur.su@lionic.com; david.marchand@redhat.com
>Subject: Re: [EXT] [PATCH v1 4/4] regexdev: implement regex rte level
>functions
>
>06/04/2020 15:22, Pavan Nikhilesh Bhagavatula:
>> >06/04/2020 14:33, Pavan Nikhilesh Bhagavatula:
>> >> >> From: Pavan Nikhilesh Bhagavatula
>> >> >> > >+uint16_t
>> >> >> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t
>> >qp_id,
>> >> >> > >+			   struct rte_regex_ops **ops, uint16_t
>> >nb_ops)
>> >> >> > >+{
>> >> >> > >+	return regex_devices[dev_id]-
>> >> >> > >>enqueue(regex_devices[dev_id], qp_id,
>> >> >> > >+					      ops, nb_ops);
>> >> >> > >+}
>> >> >> >
>> >> >> > Move these functions to .h in-lining them.
>> >> >> > Also, please add debug checks @see
>> >> >rte_eth_rx_burst/rte_eth_tx_burst.
>> >> >>
>> >> >> O.K will update.
>> >> >
>> >> >In general, inlining is a pain for ABI compatibility.
>> >> >Please inline only if the gain is very significant.
>> >> >
>> >>
>> >> The performance gain mostly comes from hoisting
>> >`regex_devices[dev_id]` load above the
>> >> poll loop.
>> >> Since, the performance measurement application is still in pipeline
>> >and regexdev would be
>> >> experimental for next couple of releases I suggest inlining it now
>and
>> >worrying about ABI when
>> >> experimental tag needs to be removed.
>> >
>> >No, we must worry about ABI from the beginning.
>>
>> I though performance was the primary objective :-).
>
>It is.
>
>> >> We can follow the same path as done by ethdev
>> >[https://urldefense.proofpoint.com/v2/url?u=https-
>3A__www.mail-
>> >2Darchive.com_dev-
>>
>>40dpdk.org_msg142392.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xt
>f
>> >Q&r=E3SgYMjtKCMVsB-fmvgGV3o-
>> >g_fjLhk5Pupi9ijohpc&m=7Gqb6WKmZV5uY3xa7FRVrRVDz8Usrsd-
>>
>>rDjIKr6CUQQ&s=sQo2Kx9fzTNXwiQ2Fzki3s5GSuiiAEzz2VtN68_KKXo&e
>=
>> >]
>> >
>> >ethdev is not an argument.
>>
>> What about ring? [https://urldefense.proofpoint.com/v2/url?u=http-
>3A__mails.dpdk.org_archives_dev_2020-
>2DApril_161506.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=E3S
>gYMjtKCMVsB-fmvgGV3o-
>g_fjLhk5Pupi9ijohpc&m=u9gnM_YrOJDusN4yR8YUcUuUkri4tOjnHrQ0A
>Qd5zTw&s=uv6AQA-
>Zu7o6ugyhpGHLxFOk4SfEdkHfFGDmhzANRME&e= ]
>>
>> Why do we need to prove the same performance advantage using in-
>lining for datapath
>> critical functions again and again?
>
>Because every libraries have not the same usage and load.
>We should compare how much cycle is saved with inline vs
>how much cycles is, "in average", a regex burst?
>
>If you tell me regex processing is fast, OK, let's inline.
>

Regex processing speed would still be dependent on underlying device capabilities.

All we are trying to do is reduce the enqueue/dequeue completion time which would 
bring down the overall latency.

Thanks,
Pavan.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 13:22  0%           ` Pavan Nikhilesh Bhagavatula
@ 2020-04-06 13:36  0%             ` Thomas Monjalon
  2020-04-06 13:50  0%               ` Pavan Nikhilesh Bhagavatula
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-04-06 13:36 UTC (permalink / raw)
  To: Pavan Nikhilesh Bhagavatula
  Cc: Ori Kam, Jerin Jacob Kollanukkaran, xiang.w.wang, dev,
	Shahaf Shuler, hemant.agrawal, Opher Reviv, Alex Rosenbaum,
	Dovrat Zifroni, Prasun Kapoor, nipun.gupta, bruce.richardson,
	yang.a.hong, harry.chang, gu.jian1, shanjiangh, zhangy.yun,
	lixingfu, wushuai, yuyingxia, fanchenggang, davidfgao, liuzhong1,
	zhaoyong11, oc, jim, hongjun.ni, j.bromhead, deri, fc, arthur.su,
	david.marchand

06/04/2020 15:22, Pavan Nikhilesh Bhagavatula:
> >06/04/2020 14:33, Pavan Nikhilesh Bhagavatula:
> >> >> From: Pavan Nikhilesh Bhagavatula
> >> >> > >+uint16_t
> >> >> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t
> >qp_id,
> >> >> > >+			   struct rte_regex_ops **ops, uint16_t
> >nb_ops)
> >> >> > >+{
> >> >> > >+	return regex_devices[dev_id]-
> >> >> > >>enqueue(regex_devices[dev_id], qp_id,
> >> >> > >+					      ops, nb_ops);
> >> >> > >+}
> >> >> >
> >> >> > Move these functions to .h in-lining them.
> >> >> > Also, please add debug checks @see
> >> >rte_eth_rx_burst/rte_eth_tx_burst.
> >> >>
> >> >> O.K will update.
> >> >
> >> >In general, inlining is a pain for ABI compatibility.
> >> >Please inline only if the gain is very significant.
> >> >
> >>
> >> The performance gain mostly comes from hoisting
> >`regex_devices[dev_id]` load above the
> >> poll loop.
> >> Since, the performance measurement application is still in pipeline
> >and regexdev would be
> >> experimental for next couple of releases I suggest inlining it now and
> >worrying about ABI when
> >> experimental tag needs to be removed.
> >
> >No, we must worry about ABI from the beginning.
> 
> I though performance was the primary objective :-).

It is.

> >> We can follow the same path as done by ethdev
> >[https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mail-
> >2Darchive.com_dev-
> >40dpdk.org_msg142392.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xtf
> >Q&r=E3SgYMjtKCMVsB-fmvgGV3o-
> >g_fjLhk5Pupi9ijohpc&m=7Gqb6WKmZV5uY3xa7FRVrRVDz8Usrsd-
> >rDjIKr6CUQQ&s=sQo2Kx9fzTNXwiQ2Fzki3s5GSuiiAEzz2VtN68_KKXo&e=
> >]
> >
> >ethdev is not an argument.
> 
> What about ring? [http://mails.dpdk.org/archives/dev/2020-April/161506.html]
> 
> Why do we need to prove the same performance advantage using in-lining for datapath 
> critical functions again and again?

Because every libraries have not the same usage and load.
We should compare how much cycle is saved with inline vs
how much cycles is, "in average", a regex burst?

If you tell me regex processing is fast, OK, let's inline.



^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 13:14  3%         ` Thomas Monjalon
  2020-04-06 13:20  0%           ` Jerin Jacob
@ 2020-04-06 13:22  0%           ` Pavan Nikhilesh Bhagavatula
  2020-04-06 13:36  0%             ` Thomas Monjalon
  1 sibling, 1 reply; 200+ results
From: Pavan Nikhilesh Bhagavatula @ 2020-04-06 13:22 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: Ori Kam, Jerin Jacob Kollanukkaran, xiang.w.wang, dev,
	Shahaf Shuler, hemant.agrawal, Opher Reviv, Alex Rosenbaum,
	Dovrat Zifroni, Prasun Kapoor, nipun.gupta, bruce.richardson,
	yang.a.hong, harry.chang, gu.jian1, shanjiangh, zhangy.yun,
	lixingfu, wushuai, yuyingxia, fanchenggang, davidfgao, liuzhong1,
	zhaoyong11, oc, jim, hongjun.ni, j.bromhead, deri, fc, arthur.su,
	david.marchand

>06/04/2020 14:33, Pavan Nikhilesh Bhagavatula:
>> >> From: Pavan Nikhilesh Bhagavatula
>> >> > >+uint16_t
>> >> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t
>qp_id,
>> >> > >+			   struct rte_regex_ops **ops, uint16_t
>nb_ops)
>> >> > >+{
>> >> > >+	return regex_devices[dev_id]-
>> >> > >>enqueue(regex_devices[dev_id], qp_id,
>> >> > >+					      ops, nb_ops);
>> >> > >+}
>> >> >
>> >> > Move these functions to .h in-lining them.
>> >> > Also, please add debug checks @see
>> >rte_eth_rx_burst/rte_eth_tx_burst.
>> >>
>> >> O.K will update.
>> >
>> >In general, inlining is a pain for ABI compatibility.
>> >Please inline only if the gain is very significant.
>> >
>>
>> The performance gain mostly comes from hoisting
>`regex_devices[dev_id]` load above the
>> poll loop.
>> Since, the performance measurement application is still in pipeline
>and regexdev would be
>> experimental for next couple of releases I suggest inlining it now and
>worrying about ABI when
>> experimental tag needs to be removed.
>
>No, we must worry about ABI from the beginning.

I though performance was the primary objective :-).

>
>> We can follow the same path as done by ethdev
>[https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mail-
>2Darchive.com_dev-
>40dpdk.org_msg142392.html&d=DwICAg&c=nKjWec2b6R0mOyPaz7xtf
>Q&r=E3SgYMjtKCMVsB-fmvgGV3o-
>g_fjLhk5Pupi9ijohpc&m=7Gqb6WKmZV5uY3xa7FRVrRVDz8Usrsd-
>rDjIKr6CUQQ&s=sQo2Kx9fzTNXwiQ2Fzki3s5GSuiiAEzz2VtN68_KKXo&e=
>]
>
>ethdev is not an argument.

What about ring? [http://mails.dpdk.org/archives/dev/2020-April/161506.html]

Why do we need to prove the same performance advantage using in-lining for datapath 
critical functions again and again?

>
>


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 13:14  3%         ` Thomas Monjalon
@ 2020-04-06 13:20  0%           ` Jerin Jacob
  2020-04-06 13:22  0%           ` Pavan Nikhilesh Bhagavatula
  1 sibling, 0 replies; 200+ results
From: Jerin Jacob @ 2020-04-06 13:20 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: Pavan Nikhilesh Bhagavatula, Ori Kam, Jerin Jacob Kollanukkaran,
	xiang.w.wang, dev, Shahaf Shuler, hemant.agrawal, Opher Reviv,
	Alex Rosenbaum, Dovrat Zifroni, Prasun Kapoor, nipun.gupta,
	bruce.richardson, yang.a.hong, harry.chang, gu.jian1, shanjiangh,
	zhangy.yun, lixingfu, wushuai, yuyingxia, fanchenggang,
	davidfgao, liuzhong1, zhaoyong11, oc, jim, hongjun.ni,
	j.bromhead, deri, fc, arthur.su, david.marchand

On Mon, Apr 6, 2020 at 6:44 PM Thomas Monjalon <thomas@monjalon.net> wrote:
>
> 06/04/2020 14:33, Pavan Nikhilesh Bhagavatula:
> > >> From: Pavan Nikhilesh Bhagavatula
> > >> > >+uint16_t
> > >> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
> > >> > >+                          struct rte_regex_ops **ops, uint16_t nb_ops)
> > >> > >+{
> > >> > >+       return regex_devices[dev_id]-
> > >> > >>enqueue(regex_devices[dev_id], qp_id,
> > >> > >+                                             ops, nb_ops);
> > >> > >+}
> > >> >
> > >> > Move these functions to .h in-lining them.
> > >> > Also, please add debug checks @see
> > >rte_eth_rx_burst/rte_eth_tx_burst.
> > >>
> > >> O.K will update.
> > >
> > >In general, inlining is a pain for ABI compatibility.
> > >Please inline only if the gain is very significant.
> > >
> >
> > The performance gain mostly comes from hoisting `regex_devices[dev_id]` load above the
> > poll loop.
> > Since, the performance measurement application is still in pipeline and regexdev would be
> > experimental for next couple of releases I suggest inlining it now and worrying about ABI when
> > experimental tag needs to be removed.
>
> No, we must worry about ABI from the beginning.

I think, we need to have the performance number first before we decide
one or another.


>
> > We can follow the same path as done by ethdev [https://www.mail-archive.com/dev@dpdk.org/msg142392.html]
>
> ethdev is not an argument.

Actually this thread explains how to make it inline without exposing
the internal structure unlike existing ethdev. The effort
is stalled due to PMD changes required. In this case, regexdev is new
so it is the correct time to add such code.




>
>
>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 12:33  3%       ` Pavan Nikhilesh Bhagavatula
@ 2020-04-06 13:14  3%         ` Thomas Monjalon
  2020-04-06 13:20  0%           ` Jerin Jacob
  2020-04-06 13:22  0%           ` Pavan Nikhilesh Bhagavatula
  0 siblings, 2 replies; 200+ results
From: Thomas Monjalon @ 2020-04-06 13:14 UTC (permalink / raw)
  To: Pavan Nikhilesh Bhagavatula
  Cc: Ori Kam, Jerin Jacob Kollanukkaran, xiang.w.wang, dev,
	Shahaf Shuler, hemant.agrawal, Opher Reviv, Alex Rosenbaum,
	Dovrat Zifroni, Prasun Kapoor, nipun.gupta, bruce.richardson,
	yang.a.hong, harry.chang, gu.jian1, shanjiangh, zhangy.yun,
	lixingfu, wushuai, yuyingxia, fanchenggang, davidfgao, liuzhong1,
	zhaoyong11, oc, jim, hongjun.ni, j.bromhead, deri, fc, arthur.su,
	david.marchand

06/04/2020 14:33, Pavan Nikhilesh Bhagavatula:
> >> From: Pavan Nikhilesh Bhagavatula
> >> > >+uint16_t
> >> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
> >> > >+			   struct rte_regex_ops **ops, uint16_t nb_ops)
> >> > >+{
> >> > >+	return regex_devices[dev_id]-
> >> > >>enqueue(regex_devices[dev_id], qp_id,
> >> > >+					      ops, nb_ops);
> >> > >+}
> >> >
> >> > Move these functions to .h in-lining them.
> >> > Also, please add debug checks @see
> >rte_eth_rx_burst/rte_eth_tx_burst.
> >>
> >> O.K will update.
> >
> >In general, inlining is a pain for ABI compatibility.
> >Please inline only if the gain is very significant.
> >
> 
> The performance gain mostly comes from hoisting `regex_devices[dev_id]` load above the 
> poll loop. 
> Since, the performance measurement application is still in pipeline and regexdev would be 
> experimental for next couple of releases I suggest inlining it now and worrying about ABI when
> experimental tag needs to be removed.

No, we must worry about ABI from the beginning.

> We can follow the same path as done by ethdev [https://www.mail-archive.com/dev@dpdk.org/msg142392.html]

ethdev is not an argument.




^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  2020-04-06 11:16  3%     ` Thomas Monjalon
@ 2020-04-06 12:33  3%       ` Pavan Nikhilesh Bhagavatula
  2020-04-06 13:14  3%         ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Pavan Nikhilesh Bhagavatula @ 2020-04-06 12:33 UTC (permalink / raw)
  To: Thomas Monjalon, Ori Kam
  Cc: Jerin Jacob Kollanukkaran, xiang.w.wang, dev, Shahaf Shuler,
	hemant.agrawal, Opher Reviv, Alex Rosenbaum, Dovrat Zifroni,
	Prasun Kapoor, nipun.gupta, bruce.richardson, yang.a.hong,
	harry.chang, gu.jian1, shanjiangh, zhangy.yun, lixingfu, wushuai,
	yuyingxia, fanchenggang, davidfgao, liuzhong1, zhaoyong11, oc,
	jim, hongjun.ni, j.bromhead, deri, fc, arthur.su, david.marchand

>> From: Pavan Nikhilesh Bhagavatula
>> > >+uint16_t
>> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
>> > >+			   struct rte_regex_ops **ops, uint16_t nb_ops)
>> > >+{
>> > >+	return regex_devices[dev_id]-
>> > >>enqueue(regex_devices[dev_id], qp_id,
>> > >+					      ops, nb_ops);
>> > >+}
>> >
>> > Move these functions to .h in-lining them.
>> > Also, please add debug checks @see
>rte_eth_rx_burst/rte_eth_tx_burst.
>>
>> O.K will update.
>
>In general, inlining is a pain for ABI compatibility.
>Please inline only if the gain is very significant.
>

The performance gain mostly comes from hoisting `regex_devices[dev_id]` load above the 
poll loop. 
Since, the performance measurement application is still in pipeline and regexdev would be 
experimental for next couple of releases I suggest inlining it now and worrying about ABI when
experimental tag needs to be removed.

We can follow the same path as done by ethdev [https://www.mail-archive.com/dev@dpdk.org/msg142392.html]

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions
  @ 2020-04-06 11:16  3%     ` Thomas Monjalon
  2020-04-06 12:33  3%       ` Pavan Nikhilesh Bhagavatula
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-04-06 11:16 UTC (permalink / raw)
  To: Pavan Nikhilesh Bhagavatula, Ori Kam
  Cc: Jerin Jacob Kollanukkaran, xiang.w.wang, dev, Shahaf Shuler,
	hemant.agrawal, Opher Reviv, Alex Rosenbaum, Dovrat Zifroni,
	Prasun Kapoor, nipun.gupta, bruce.richardson, yang.a.hong,
	harry.chang, gu.jian1, shanjiangh, zhangy.yun, lixingfu, wushuai,
	yuyingxia, fanchenggang, davidfgao, liuzhong1, zhaoyong11, oc,
	jim, hongjun.ni, j.bromhead, deri, fc, arthur.su, david.marchand

05/04/2020 17:04, Ori Kam:
> From: Pavan Nikhilesh Bhagavatula
> > >+uint16_t
> > >+rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
> > >+			   struct rte_regex_ops **ops, uint16_t nb_ops)
> > >+{
> > >+	return regex_devices[dev_id]-
> > >>enqueue(regex_devices[dev_id], qp_id,
> > >+					      ops, nb_ops);
> > >+}
> > 
> > Move these functions to .h in-lining them.
> > Also, please add debug checks @see rte_eth_rx_burst/rte_eth_tx_burst.
> 
> O.K will update.

In general, inlining is a pain for ABI compatibility.
Please inline only if the gain is very significant.



^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode
  2020-04-03 17:42  1%       ` [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode Konstantin Ananyev
@ 2020-04-04 17:27  0%         ` Wang, Haiyue
  2020-04-08  5:00  0%         ` Honnappa Nagarahalli
  1 sibling, 0 replies; 200+ results
From: Wang, Haiyue @ 2020-04-04 17:27 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev
  Cc: honnappa.nagarahalli, david.marchand, jielong.zjl, Ananyev, Konstantin

> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Konstantin Ananyev
> Sent: Saturday, April 4, 2020 01:42
> To: dev@dpdk.org
> Cc: honnappa.nagarahalli@arm.com; david.marchand@redhat.com; jielong.zjl@antfin.com; Ananyev,
> Konstantin <konstantin.ananyev@intel.com>
> Subject: [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode
> 
> Introduce relaxed tail sync (RTS) mode for MT ring synchronization.
> Aim to reduce stall times in case when ring is used on
> overcommited cpus (multiple active threads on the same cpu).
> The main difference from original MP/MC algorithm is that
> tail value is increased not by every thread that finished enqueue/dequeue,
> but only by the last one.
> That allows threads to avoid spinning on ring tail value,
> leaving actual tail value change to the last thread in the update queue.
> 
> check-abi.sh reports what I believe is a false-positive about
> ring cons/prod changes. As a workaround, devtools/libabigail.abignore is
> updated to suppress *struct ring* related errors.
> 
> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> ---
>  devtools/libabigail.abignore           |   7 +
>  lib/librte_ring/Makefile               |   5 +-
>  lib/librte_ring/meson.build            |   5 +-
>  lib/librte_ring/rte_ring.c             | 100 +++++++-
>  lib/librte_ring/rte_ring.h             | 110 ++++++++-
>  lib/librte_ring/rte_ring_elem.h        |  86 ++++++-
>  lib/librte_ring/rte_ring_rts.h         | 316 +++++++++++++++++++++++++
>  lib/librte_ring/rte_ring_rts_elem.h    | 205 ++++++++++++++++
>  lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++++++
>  9 files changed, 1015 insertions(+), 29 deletions(-)
>  create mode 100644 lib/librte_ring/rte_ring_rts.h
>  create mode 100644 lib/librte_ring/rte_ring_rts_elem.h
>  create mode 100644 lib/librte_ring/rte_ring_rts_generic.h
> 


>  #ifdef __cplusplus
> diff --git a/lib/librte_ring/rte_ring_rts.h b/lib/librte_ring/rte_ring_rts.h
> new file mode 100644
> index 000000000..18404fe48
> --- /dev/null
> +++ b/lib/librte_ring/rte_ring_rts.h
> @@ -0,0 +1,316 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * Copyright (c) 2010-2017 Intel Corporation
> + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
> + * All rights reserved.
> + * Derived from FreeBSD's bufring.h

Find that it is buf_ring.h in real ;-)

> + * Used as BSD-3 Licensed with permission from Kip Macy.
> + */

> --
> 2.17.1


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode
  2020-04-03 17:42  3%     ` [dpdk-dev] [PATCH v3 0/9] New sync modes for ring Konstantin Ananyev
  @ 2020-04-03 17:42  1%       ` Konstantin Ananyev
  2020-04-04 17:27  0%         ` Wang, Haiyue
  2020-04-08  5:00  0%         ` Honnappa Nagarahalli
  1 sibling, 2 replies; 200+ results
From: Konstantin Ananyev @ 2020-04-03 17:42 UTC (permalink / raw)
  To: dev; +Cc: honnappa.nagarahalli, david.marchand, jielong.zjl, Konstantin Ananyev

Introduce relaxed tail sync (RTS) mode for MT ring synchronization.
Aim to reduce stall times in case when ring is used on
overcommited cpus (multiple active threads on the same cpu).
The main difference from original MP/MC algorithm is that
tail value is increased not by every thread that finished enqueue/dequeue,
but only by the last one.
That allows threads to avoid spinning on ring tail value,
leaving actual tail value change to the last thread in the update queue.

check-abi.sh reports what I believe is a false-positive about
ring cons/prod changes. As a workaround, devtools/libabigail.abignore is
updated to suppress *struct ring* related errors.

Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
---
 devtools/libabigail.abignore           |   7 +
 lib/librte_ring/Makefile               |   5 +-
 lib/librte_ring/meson.build            |   5 +-
 lib/librte_ring/rte_ring.c             | 100 +++++++-
 lib/librte_ring/rte_ring.h             | 110 ++++++++-
 lib/librte_ring/rte_ring_elem.h        |  86 ++++++-
 lib/librte_ring/rte_ring_rts.h         | 316 +++++++++++++++++++++++++
 lib/librte_ring/rte_ring_rts_elem.h    | 205 ++++++++++++++++
 lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++++++
 9 files changed, 1015 insertions(+), 29 deletions(-)
 create mode 100644 lib/librte_ring/rte_ring_rts.h
 create mode 100644 lib/librte_ring/rte_ring_rts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_rts_generic.h

diff --git a/devtools/libabigail.abignore b/devtools/libabigail.abignore
index a59df8f13..cd86d89ca 100644
--- a/devtools/libabigail.abignore
+++ b/devtools/libabigail.abignore
@@ -11,3 +11,10 @@
         type_kind = enum
         name = rte_crypto_asym_xform_type
         changed_enumerators = RTE_CRYPTO_ASYM_XFORM_TYPE_LIST_END
+; Ignore updates of ring prod/cons
+[suppress_type]
+        type_kind = struct
+        name = rte_ring
+[suppress_type]
+        type_kind = struct
+        name = rte_event_ring
diff --git a/lib/librte_ring/Makefile b/lib/librte_ring/Makefile
index 917c560ad..8f5c284cc 100644
--- a/lib/librte_ring/Makefile
+++ b/lib/librte_ring/Makefile
@@ -18,6 +18,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_RING) := rte_ring.c
 SYMLINK-$(CONFIG_RTE_LIBRTE_RING)-include := rte_ring.h \
 					rte_ring_elem.h \
 					rte_ring_generic.h \
-					rte_ring_c11_mem.h
+					rte_ring_c11_mem.h \
+					rte_ring_rts.h \
+					rte_ring_rts_elem.h \
+					rte_ring_rts_generic.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ring/meson.build b/lib/librte_ring/meson.build
index f2f3ccc88..612936afb 100644
--- a/lib/librte_ring/meson.build
+++ b/lib/librte_ring/meson.build
@@ -5,7 +5,10 @@ sources = files('rte_ring.c')
 headers = files('rte_ring.h',
 		'rte_ring_elem.h',
 		'rte_ring_c11_mem.h',
-		'rte_ring_generic.h')
+		'rte_ring_generic.h',
+		'rte_ring_rts.h',
+		'rte_ring_rts_elem.h',
+		'rte_ring_rts_generic.h')
 
 # rte_ring_create_elem and rte_ring_get_memsize_elem are experimental
 allow_experimental_apis = true
diff --git a/lib/librte_ring/rte_ring.c b/lib/librte_ring/rte_ring.c
index fa5733907..222eec0fb 100644
--- a/lib/librte_ring/rte_ring.c
+++ b/lib/librte_ring/rte_ring.c
@@ -45,6 +45,9 @@ EAL_REGISTER_TAILQ(rte_ring_tailq)
 /* true if x is a power of 2 */
 #define POWEROF2(x) ((((x)-1) & (x)) == 0)
 
+/* by default set head/tail distance as 1/8 of ring capacity */
+#define HTD_MAX_DEF	8
+
 /* return the size of memory occupied by a ring */
 ssize_t
 rte_ring_get_memsize_elem(unsigned int esize, unsigned int count)
@@ -79,11 +82,84 @@ rte_ring_get_memsize(unsigned int count)
 	return rte_ring_get_memsize_elem(sizeof(void *), count);
 }
 
+/*
+ * internal helper function to reset prod/cons head-tail values.
+ */
+static void
+reset_headtail(void *p)
+{
+	struct rte_ring_headtail *ht;
+	struct rte_ring_rts_headtail *ht_rts;
+
+	ht = p;
+	ht_rts = p;
+
+	switch (ht->sync_type) {
+	case RTE_RING_SYNC_MT:
+	case RTE_RING_SYNC_ST:
+		ht->head = 0;
+		ht->tail = 0;
+		break;
+	case RTE_RING_SYNC_MT_RTS:
+		ht_rts->head.raw = 0;
+		ht_rts->tail.raw = 0;
+		break;
+	default:
+		/* unknown sync mode */
+		RTE_ASSERT(0);
+	}
+}
+
 void
 rte_ring_reset(struct rte_ring *r)
 {
-	r->prod.head = r->cons.head = 0;
-	r->prod.tail = r->cons.tail = 0;
+	reset_headtail(&r->prod);
+	reset_headtail(&r->cons);
+}
+
+/*
+ * helper function, calculates sync_type values for prod and cons
+ * based on input flags. Returns zero at success or negative
+ * errno value otherwise.
+ */
+static int
+get_sync_type(uint32_t flags, enum rte_ring_sync_type *prod_st,
+	enum rte_ring_sync_type *cons_st)
+{
+	static const uint32_t prod_st_flags =
+		(RING_F_SP_ENQ | RING_F_MP_RTS_ENQ);
+	static const uint32_t cons_st_flags =
+		(RING_F_SC_DEQ | RING_F_MC_RTS_DEQ);
+
+	switch (flags & prod_st_flags) {
+	case 0:
+		*prod_st = RTE_RING_SYNC_MT;
+		break;
+	case RING_F_SP_ENQ:
+		*prod_st = RTE_RING_SYNC_ST;
+		break;
+	case RING_F_MP_RTS_ENQ:
+		*prod_st = RTE_RING_SYNC_MT_RTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (flags & cons_st_flags) {
+	case 0:
+		*cons_st = RTE_RING_SYNC_MT;
+		break;
+	case RING_F_SC_DEQ:
+		*cons_st = RTE_RING_SYNC_ST;
+		break;
+	case RING_F_MC_RTS_DEQ:
+		*cons_st = RTE_RING_SYNC_MT_RTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 int
@@ -100,16 +176,20 @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
 	RTE_BUILD_BUG_ON((offsetof(struct rte_ring, prod) &
 			  RTE_CACHE_LINE_MASK) != 0);
 
+	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, sync_type) !=
+		offsetof(struct rte_ring_rts_headtail, sync_type));
+	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, tail) !=
+		offsetof(struct rte_ring_rts_headtail, tail.val.pos));
+
 	/* init the ring structure */
 	memset(r, 0, sizeof(*r));
 	ret = strlcpy(r->name, name, sizeof(r->name));
 	if (ret < 0 || ret >= (int)sizeof(r->name))
 		return -ENAMETOOLONG;
 	r->flags = flags;
-	r->prod.sync_type = (flags & RING_F_SP_ENQ) ?
-		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
-	r->cons.sync_type = (flags & RING_F_SC_DEQ) ?
-		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
+	ret = get_sync_type(flags, &r->prod.sync_type, &r->cons.sync_type);
+	if (ret != 0)
+		return ret;
 
 	if (flags & RING_F_EXACT_SZ) {
 		r->size = rte_align32pow2(count + 1);
@@ -126,8 +206,12 @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
 		r->mask = count - 1;
 		r->capacity = r->mask;
 	}
-	r->prod.head = r->cons.head = 0;
-	r->prod.tail = r->cons.tail = 0;
+
+	/* set default values for head-tail distance */
+	if (flags & RING_F_MP_RTS_ENQ)
+		rte_ring_set_prod_htd_max(r, r->capacity / HTD_MAX_DEF);
+	if (flags & RING_F_MC_RTS_DEQ)
+		rte_ring_set_cons_htd_max(r, r->capacity / HTD_MAX_DEF);
 
 	return 0;
 }
diff --git a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h
index d4775a063..f6f084d79 100644
--- a/lib/librte_ring/rte_ring.h
+++ b/lib/librte_ring/rte_ring.h
@@ -48,6 +48,7 @@ extern "C" {
 #include <rte_branch_prediction.h>
 #include <rte_memzone.h>
 #include <rte_pause.h>
+#include <rte_debug.h>
 
 #define RTE_TAILQ_RING_NAME "RTE_RING"
 
@@ -65,10 +66,13 @@ enum rte_ring_queue_behavior {
 enum rte_ring_sync_type {
 	RTE_RING_SYNC_MT,     /**< multi-thread safe (default mode) */
 	RTE_RING_SYNC_ST,     /**< single thread only */
+#ifdef ALLOW_EXPERIMENTAL_API
+	RTE_RING_SYNC_MT_RTS, /**< multi-thread relaxed tail sync */
+#endif
 };
 
 /**
- * structure to hold a pair of head/tail values and other metadata.
+ * structures to hold a pair of head/tail values and other metadata.
  * Depending on sync_type format of that structure might be different,
  * but offset for *sync_type* and *tail* values should remain the same.
  */
@@ -84,6 +88,21 @@ struct rte_ring_headtail {
 	};
 };
 
+union rte_ring_ht_poscnt {
+	uint64_t raw;
+	struct {
+		uint32_t cnt; /**< head/tail reference counter */
+		uint32_t pos; /**< head/tail position */
+	} val;
+};
+
+struct rte_ring_rts_headtail {
+	volatile union rte_ring_ht_poscnt tail;
+	enum rte_ring_sync_type sync_type;  /**< sync type of prod/cons */
+	uint32_t htd_max;   /**< max allowed distance between head/tail */
+	volatile union rte_ring_ht_poscnt head;
+};
+
 /**
  * An RTE ring structure.
  *
@@ -111,11 +130,21 @@ struct rte_ring {
 	char pad0 __rte_cache_aligned; /**< empty cache line */
 
 	/** Ring producer status. */
-	struct rte_ring_headtail prod __rte_cache_aligned;
+	RTE_STD_C11
+	union {
+		struct rte_ring_headtail prod;
+		struct rte_ring_rts_headtail rts_prod;
+	}  __rte_cache_aligned;
+
 	char pad1 __rte_cache_aligned; /**< empty cache line */
 
 	/** Ring consumer status. */
-	struct rte_ring_headtail cons __rte_cache_aligned;
+	RTE_STD_C11
+	union {
+		struct rte_ring_headtail cons;
+		struct rte_ring_rts_headtail rts_cons;
+	}  __rte_cache_aligned;
+
 	char pad2 __rte_cache_aligned; /**< empty cache line */
 };
 
@@ -132,6 +161,9 @@ struct rte_ring {
 #define RING_F_EXACT_SZ 0x0004
 #define RTE_RING_SZ_MASK  (0x7fffffffU) /**< Ring size mask */
 
+#define RING_F_MP_RTS_ENQ 0x0008 /**< The default enqueue is "MP RTS". */
+#define RING_F_MC_RTS_DEQ 0x0010 /**< The default dequeue is "MC RTS". */
+
 #define __IS_SP RTE_RING_SYNC_ST
 #define __IS_MP RTE_RING_SYNC_MT
 #define __IS_SC RTE_RING_SYNC_ST
@@ -461,6 +493,10 @@ rte_ring_sp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
 			RTE_RING_SYNC_ST, free_space);
 }
 
+#ifdef ALLOW_EXPERIMENTAL_API
+#include <rte_ring_rts.h>
+#endif
+
 /**
  * Enqueue several objects on a ring.
  *
@@ -484,8 +520,21 @@ static __rte_always_inline unsigned int
 rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
 		      unsigned int n, unsigned int *free_space)
 {
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-			r->prod.sync_type, free_space);
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_bulk(r, obj_table, n, free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_bulk(r, obj_table, n, free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_bulk(r, obj_table, n,
+			free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 /**
@@ -619,8 +668,20 @@ static __rte_always_inline unsigned int
 rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,
 		unsigned int *available)
 {
-	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-				r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_bulk(r, obj_table, n, available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_bulk(r, obj_table, n, available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_bulk(r, obj_table, n, available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 /**
@@ -940,8 +1001,21 @@ static __rte_always_inline unsigned
 rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table,
 		      unsigned int n, unsigned int *free_space)
 {
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_VARIABLE,
-			r->prod.sync_type, free_space);
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_burst(r, obj_table, n, free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_burst(r, obj_table, n, free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_burst(r, obj_table, n,
+			free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 /**
@@ -1020,9 +1094,21 @@ static __rte_always_inline unsigned
 rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table,
 		unsigned int n, unsigned int *available)
 {
-	return __rte_ring_do_dequeue(r, obj_table, n,
-				RTE_RING_QUEUE_VARIABLE,
-				r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_burst(r, obj_table, n, available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_burst(r, obj_table, n, available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_burst(r, obj_table, n,
+			available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 #ifdef __cplusplus
diff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h
index 28f9836e6..5de0850dc 100644
--- a/lib/librte_ring/rte_ring_elem.h
+++ b/lib/librte_ring/rte_ring_elem.h
@@ -542,6 +542,8 @@ rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
 			RTE_RING_QUEUE_FIXED, __IS_SP, free_space);
 }
 
+#include <rte_ring_rts_elem.h>
+
 /**
  * Enqueue several objects on a ring.
  *
@@ -571,6 +573,26 @@ rte_ring_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
 {
 	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
 			RTE_RING_QUEUE_FIXED, r->prod.sync_type, free_space);
+
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_bulk_elem(r, obj_table, esize, n,
+			free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_bulk_elem(r, obj_table, esize, n,
+			free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_bulk_elem(r, obj_table, esize, n,
+			free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (free_space != NULL)
+		*free_space = 0;
+	return 0;
 }
 
 /**
@@ -733,8 +755,25 @@ static __rte_always_inline unsigned int
 rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
 		unsigned int esize, unsigned int n, unsigned int *available)
 {
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_FIXED, r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_bulk_elem(r, obj_table, esize, n,
+			available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_bulk_elem(r, obj_table, esize, n,
+			available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_bulk_elem(r, obj_table, esize,
+			n, available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (available != NULL)
+		*available = 0;
+	return 0;
 }
 
 /**
@@ -901,8 +940,25 @@ static __rte_always_inline unsigned
 rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
 		unsigned int esize, unsigned int n, unsigned int *free_space)
 {
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_VARIABLE, r->prod.sync_type, free_space);
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_burst_elem(r, obj_table, esize, n,
+			free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_burst_elem(r, obj_table, esize, n,
+			free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_burst_elem(r, obj_table, esize,
+			n, free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (free_space != NULL)
+		*free_space = 0;
+	return 0;
 }
 
 /**
@@ -993,9 +1049,25 @@ static __rte_always_inline unsigned int
 rte_ring_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
 		unsigned int esize, unsigned int n, unsigned int *available)
 {
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-				RTE_RING_QUEUE_VARIABLE,
-				r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_burst_elem(r, obj_table, esize, n,
+			available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_burst_elem(r, obj_table, esize, n,
+			available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_burst_elem(r, obj_table, esize,
+			n, available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (available != NULL)
+		*available = 0;
+	return 0;
 }
 
 #ifdef __cplusplus
diff --git a/lib/librte_ring/rte_ring_rts.h b/lib/librte_ring/rte_ring_rts.h
new file mode 100644
index 000000000..18404fe48
--- /dev/null
+++ b/lib/librte_ring/rte_ring_rts.h
@@ -0,0 +1,316 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#ifndef _RTE_RING_RTS_H_
+#define _RTE_RING_RTS_H_
+
+/**
+ * @file rte_ring_rts.h
+ * @b EXPERIMENTAL: this API may change without prior notice
+ * It is not recommended to include this file directly.
+ * Please include <rte_ring.h> instead.
+ *
+ * Contains functions for Relaxed Tail Sync (RTS) ring mode.
+ * The main idea remains the same as for our original MP/MC synchronization
+ * mechanism.
+ * The main difference is that tail value is increased not
+ * by every thread that finished enqueue/dequeue,
+ * but only by the last one doing enqueue/dequeue.
+ * That allows threads to skip spinning on tail value,
+ * leaving actual tail value change to last thread in the update queue.
+ * RTS requires 2 64-bit CAS for each enqueue(/dequeue) operation:
+ * one for head update, second for tail update.
+ * As a gain it allows thread to avoid spinning/waiting on tail value.
+ * In comparision original MP/MC algorithm requires one 32-bit CAS
+ * for head update and waiting/spinning on tail value.
+ *
+ * Brief outline:
+ *  - introduce refcnt for both head and tail.
+ *  - increment head.refcnt for each head.value update
+ *  - write head:value and head:refcnt atomically (64-bit CAS)
+ *  - move tail.value ahead only when tail.refcnt + 1 == head.refcnt
+ *  - increment tail.refcnt when each enqueue/dequeue op finishes
+ *    (no matter is tail:value going to change or not)
+ *  - write tail.value and tail.recnt atomically (64-bit CAS)
+ *
+ * To avoid producer/consumer starvation:
+ *  - limit max allowed distance between head and tail value (HTD_MAX).
+ *    I.E. thread is allowed to proceed with changing head.value,
+ *    only when:  head.value - tail.value <= HTD_MAX
+ * HTD_MAX is an optional parameter.
+ * With HTD_MAX == 0 we'll have fully serialized ring -
+ * i.e. only one thread at a time will be able to enqueue/dequeue
+ * to/from the ring.
+ * With HTD_MAX >= ring.capacity - no limitation.
+ * By default HTD_MAX == ring.capacity / 8.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ring_rts_generic.h>
+
+/**
+ * @internal Enqueue several objects on the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param free_space
+ *   returns the amount of space after the enqueue operation has finished
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_enqueue(struct rte_ring *r, void * const *obj_table,
+		uint32_t n, enum rte_ring_queue_behavior behavior,
+		uint32_t *free_space)
+{
+	uint32_t free, head;
+
+	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
+
+	if (n != 0) {
+		ENQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
+		__rte_ring_rts_update_tail(&r->rts_prod);
+	}
+
+	if (free_space != NULL)
+		*free_space = free - n;
+	return n;
+}
+
+/**
+ * @internal Dequeue several objects from the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to pull from the ring.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param available
+ *   returns the number of remaining ring entries after the dequeue has finished
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_dequeue(struct rte_ring *r, void **obj_table,
+		uint32_t n, enum rte_ring_queue_behavior behavior,
+		uint32_t *available)
+{
+	uint32_t entries, head;
+
+	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
+
+	if (n != 0) {
+		DEQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
+		__rte_ring_rts_update_tail(&r->rts_cons);
+	}
+
+	if (available != NULL)
+		*available = entries - n;
+	return n;
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mp_rts_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS ring (multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mc_rts_dequeue_bulk(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			available);
+}
+
+/**
+ * Return producer max Head-Tail-Distance (HTD).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   Producer HTD value, if producer is set in appropriate sync mode,
+ *   or UINT32_MAX otherwise.
+ */
+__rte_experimental
+static inline uint32_t
+rte_ring_get_prod_htd_max(const struct rte_ring *r)
+{
+	if (r->prod.sync_type == RTE_RING_SYNC_MT_RTS)
+		return r->rts_prod.htd_max;
+	return UINT32_MAX;
+}
+
+/**
+ * Set producer max Head-Tail-Distance (HTD).
+ * Note that producer has to use appropriate sync mode (RTS).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param v
+ *   new HTD value to setup.
+ * @return
+ *   Zero on success, or negative error code otherwise.
+ */
+__rte_experimental
+static inline int
+rte_ring_set_prod_htd_max(struct rte_ring *r, uint32_t v)
+{
+	if (r->prod.sync_type != RTE_RING_SYNC_MT_RTS)
+		return -ENOTSUP;
+
+	r->rts_prod.htd_max = v;
+	return 0;
+}
+
+/**
+ * Return consumer max Head-Tail-Distance (HTD).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   Consumer HTD value, if consumer is set in appropriate sync mode,
+ *   or UINT32_MAX otherwise.
+ */
+__rte_experimental
+static inline uint32_t
+rte_ring_get_cons_htd_max(const struct rte_ring *r)
+{
+	if (r->cons.sync_type == RTE_RING_SYNC_MT_RTS)
+		return r->rts_cons.htd_max;
+	return UINT32_MAX;
+}
+
+/**
+ * Set consumer max Head-Tail-Distance (HTD).
+ * Note that consumer has to use appropriate sync mode (RTS).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param v
+ *   new HTD value to setup.
+ * @return
+ *   Zero on success, or negative error code otherwise.
+ */
+__rte_experimental
+static inline int
+rte_ring_set_cons_htd_max(struct rte_ring *r, uint32_t v)
+{
+	if (r->cons.sync_type != RTE_RING_SYNC_MT_RTS)
+		return -ENOTSUP;
+
+	r->rts_cons.htd_max = v;
+	return 0;
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mp_rts_enqueue_burst(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS  ring (multi-consumers safe).
+ * When the requested objects are more than the available objects,
+ * only dequeue the actual number of objects.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mc_rts_dequeue_burst(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, available);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_RING_RTS_H_ */
diff --git a/lib/librte_ring/rte_ring_rts_elem.h b/lib/librte_ring/rte_ring_rts_elem.h
new file mode 100644
index 000000000..71a331b23
--- /dev/null
+++ b/lib/librte_ring/rte_ring_rts_elem.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#ifndef _RTE_RING_RTS_ELEM_H_
+#define _RTE_RING_RTS_ELEM_H_
+
+/**
+ * @file rte_ring_rts_elem.h
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * It is not recommended to include this file directly.
+ * Please include <rte_ring_elem.h> instead.
+ * Contains *ring_elem* functions for Relaxed Tail Sync (RTS) ring mode.
+ * for more details please refer to <rte_ring_rts.h>.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ring_rts_generic.h>
+
+/**
+ * @internal Enqueue several objects on the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param free_space
+ *   returns the amount of space after the enqueue operation has finished
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_enqueue_elem(struct rte_ring *r, void * const *obj_table,
+	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
+	uint32_t *free_space)
+{
+	uint32_t free, head;
+
+	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
+
+	if (n != 0) {
+		__rte_ring_enqueue_elems(r, head, obj_table, esize, n);
+		__rte_ring_rts_update_tail(&r->rts_prod);
+	}
+
+	if (free_space != NULL)
+		*free_space = free - n;
+	return n;
+}
+
+/**
+ * @internal Dequeue several objects from the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to pull from the ring.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param available
+ *   returns the number of remaining ring entries after the dequeue has finished
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_dequeue_elem(struct rte_ring *r, void **obj_table,
+	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
+	uint32_t *available)
+{
+	uint32_t entries, head;
+
+	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
+
+	if (n != 0) {
+		__rte_ring_dequeue_elems(r, head, obj_table, esize, n);
+		__rte_ring_rts_update_tail(&r->rts_cons);
+	}
+
+	if (available != NULL)
+		*available = entries - n;
+	return n;
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mp_rts_enqueue_bulk_elem(struct rte_ring *r, void * const *obj_table,
+	unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_FIXED, free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS ring (multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mc_rts_dequeue_bulk_elem(struct rte_ring *r, void **obj_table,
+	unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
+		RTE_RING_QUEUE_FIXED, available);
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mp_rts_enqueue_burst_elem(struct rte_ring *r, void * const *obj_table,
+	unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS  ring (multi-consumers safe).
+ * When the requested objects are more than the available objects,
+ * only dequeue the actual number of objects.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mc_rts_dequeue_burst_elem(struct rte_ring *r, void **obj_table,
+	unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, available);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_RING_RTS_ELEM_H_ */
diff --git a/lib/librte_ring/rte_ring_rts_generic.h b/lib/librte_ring/rte_ring_rts_generic.h
new file mode 100644
index 000000000..f88460d47
--- /dev/null
+++ b/lib/librte_ring/rte_ring_rts_generic.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#ifndef _RTE_RING_RTS_GENERIC_H_
+#define _RTE_RING_RTS_GENERIC_H_
+
+/**
+ * @file rte_ring_rts_generic.h
+ * It is not recommended to include this file directly,
+ * include <rte_ring.h> instead.
+ * Contains internal helper functions for Relaxed Tail Sync (RTS) ring mode.
+ * For more information please refer to <rte_ring_rts.h>.
+ */
+
+/**
+ * @internal This function updates tail values.
+ */
+static __rte_always_inline void
+__rte_ring_rts_update_tail(struct rte_ring_rts_headtail *ht)
+{
+	union rte_ring_ht_poscnt h, ot, nt;
+
+	/*
+	 * If there are other enqueues/dequeues in progress that
+	 * might preceded us, then don't update tail with new value.
+	 */
+
+	do {
+		ot.raw = ht->tail.raw;
+		rte_smp_rmb();
+
+		/* on 32-bit systems we have to do atomic read here */
+		h.raw = rte_atomic64_read((rte_atomic64_t *)
+			(uintptr_t)&ht->head.raw);
+
+		nt.raw = ot.raw;
+		if (++nt.val.cnt == h.val.cnt)
+			nt.val.pos = h.val.pos;
+
+	} while (rte_atomic64_cmpset(&ht->tail.raw, ot.raw, nt.raw) == 0);
+}
+
+/**
+ * @internal This function waits till head/tail distance wouldn't
+ * exceed pre-defined max value.
+ */
+static __rte_always_inline void
+__rte_ring_rts_head_wait(const struct rte_ring_rts_headtail *ht,
+	union rte_ring_ht_poscnt *h)
+{
+	uint32_t max;
+
+	max = ht->htd_max;
+	h->raw = ht->head.raw;
+	rte_smp_rmb();
+
+	while (h->val.pos - ht->tail.val.pos > max) {
+		rte_pause();
+		h->raw = ht->head.raw;
+		rte_smp_rmb();
+	}
+}
+
+/**
+ * @internal This function updates the producer head for enqueue.
+ *
+ * @param r
+ *   A pointer to the ring structure
+ * @param is_sp
+ *   Indicates whether multi-producer path is needed or not
+ * @param n
+ *   The number of elements we will want to enqueue, i.e. how far should the
+ *   head be moved
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param old_head
+ *   Returns head value as it was before the move, i.e. where enqueue starts
+ * @param new_head
+ *   Returns the current/new head value i.e. where enqueue finishes
+ * @param free_entries
+ *   Returns the amount of free space in the ring BEFORE head was moved
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline uint32_t
+__rte_ring_rts_move_prod_head(struct rte_ring *r, uint32_t num,
+	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
+	uint32_t *free_entries)
+{
+	uint32_t n;
+	union rte_ring_ht_poscnt nh, oh;
+
+	const uint32_t capacity = r->capacity;
+
+	do {
+		/* Reset n to the initial burst count */
+		n = num;
+
+		/* read prod head (may spin on prod tail) */
+		__rte_ring_rts_head_wait(&r->rts_prod, &oh);
+
+		/* add rmb barrier to avoid load/load reorder in weak
+		 * memory model. It is noop on x86
+		 */
+		rte_smp_rmb();
+
+		/*
+		 *  The subtraction is done between two unsigned 32bits value
+		 * (the result is always modulo 32 bits even if we have
+		 * *old_head > cons_tail). So 'free_entries' is always between 0
+		 * and capacity (which is < size).
+		 */
+		*free_entries = capacity + r->cons.tail - oh.val.pos;
+
+		/* check that we have enough room in ring */
+		if (unlikely(n > *free_entries))
+			n = (behavior == RTE_RING_QUEUE_FIXED) ?
+					0 : *free_entries;
+
+		if (n == 0)
+			break;
+
+		nh.val.pos = oh.val.pos + n;
+		nh.val.cnt = oh.val.cnt + 1;
+
+	} while (rte_atomic64_cmpset(&r->rts_prod.head.raw,
+			oh.raw, nh.raw) == 0);
+
+	*old_head = oh.val.pos;
+	return n;
+}
+
+/**
+ * @internal This function updates the consumer head for dequeue
+ *
+ * @param r
+ *   A pointer to the ring structure
+ * @param is_sc
+ *   Indicates whether multi-consumer path is needed or not
+ * @param n
+ *   The number of elements we will want to enqueue, i.e. how far should the
+ *   head be moved
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param old_head
+ *   Returns head value as it was before the move, i.e. where dequeue starts
+ * @param new_head
+ *   Returns the current/new head value i.e. where dequeue finishes
+ * @param entries
+ *   Returns the number of entries in the ring BEFORE head was moved
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_rts_move_cons_head(struct rte_ring *r, uint32_t num,
+	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
+	uint32_t *entries)
+{
+	uint32_t n;
+	union rte_ring_ht_poscnt nh, oh;
+
+	/* move cons.head atomically */
+	do {
+		/* Restore n as it may change every loop */
+		n = num;
+
+		/* read cons head (may spin on cons tail) */
+		__rte_ring_rts_head_wait(&r->rts_cons, &oh);
+
+
+		/* add rmb barrier to avoid load/load reorder in weak
+		 * memory model. It is noop on x86
+		 */
+		rte_smp_rmb();
+
+		/* The subtraction is done between two unsigned 32bits value
+		 * (the result is always modulo 32 bits even if we have
+		 * cons_head > prod_tail). So 'entries' is always between 0
+		 * and size(ring)-1.
+		 */
+		*entries = r->prod.tail - oh.val.pos;
+
+		/* Set the actual entries for dequeue */
+		if (n > *entries)
+			n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 : *entries;
+
+		if (unlikely(n == 0))
+			break;
+
+		nh.val.pos = oh.val.pos + n;
+		nh.val.cnt = oh.val.cnt + 1;
+
+	} while (rte_atomic64_cmpset(&r->rts_cons.head.raw,
+			oh.raw, nh.raw) == 0);
+
+	*old_head = oh.val.pos;
+	return n;
+}
+
+#endif /* _RTE_RING_RTS_GENERIC_H_ */
-- 
2.17.1


^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v3 0/9] New sync modes for ring
  2020-04-02 22:09  3%   ` [dpdk-dev] [PATCH v2 0/9] " Konstantin Ananyev
  2020-04-02 22:09  1%     ` [dpdk-dev] [PATCH v2 3/9] ring: introduce RTS ring mode Konstantin Ananyev
@ 2020-04-03 17:42  3%     ` Konstantin Ananyev
    2020-04-03 17:42  1%       ` [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode Konstantin Ananyev
  1 sibling, 2 replies; 200+ results
From: Konstantin Ananyev @ 2020-04-03 17:42 UTC (permalink / raw)
  To: dev; +Cc: honnappa.nagarahalli, david.marchand, jielong.zjl, Konstantin Ananyev

V2 - V3
1. Few more compilation fixes (for gcc 4.8.X)
2. Extra update devtools/libabigail.abignore (workaround) 

V1 - v2 changes:
1. Fix compilation issues
2. Add C11 atomics support
3. Updates devtools/libabigail.abignore (workaround)

RFC - V1 changes:
1. remove ABI brekage (at least I hope I did)
2. Add support for ring_elem
3. Rework peek related API a bit
4. Rework test to make it less verbose and unite all test-cases
   in one command
5. Add new test-case for MT peek API

TODO list:
1. Update docs

These days more and more customers use(/try to use) DPDK based apps within
overcommitted systems (multiple acttive threads over same pysical cores):
VM, container deployments, etc.
One quite common problem they hit:
Lock-Holder-Preemption/Lock-Waiter-Preemption with rte_ring.
LHP is quite a common problem for spin-based sync primitives
(spin-locks, etc.) on overcommitted systems.
The situation gets much worse when some sort of
fair-locking technique is used (ticket-lock, etc.).
As now not only lock-owner but also lock-waiters scheduling
order matters a lot (LWP).
These two problems are well-known for kernel within VMs:
http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
The problem with rte_ring is that while head accusion is sort of
un-fair locking, waiting on tail is very similar to ticket lock schema -
tail has to be updated in particular order.
That makes current rte_ring implementation to perform
really pure on some overcommited scenarios.
It is probably not possible to completely resolve LHP problem in
userspace only (without some kernel communication/intervention).
But removing fairness at tail update helps to avoid LWP and
can mitigate the situation significantly.
This patch proposes two new optional ring synchronization modes:
1) Head/Tail Sync (HTS) mode
In that mode enqueue/dequeue operation is fully serialized:
    only one thread at a time is allowed to perform given op.
    As another enhancement provide ability to split enqueue/dequeue
    operation into two phases:
      - enqueue/dequeue start
      - enqueue/dequeue finish
    That allows user to inspect objects in the ring without removing
    them from it (aka MT safe peek).
2) Relaxed Tail Sync (RTS)
The main difference from original MP/MC algorithm is that
tail value is increased not by every thread that finished enqueue/dequeue,
but only by the last one.
That allows threads to avoid spinning on ring tail value,
leaving actual tail value change to the last thread in the update queue.

Note that these new sync modes are optional.
For current rte_ring users nothing should change
(both in terms of API/ABI and performance).
Existing sync modes MP/MC,SP/SC kept untouched, set up in the same
way (via flags and _init_), and MP/MC remains as default one.
The only thing that changed:
Format of prod/cons now could differ depending on mode selected at _init_.
So user has to stick with one sync model through whole ring lifetime.
In other words, user can't create a ring for let say SP mode and then
in the middle of data-path change his mind and start using MP_RTS mode.
For existing modes (SP/MP, SC/MC) format remains the same and
user can still use them interchangeably, though of course it is an
error prone practice.

Test results on IA (see below) show significant improvements
for average enqueue/dequeue op times on overcommitted systems.
For 'classic' DPDK deployments (one thread per core) original MP/MC
algorithm still shows best numbers, though for 64-bit target
RTS numbers are not that far away.
Numbers were produced by new UT test-case: ring_stress_autotest, i.e.:
echo ring_stress_autotest | ./dpdk-test -n 4 --lcores='...'

X86_64 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     8.00       8.15    8.99
2thread@2core(--lcores=6-8)                     19.14      19.61   20.35
4thread@4core(--lcores=6-10)                    29.43      29.79   31.82
8thread@8core(--lcores=6-14)                    110.59     192.81  119.50
16thread@16core(--lcores=6-22)                  461.03     813.12  495.59
32thread/@32core(--lcores='6-22,55-70')         982.90     1972.38 1160.51

2thread@1core(--lcores='6,(10-11)@7'            20140.50   23.58   25.14
4thread@2core(--lcores='6,(10-11)@7,(20-21)@8'  153680.60  76.88   80.05
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  280314.32  294.72  318.79
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 643176.59  1144.02 1175.14
32thread@2core(--lcores='6,(10-25)@7,(30-45)@8' 4264238.80 4627.48 4892.68

8thread@2core(--lcores='6,(10-17)@(7,8))'       321085.98  298.59  307.47
16thread@4core(--lcores='6,(20-35)@(7-10))'     1900705.61 575.35  678.29
32thread@4core(--lcores='6,(20-51)@(7-10))'     5510445.85 2164.36 2714.12

i686 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     7.85       12.13   11.31
2thread@2core(--lcores=6-8)                     17.89      24.52   21.86
8thread@8core(--lcores=6-14)                    32.58      354.20  54.58
32thread/@32core(--lcores='6-22,55-70')         813.77     6072.41 2169.91

2thread@1core(--lcores='6,(10-11)@7'            16095.00   36.06   34.74
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  1140354.54 346.61  361.57
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 1920417.86 1314.90 1416.65

8thread@2core(--lcores='6,(10-17)@(7,8))'       594358.61  332.70  357.74
32thread@4core(--lcores='6,(20-51)@(7-10))'     5319896.86 2836.44 3028.87

Konstantin Ananyev (9):
  test/ring: add contention stress test
  ring: prepare ring to allow new sync schemes
  ring: introduce RTS ring mode
  test/ring: add contention stress test for RTS ring
  ring: introduce HTS ring mode
  test/ring: add contention stress test for HTS ring
  ring: introduce peek style API
  test/ring: add stress test for MT peek API
  ring: add C11 memory model for new sync modes

 app/test/Makefile                      |   5 +
 app/test/meson.build                   |   5 +
 app/test/test_pdump.c                  |   6 +-
 app/test/test_ring_hts_stress.c        |  32 ++
 app/test/test_ring_mpmc_stress.c       |  31 ++
 app/test/test_ring_peek_stress.c       |  43 +++
 app/test/test_ring_rts_stress.c        |  32 ++
 app/test/test_ring_stress.c            |  57 ++++
 app/test/test_ring_stress.h            |  38 +++
 app/test/test_ring_stress_impl.h       | 444 +++++++++++++++++++++++++
 devtools/libabigail.abignore           |   7 +
 lib/librte_pdump/rte_pdump.c           |   2 +-
 lib/librte_port/rte_port_ring.c        |  12 +-
 lib/librte_ring/Makefile               |  11 +-
 lib/librte_ring/meson.build            |  11 +-
 lib/librte_ring/rte_ring.c             | 114 ++++++-
 lib/librte_ring/rte_ring.h             | 244 ++++++++++++--
 lib/librte_ring/rte_ring_c11_mem.h     |  44 +++
 lib/librte_ring/rte_ring_elem.h        | 105 +++++-
 lib/librte_ring/rte_ring_generic.h     |  48 +++
 lib/librte_ring/rte_ring_hts.h         | 214 ++++++++++++
 lib/librte_ring/rte_ring_hts_c11_mem.h | 222 +++++++++++++
 lib/librte_ring/rte_ring_hts_elem.h    | 209 ++++++++++++
 lib/librte_ring/rte_ring_hts_generic.h | 235 +++++++++++++
 lib/librte_ring/rte_ring_peek.h        | 379 +++++++++++++++++++++
 lib/librte_ring/rte_ring_rts.h         | 320 ++++++++++++++++++
 lib/librte_ring/rte_ring_rts_c11_mem.h | 198 +++++++++++
 lib/librte_ring/rte_ring_rts_elem.h    | 209 ++++++++++++
 lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++
 29 files changed, 3431 insertions(+), 56 deletions(-)
 create mode 100644 app/test/test_ring_hts_stress.c
 create mode 100644 app/test/test_ring_mpmc_stress.c
 create mode 100644 app/test/test_ring_peek_stress.c
 create mode 100644 app/test/test_ring_rts_stress.c
 create mode 100644 app/test/test_ring_stress.c
 create mode 100644 app/test/test_ring_stress.h
 create mode 100644 app/test/test_ring_stress_impl.h
 create mode 100644 lib/librte_ring/rte_ring_hts.h
 create mode 100644 lib/librte_ring/rte_ring_hts_c11_mem.h
 create mode 100644 lib/librte_ring/rte_ring_hts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_hts_generic.h
 create mode 100644 lib/librte_ring/rte_ring_peek.h
 create mode 100644 lib/librte_ring/rte_ring_rts.h
 create mode 100644 lib/librte_ring/rte_ring_rts_c11_mem.h
 create mode 100644 lib/librte_ring/rte_ring_rts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_rts_generic.h

-- 
2.17.1


^ permalink raw reply	[relevance 3%]

* [dpdk-dev]  [PATCH v4 00/33] DPDK Trace support
  2020-03-29 14:43  1%   ` [dpdk-dev] [PATCH v3 00/33] " jerinj
  2020-04-01  8:18  3%     ` David Marchand
@ 2020-04-03 15:36  1%     ` jerinj
  1 sibling, 0 replies; 200+ results
From: jerinj @ 2020-04-03 15:36 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson, david.marchand, mattias.ronnblom,
	skori, Jerin Jacob

From: Jerin Jacob <jerinj@marvell.com>

v4:
~~

This patch depends on http://patches.dpdk.org/patch/67758/

Depends-on:series-9191

1) Rebased to master.

2) Adapted to latest EAL directory structure change.

3) Fix possible build issue with out of tree application wherein
it does not define -DALLOW_EXPERIMENTAL_API. Fixed by making
fast path trace functions as NOP as it was getting included
in the inline functions of ethdev,mempool, cryptodev, etc(David)
 
4) Removed DALLOW_EXPERIMENTAL_API definition from individual driver files.
Now it set as global using http://patches.dpdk.org/patch/67758/ patch (David)

5) Added new meson option(-Denable_trace_dp=true)for enabling the datapath trace point (David, Bruce)

6) Changed the authorship and Rewrote the programmer's guide  based on the below feedback(Thomas)
http://patches.dpdk.org/patch/67352/

v3:
~~

1) Fix the following build issues reported by CI
http://mails.dpdk.org/archives/test-report/2020-March/122060.html

a) clang + i686 meson build issue(Fixed in the the patch meson: add libatomic as a global dependency for i686 clang)
b) fixed build issue with FreeBSD with top of tree change.
c) fixed missing experimental API for iavf and ice with meson build in avx512 files.

v2:
~~
Addressed the following review comments from Mattias Rönnblom:

1) Changed 

from:
	typedef uint64_t* rte_trace_t;
to
	typedef uint64_t rte_trace_t;

	Initially thought to make the handle as
	struct rte_trace {
	    uint64_t val;
	}

	but changed to uint64_t for the following reasons
	a) It is opaque to the application and it will fix the compile-time type
	check as well.
	b) The handle has an index that will point to an internal slow-path
	structure so no ABI change required in the future.
	c) RTE_TRACE_POINT_DEFINE need to expose trace object. So it is better
	to keep as uint64_t and avoid one more indirection for no use.

2)
Changed:
from:
	enum rte_trace_mode_e {
to:
	enum rte_trace_mode {

3) removed [out] "found" param from rte_trace_pattern() and
rte_trace_regexp()


4) Changed rte_trace_from_name to rte_trace_by_name

5) rte_trace_is_dp_enabled() return bool now


6) in __rte_trace_point_register() the argument fn change to register_fn

7) removed !! from rte_trace_is_enabled()

8) Remove uninitialized "rc warning" from rte_trace_pattern() and
rte_trace_regexp()

9) fixup bool return type for trace_entry_compare()

10) fixup calloc casting in trace_mkdir()

11) check fclose() return in trace_meta_save() and trace_mem_save()

12) rte_trace_ctf_* macro cleanup

13) added release notes

14) fix build issues reported by CI
http://mails.dpdk.org/archives/test-report/2020-March/121235.html


This patch set contains 
~~~~~~~~~~~~~~~~~~~~~~~~

# The native implementation of common trace format(CTF)[1] based tracer
# Public API to create the trace points.
# Add tracepoints to eal, ethdev, mempool, eventdev and cryptodev 
library for tracing support
# A unit test case
# Performance test case to measure the trace overhead. (See eal/trace:
# add trace performance test cases, patch)
# Programmers guide for Trace support(See doc: add trace library guide,
# patch)

# Tested OS:
~~~~~~~~~~~
- Linux
- FreeBSD

# Tested open source CTF trace viewers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Babeltrace
- Tracecompass

# Trace overhead comparison with LTTng
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

trace overhead data on x86:[2]
# 236 cycles with LTTng(>100ns)
# 18 cycles(7ns) with Native DPDK CTF emitter.(See eal/trace: add trace
# performance test cases patch)

trace overhead data on arm64:
#  312  cycles to  1100 cycles with LTTng based on the class of arm64
#  CPU.
#  11 cycles to 13 cycles with Native DPDK CTF emitter based on the
class of arm64 CPU.

18 cycles(on x86) vs 11 cycles(on arm64) is due to rdtsc() overhead in
x86. It seems  rdtsc takes around 15cycles in x86.


More details:
~~~~~~~~~~~~~

# The Native DPDK CTF trace support does not have any dependency on
third-party library.
The generated output file is compatible with LTTng as both are using
CTF trace format.

The performance gain comes from:
1) exploit dpdk worker thread usage model to avoid atomics and use per
core variables
2) use hugepage,
3) avoid a lot function pointers in fast-path etc
4) avoid unaligned store for arm64 etc

Features:
~~~~~~~~~
- APIs and Features are similar to rte_log dynamic framework
API(expect log prints on stdout vs it dumps on trace file)
- No specific limit on the events. A string-based event like rte_log
for pattern matching
- Dynamic enable/disable support.
- Instructmention overhead is ~1 cycle. i.e cost of adding the code
wth out using trace feature.
- Timestamp support for all the events using DPDK rte_rtdsc
- No dependency on another library. Clean room native implementation of
  CTF.

Functional test case:
a) echo "trace_autotest" | sudo ./build/app/test/dpdk-test  -c 0x3
--trace-level=8

The above command emits the following trace events
<code>
        uint8_t i;

        rte_trace_lib_eal_generic_void();
        rte_trace_lib_eal_generic_u64(0x10000000000000);
        rte_trace_lib_eal_generic_u32(0x10000000);
        rte_trace_lib_eal_generic_u16(0xffee);
        rte_trace_lib_eal_generic_u8(0xc);
        rte_trace_lib_eal_generic_i64(-1234);
        rte_trace_lib_eal_generic_i32(-1234567);
        rte_trace_lib_eal_generic_i16(12);
        rte_trace_lib_eal_generic_i8(-3);
        rte_trace_lib_eal_generic_string("my string");
        rte_trace_lib_eal_generic_function(__func__);

        for (i = 0; i < 128; i++)
                rte_trace_lib_eal_generic_u8(i);
</code>

Install babeltrace package in Linux and point the generated trace file
to babel trace. By default trace file created under
<user>/dpdk-traces/time_stamp/

example:
# babeltrace /root/dpdk-traces/rte-2020-02-15-PM-02-56-51 | more

[13:27:36.138468807] (+?.?????????) lib.eal.generic.void: { cpu_id =
0, name = "dpdk-test" }, { }
[13:27:36.138468851] (+0.000000044) lib.eal.generic.u64: { cpu_id = 0,
name = "dpdk-test" }, { in = 4503599627370496 }
[13:27:36.138468860] (+0.000000009) lib.eal.generic.u32: { cpu_id = 0,
name = "dpdk-test" }, { in = 268435456 }
[13:27:36.138468934] (+0.000000074) lib.eal.generic.u16: { cpu_id = 0,
name = "dpdk-test" }, { in = 65518 }
[13:27:36.138468949] (+0.000000015) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 12 }
[13:27:36.138468956] (+0.000000007) lib.eal.generic.i64: { cpu_id = 0,
name = "dpdk-test" }, { in = -1234 }
[13:27:36.138468963] (+0.000000007) lib.eal.generic.i32: { cpu_id = 0,
name = "dpdk-test" }, { in = -1234567 }
[13:27:36.138469024] (+0.000000061) lib.eal.generic.i16: { cpu_id = 0,
name = "dpdk-test" }, { in = 12 }
[13:27:36.138469044] (+0.000000020) lib.eal.generic.i8: { cpu_id = 0,
name = "dpdk-test" }, { in = -3 }
[13:27:36.138469051] (+0.000000007) lib.eal.generic.string: { cpu_id =
0, name = "dpdk-test" }, { str = "my string" }
[13:27:36.138469203] (+0.000000152) lib.eal.generic.func: { cpu_id =
0, name = "dpdk-test" }, { func = "test_trace_points" }
[13:27:36.138469239] (+0.000000036) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 0 }
[13:27:36.138469246] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 1 }
[13:27:36.138469252] (+0.000000006) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 2 }
[13:27:36.138469262] (+0.000000010) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 3 }
[13:27:36.138469269] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 4 }
[13:27:36.138469276] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 5 }

# There is a  GUI based trace viewer available in Windows, Linux and
# Mac.
It is called as tracecompass.(https://www.eclipse.org/tracecompass/)

The example screenshot and Histogram of above DPDK trace using
Tracecompass.

https://github.com/jerinjacobk/share/blob/master/dpdk_trace.JPG


File walk through:
~~~~~~~~~~~~~~~~~~

lib/librte_eal/common/include/rte_trace.h - Public API for Trace
provider and Trace control
lib/librte_eal/common/eal_common_trace.c - main trace implementation
lib/librte_eal/common/eal_common_trace_ctf.c - CTF metadata spec
implementation
lib/librte_eal/common/eal_common_trace_utils.c - command line utils
and filesystem operations.
lib/librte_eal/common/eal_common_trace_points.c -  trace points for EAL
library
lib/librte_eal/common/include/rte_trace_eal.h - EAL tracepoint public
API.
lib/librte_eal/common/eal_trace.h - Private trace header file.


[1] https://diamon.org/ctf/

[2] The above test is ported to LTTng for finding the LTTng trace
overhead. It available at
https://github.com/jerinjacobk/lttng-overhead
https://github.com/jerinjacobk/lttng-overhead/blob/master/README

Jerin Jacob (22):
  eal: introduce API for getting thread name
  eal/trace: define the public API for trace support
  eal/trace: implement trace register API
  eal/trace: implement trace operation APIs
  eal/trace: add internal trace init and fini interface
  eal/trace: get bootup timestamp for trace
  eal/trace: create CTF TDSL metadata in memory
  eal/trace: implement trace memory allocation
  eal/trace: implement debug dump function
  eal/trace: implement trace save
  eal/trace: implement registration payload
  eal/trace: implement provider payload
  eal/trace: hook internal trace APIs to Linux
  eal/trace: hook internal trace APIs to FreeBSD
  eal/trace: add generic tracepoints
  eal/trace: add alarm tracepoints
  eal/trace: add memory tracepoints
  eal/trace: add memzone tracepoints
  eal/trace: add thread tracepoints
  eal/trace: add interrupt tracepoints
  eal/trace: add trace performance test cases
  doc: add trace library guide

Pavan Nikhilesh (1):
  meson: add libatomic as a global dependency for i686 clang

Sunil Kumar Kori (10):
  eal/trace: handle CTF keyword collision
  eal/trace: add trace level configuration parameter
  eal/trace: add trace dir configuration parameter
  eal/trace: add trace bufsize configuration parameter
  eal/trace: add trace mode configuration parameter
  eal/trace: add unit test cases
  ethdev: add tracepoints
  eventdev: add tracepoints
  cryptodev: add tracepoints
  mempool: add tracepoints

 MAINTAINERS                                   |   8 +
 app/test/Makefile                             |   4 +-
 app/test/meson.build                          |   3 +
 app/test/test_trace.c                         | 618 ++++++++++++++++++
 app/test/test_trace.h                         |  52 ++
 app/test/test_trace_perf.c                    | 179 +++++
 app/test/test_trace_register.c                |  46 ++
 config/common_base                            |   1 +
 config/meson.build                            |   9 +
 doc/api/doxy-api-index.md                     |   3 +-
 doc/guides/linux_gsg/eal_args.include.rst     |  55 ++
 doc/guides/prog_guide/build-sdk-meson.rst     |   5 +
 doc/guides/prog_guide/index.rst               |   1 +
 doc/guides/prog_guide/trace_lib.rst           | 339 ++++++++++
 doc/guides/rel_notes/release_20_05.rst        |   9 +
 drivers/event/octeontx/meson.build            |   5 -
 drivers/event/octeontx2/meson.build           |   5 -
 drivers/event/opdl/meson.build                |   5 -
 examples/cmdline/Makefile                     |   1 +
 examples/cmdline/meson.build                  |   1 +
 examples/distributor/Makefile                 |   1 +
 examples/distributor/meson.build              |   1 +
 examples/ethtool/ethtool-app/Makefile         |   1 +
 examples/eventdev_pipeline/meson.build        |   1 +
 examples/flow_filtering/Makefile              |   1 +
 examples/flow_filtering/meson.build           |   1 +
 examples/helloworld/Makefile                  |   1 +
 examples/helloworld/meson.build               |   1 +
 examples/ioat/Makefile                        |   1 +
 examples/ioat/meson.build                     |   1 +
 examples/ip_fragmentation/Makefile            |   2 +
 examples/ip_fragmentation/meson.build         |   1 +
 examples/ip_reassembly/Makefile               |   1 +
 examples/ip_reassembly/meson.build            |   1 +
 examples/ipv4_multicast/Makefile              |   1 +
 examples/ipv4_multicast/meson.build           |   1 +
 examples/l2fwd-cat/Makefile                   |   1 +
 examples/l2fwd-cat/meson.build                |   1 +
 examples/l2fwd-event/Makefile                 |   1 +
 examples/l2fwd-event/meson.build              |   6 +-
 examples/l2fwd-jobstats/Makefile              |   1 +
 examples/l2fwd-jobstats/meson.build           |   1 +
 examples/l2fwd-keepalive/Makefile             |   1 +
 examples/l2fwd-keepalive/ka-agent/Makefile    |   1 +
 examples/l2fwd-keepalive/meson.build          |   1 +
 examples/l3fwd-acl/Makefile                   |   1 +
 examples/l3fwd-acl/meson.build                |   1 +
 examples/l3fwd/Makefile                       |   1 +
 examples/l3fwd/meson.build                    |   1 +
 examples/link_status_interrupt/Makefile       |   1 +
 examples/link_status_interrupt/meson.build    |   1 +
 .../client_server_mp/mp_client/Makefile       |   1 +
 .../client_server_mp/mp_client/meson.build    |   1 +
 .../client_server_mp/mp_server/meson.build    |   1 +
 examples/multi_process/hotplug_mp/Makefile    |   1 +
 examples/multi_process/hotplug_mp/meson.build |   1 +
 examples/multi_process/simple_mp/Makefile     |   1 +
 examples/multi_process/simple_mp/meson.build  |   1 +
 examples/multi_process/symmetric_mp/Makefile  |   1 +
 .../multi_process/symmetric_mp/meson.build    |   1 +
 examples/ntb/Makefile                         |   1 +
 examples/ntb/meson.build                      |   1 +
 examples/packet_ordering/Makefile             |   1 +
 examples/packet_ordering/meson.build          |   1 +
 .../performance-thread/l3fwd-thread/Makefile  |   1 +
 .../l3fwd-thread/meson.build                  |   1 +
 .../performance-thread/pthread_shim/Makefile  |   1 +
 .../pthread_shim/meson.build                  |   1 +
 examples/ptpclient/Makefile                   |   1 +
 examples/ptpclient/meson.build                |   1 +
 examples/qos_meter/Makefile                   |   1 +
 examples/qos_meter/meson.build                |   1 +
 examples/qos_sched/Makefile                   |   1 +
 examples/qos_sched/meson.build                |   1 +
 examples/server_node_efd/node/Makefile        |   1 +
 examples/server_node_efd/node/meson.build     |   1 +
 examples/server_node_efd/server/Makefile      |   1 +
 examples/server_node_efd/server/meson.build   |   1 +
 examples/service_cores/Makefile               |   1 +
 examples/service_cores/meson.build            |   1 +
 examples/skeleton/Makefile                    |   1 +
 examples/skeleton/meson.build                 |   1 +
 examples/timer/Makefile                       |   1 +
 examples/timer/meson.build                    |   1 +
 examples/vm_power_manager/Makefile            |   1 +
 examples/vm_power_manager/meson.build         |   1 +
 examples/vmdq/Makefile                        |   1 +
 examples/vmdq/meson.build                     |   1 +
 examples/vmdq_dcb/Makefile                    |   1 +
 examples/vmdq_dcb/meson.build                 |   1 +
 lib/librte_cryptodev/Makefile                 |   4 +-
 lib/librte_cryptodev/cryptodev_trace_points.c |  70 ++
 lib/librte_cryptodev/meson.build              |   6 +-
 lib/librte_cryptodev/rte_cryptodev.c          |  18 +
 lib/librte_cryptodev/rte_cryptodev.h          |   6 +
 .../rte_cryptodev_version.map                 |  18 +
 lib/librte_cryptodev/rte_trace_cryptodev.h    | 133 ++++
 lib/librte_cryptodev/rte_trace_cryptodev_fp.h |  34 +
 lib/librte_distributor/meson.build            |   5 -
 lib/librte_eal/common/eal_common_log.c        |   9 +-
 lib/librte_eal/common/eal_common_memzone.c    |   9 +
 lib/librte_eal/common/eal_common_options.c    |  68 +-
 lib/librte_eal/common/eal_common_thread.c     |   3 +-
 lib/librte_eal/common/eal_common_trace.c      | 610 +++++++++++++++++
 lib/librte_eal/common/eal_common_trace_ctf.c  | 488 ++++++++++++++
 .../common/eal_common_trace_points.c          | 115 ++++
 .../common/eal_common_trace_utils.c           | 523 +++++++++++++++
 lib/librte_eal/common/eal_options.h           |   8 +
 lib/librte_eal/common/eal_private.h           |  11 +
 lib/librte_eal/common/eal_trace.h             | 122 ++++
 lib/librte_eal/common/meson.build             |   4 +
 lib/librte_eal/common/rte_malloc.c            |  60 +-
 lib/librte_eal/freebsd/Makefile               |   4 +
 lib/librte_eal/freebsd/eal.c                  |  10 +
 lib/librte_eal/freebsd/eal_alarm.c            |   3 +
 lib/librte_eal/freebsd/eal_interrupts.c       |  54 +-
 lib/librte_eal/freebsd/eal_thread.c           |  21 +-
 lib/librte_eal/include/meson.build            |   4 +
 lib/librte_eal/include/rte_lcore.h            |  17 +
 lib/librte_eal/include/rte_trace.h            | 584 +++++++++++++++++
 lib/librte_eal/include/rte_trace_eal.h        | 247 +++++++
 lib/librte_eal/include/rte_trace_provider.h   | 160 +++++
 lib/librte_eal/include/rte_trace_register.h   |  53 ++
 lib/librte_eal/linux/Makefile                 |   4 +
 lib/librte_eal/linux/eal.c                    |   9 +
 lib/librte_eal/linux/eal_alarm.c              |   4 +
 lib/librte_eal/linux/eal_interrupts.c         |  84 ++-
 lib/librte_eal/linux/eal_thread.c             |  27 +-
 lib/librte_eal/rte_eal_version.map            |  59 ++
 lib/librte_ethdev/Makefile                    |   3 +
 lib/librte_ethdev/ethdev_trace_points.c       |  43 ++
 lib/librte_ethdev/meson.build                 |   5 +-
 lib/librte_ethdev/rte_ethdev.c                |  12 +
 lib/librte_ethdev/rte_ethdev.h                |   5 +
 lib/librte_ethdev/rte_ethdev_version.map      |  10 +
 lib/librte_ethdev/rte_trace_ethdev.h          |  90 +++
 lib/librte_ethdev/rte_trace_ethdev_fp.h       |  40 ++
 lib/librte_eventdev/Makefile                  |   3 +
 lib/librte_eventdev/eventdev_trace_points.c   | 173 +++++
 lib/librte_eventdev/meson.build               |   3 +
 .../rte_event_crypto_adapter.c                |  10 +
 .../rte_event_eth_rx_adapter.c                |  11 +
 .../rte_event_eth_tx_adapter.c                |  13 +-
 .../rte_event_eth_tx_adapter.h                |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c |   8 +-
 lib/librte_eventdev/rte_event_timer_adapter.h |   8 +
 lib/librte_eventdev/rte_eventdev.c            |   9 +
 lib/librte_eventdev/rte_eventdev.h            |   5 +-
 lib/librte_eventdev/rte_eventdev_version.map  |  42 ++
 lib/librte_eventdev/rte_trace_eventdev.h      | 278 ++++++++
 lib/librte_eventdev/rte_trace_eventdev_fp.h   |  75 +++
 lib/librte_mempool/Makefile                   |   3 +
 lib/librte_mempool/mempool_trace_points.c     | 108 +++
 lib/librte_mempool/meson.build                |   5 +-
 lib/librte_mempool/rte_mempool.c              |  16 +
 lib/librte_mempool/rte_mempool.h              |  13 +
 lib/librte_mempool/rte_mempool_ops.c          |   7 +
 lib/librte_mempool/rte_mempool_version.map    |  26 +
 lib/librte_mempool/rte_trace_mempool.h        | 148 +++++
 lib/librte_mempool/rte_trace_mempool_fp.h     | 102 +++
 lib/librte_rcu/meson.build                    |   5 -
 meson_options.txt                             |   2 +
 162 files changed, 6266 insertions(+), 110 deletions(-)
 create mode 100644 app/test/test_trace.c
 create mode 100644 app/test/test_trace.h
 create mode 100644 app/test/test_trace_perf.c
 create mode 100644 app/test/test_trace_register.c
 create mode 100644 doc/guides/prog_guide/trace_lib.rst
 create mode 100644 lib/librte_cryptodev/cryptodev_trace_points.c
 create mode 100644 lib/librte_cryptodev/rte_trace_cryptodev.h
 create mode 100644 lib/librte_cryptodev/rte_trace_cryptodev_fp.h
 create mode 100644 lib/librte_eal/common/eal_common_trace.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_ctf.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_points.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_utils.c
 create mode 100644 lib/librte_eal/common/eal_trace.h
 create mode 100644 lib/librte_eal/include/rte_trace.h
 create mode 100644 lib/librte_eal/include/rte_trace_eal.h
 create mode 100644 lib/librte_eal/include/rte_trace_provider.h
 create mode 100644 lib/librte_eal/include/rte_trace_register.h
 create mode 100644 lib/librte_ethdev/ethdev_trace_points.c
 create mode 100644 lib/librte_ethdev/rte_trace_ethdev.h
 create mode 100644 lib/librte_ethdev/rte_trace_ethdev_fp.h
 create mode 100644 lib/librte_eventdev/eventdev_trace_points.c
 create mode 100644 lib/librte_eventdev/rte_trace_eventdev.h
 create mode 100644 lib/librte_eventdev/rte_trace_eventdev_fp.h
 create mode 100644 lib/librte_mempool/mempool_trace_points.c
 create mode 100644 lib/librte_mempool/rte_trace_mempool.h
 create mode 100644 lib/librte_mempool/rte_trace_mempool_fp.h

-- 
2.25.1


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [PATCH v3 07/12] service: remove rte prefix from static functions
  @ 2020-04-03 11:57  3%     ` Van Haaren, Harry
  2020-04-08 10:14  0%       ` Phil Yang
  0 siblings, 1 reply; 200+ results
From: Van Haaren, Harry @ 2020-04-03 11:57 UTC (permalink / raw)
  To: Phil Yang, thomas, Ananyev, Konstantin, stephen, maxime.coquelin, dev
  Cc: david.marchand, jerinj, hemant.agrawal, Honnappa.Nagarahalli,
	gavin.hu, ruifeng.wang, joyce.kong, nd, stable

> From: Phil Yang <phil.yang@arm.com>
> Sent: Tuesday, March 17, 2020 1:18 AM
> To: thomas@monjalon.net; Van Haaren, Harry <harry.van.haaren@intel.com>;
> Ananyev, Konstantin <konstantin.ananyev@intel.com>;
> stephen@networkplumber.org; maxime.coquelin@redhat.com; dev@dpdk.org
> Cc: david.marchand@redhat.com; jerinj@marvell.com; hemant.agrawal@nxp.com;
> Honnappa.Nagarahalli@arm.com; gavin.hu@arm.com; ruifeng.wang@arm.com;
> joyce.kong@arm.com; nd@arm.com; stable@dpdk.org
> Subject: [PATCH v3 07/12] service: remove rte prefix from static functions
> 
> Fixes: 3cf5eb1546ed ("service: fix and refactor atomic service accesses")
> Fixes: 21698354c832 ("service: introduce service cores concept")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Phil Yang <phil.yang@arm.com>
> Reviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>


This patchset needs a rebase since the EAL file movement got merged,
however I'll review here so we can include some Acks etc and make
progress.

Is this really a "Fix"? The internal function names were not exported
in the .map file, so are not part of public ABI. This is an internal
naming improvement (thanks for doing cleanup), but I don't think the
Fixes: tags make sense?

Also I'm not sure if we want to port this patch back to stable? Changing (internal) function names seems like unnecessary churn, and hence risk to a stable release, without any benefit?

---

<snip patch diff>

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [RFC] ethdev: use special speed for virtual Ethernetdevices
  2020-04-03  9:45  3%           ` Morten Brørup
@ 2020-04-03 11:01  0%             ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-04-03 11:01 UTC (permalink / raw)
  To: Ivan Dyukov, Morten Brørup
  Cc: Ferruh Yigit, Andrew Rybchenko, dev, Matan Azrad,
	Benoit Ganne (bganne),
	maxime.coquelin, Vladimir Kuramshin, amorenoz, zhihong.wang,
	xiaolong.ye, Stephen Hemminger

03/04/2020 11:45, Morten Brørup:
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ivan Dyukov
> > Sent: Friday, April 3, 2020 10:06 AM
> > 
> > 02.04.2020 23:58, Thomas Monjalon пишет:
> > > 02/04/2020 22:41, Ivan Dyukov:
> > >> 02.04.2020 16:50, Morten Brørup пишет:
> > >>>>>> Yes, if speed is unknown, it should be reported as 0.
> > >>> Could the DPDK vNIC PMDs be updated accordingly? At least the
> > virtio driver...
> > >> Current version of dpdk code on master always returns 10G speed for
> > >> virtio device and many application rely on it. e.g. pktgen. If we'll
> > >> change it, we break the apps.
> > > I am OK with breaking such strange assumption.
> > > I can understand the need for specifying the underlying hardware
> > speed
> > > through virtio driver. But hardcoded 10G... no!
> > >
> > >
> > >
> > OK. I'll redefine it to 0xffffffff, like in kernel virtio.
> > 
> 
> Thomas, you were opposed to using 1 as the special value for "unknown", as it is likely interpreted as 1 Mbps instead, and I agree with your reasoning on that.
> 
> Since using an extremely large value is as close to infinity we can get, Ivan's suggested value makes sense to me instead:
> 
> +#define ETH_SPEED_NUM_UNKNOWN      0xffffffff /**< Unknown */
> 
> In theory, it also addresses Stephen's concern about breaking the ABI for existing applications that look at speed. They will get a non-zero speed, which is not a randomly chosen fake 10G speed; so I consider it an improvement.
> Although in reality, such applications may still break if they are unable to handle the extreme speed of 4.3 Pbps.
> 
> I considered "Unlimited" instead of "Unknown", but Unlimited is not really correct, so I settled with Unknown.

Yes it makes sense.
The only drawback is that the information "speed is accurate" will
be checked against two constants:
	ETH_SPEED_NUM_NONE or ETH_SPEED_NUM_UNKNOWN
It can be mitigated with a function though.



^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ethdev: use special speed for virtual Ethernetdevices
  @ 2020-04-03  9:45  3%           ` Morten Brørup
  2020-04-03 11:01  0%             ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Morten Brørup @ 2020-04-03  9:45 UTC (permalink / raw)
  To: Ivan Dyukov, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko
  Cc: dev, Matan Azrad, Benoit Ganne (bganne),
	maxime.coquelin, Vladimir Kuramshin, amorenoz, zhihong.wang,
	xiaolong.ye, Stephen Hemminger

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ivan Dyukov
> Sent: Friday, April 3, 2020 10:06 AM
> 
> 02.04.2020 23:58, Thomas Monjalon пишет:
> > 02/04/2020 22:41, Ivan Dyukov:
> >> 02.04.2020 16:50, Morten Brørup пишет:
> >>>>>> Yes, if speed is unknown, it should be reported as 0.
> >>> Could the DPDK vNIC PMDs be updated accordingly? At least the
> virtio driver...
> >> Current version of dpdk code on master always returns 10G speed for
> >> virtio device and many application rely on it. e.g. pktgen. If we'll
> >> change it, we break the apps.
> > I am OK with breaking such strange assumption.
> > I can understand the need for specifying the underlying hardware
> speed
> > through virtio driver. But hardcoded 10G... no!
> >
> >
> >
> OK. I'll redefine it to 0xffffffff, like in kernel virtio.
> 

Thomas, you were opposed to using 1 as the special value for "unknown", as it is likely interpreted as 1 Mbps instead, and I agree with your reasoning on that.

Since using an extremely large value is as close to infinity we can get, Ivan's suggested value makes sense to me instead:

+#define ETH_SPEED_NUM_UNKNOWN      0xffffffff /**< Unknown */

In theory, it also addresses Stephen's concern about breaking the ABI for existing applications that look at speed. They will get a non-zero speed, which is not a randomly chosen fake 10G speed; so I consider it an improvement.
Although in reality, such applications may still break if they are unable to handle the extreme speed of 4.3 Pbps.

I considered "Unlimited" instead of "Unknown", but Unlimited is not really correct, so I settled with Unknown.


^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v2 3/9] ring: introduce RTS ring mode
  2020-04-02 22:09  3%   ` [dpdk-dev] [PATCH v2 0/9] " Konstantin Ananyev
@ 2020-04-02 22:09  1%     ` Konstantin Ananyev
  2020-04-03 17:42  3%     ` [dpdk-dev] [PATCH v3 0/9] New sync modes for ring Konstantin Ananyev
  1 sibling, 0 replies; 200+ results
From: Konstantin Ananyev @ 2020-04-02 22:09 UTC (permalink / raw)
  To: dev; +Cc: honnappa.nagarahalli, david.marchand, jielong.zjl, Konstantin Ananyev

Introduce relaxed tail sync (RTS) mode for MT ring synchronization.
Aim to reduce stall times in case when ring is used on
overcommited cpus (multiple active threads on the same cpu).
The main difference from original MP/MC algorithm is that
tail value is increased not by every thread that finished enqueue/dequeue,
but only by the last one.
That allows threads to avoid spinning on ring tail value,
leaving actual tail value change to the last thread in the update queue.

check-abi.sh reports what I believe is a false-positive about
ring cons/prod changes. As a workaround, devtools/libabigail.abignore is
updated to suppress *struct ring* related errors.

Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
---
 devtools/libabigail.abignore           |   4 +
 lib/librte_ring/Makefile               |   5 +-
 lib/librte_ring/meson.build            |   5 +-
 lib/librte_ring/rte_ring.c             | 100 +++++++-
 lib/librte_ring/rte_ring.h             | 110 ++++++++-
 lib/librte_ring/rte_ring_elem.h        |  86 ++++++-
 lib/librte_ring/rte_ring_rts.h         | 316 +++++++++++++++++++++++++
 lib/librte_ring/rte_ring_rts_elem.h    | 205 ++++++++++++++++
 lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++++++
 9 files changed, 1012 insertions(+), 29 deletions(-)
 create mode 100644 lib/librte_ring/rte_ring_rts.h
 create mode 100644 lib/librte_ring/rte_ring_rts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_rts_generic.h

diff --git a/devtools/libabigail.abignore b/devtools/libabigail.abignore
index a59df8f13..ece014111 100644
--- a/devtools/libabigail.abignore
+++ b/devtools/libabigail.abignore
@@ -11,3 +11,7 @@
         type_kind = enum
         name = rte_crypto_asym_xform_type
         changed_enumerators = RTE_CRYPTO_ASYM_XFORM_TYPE_LIST_END
+; Ignore updates of ring prod/cons
+[suppress_type]
+        type_kind = struct
+        name = rte_ring
diff --git a/lib/librte_ring/Makefile b/lib/librte_ring/Makefile
index 917c560ad..8f5c284cc 100644
--- a/lib/librte_ring/Makefile
+++ b/lib/librte_ring/Makefile
@@ -18,6 +18,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_RING) := rte_ring.c
 SYMLINK-$(CONFIG_RTE_LIBRTE_RING)-include := rte_ring.h \
 					rte_ring_elem.h \
 					rte_ring_generic.h \
-					rte_ring_c11_mem.h
+					rte_ring_c11_mem.h \
+					rte_ring_rts.h \
+					rte_ring_rts_elem.h \
+					rte_ring_rts_generic.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ring/meson.build b/lib/librte_ring/meson.build
index f2f3ccc88..612936afb 100644
--- a/lib/librte_ring/meson.build
+++ b/lib/librte_ring/meson.build
@@ -5,7 +5,10 @@ sources = files('rte_ring.c')
 headers = files('rte_ring.h',
 		'rte_ring_elem.h',
 		'rte_ring_c11_mem.h',
-		'rte_ring_generic.h')
+		'rte_ring_generic.h',
+		'rte_ring_rts.h',
+		'rte_ring_rts_elem.h',
+		'rte_ring_rts_generic.h')
 
 # rte_ring_create_elem and rte_ring_get_memsize_elem are experimental
 allow_experimental_apis = true
diff --git a/lib/librte_ring/rte_ring.c b/lib/librte_ring/rte_ring.c
index fa5733907..222eec0fb 100644
--- a/lib/librte_ring/rte_ring.c
+++ b/lib/librte_ring/rte_ring.c
@@ -45,6 +45,9 @@ EAL_REGISTER_TAILQ(rte_ring_tailq)
 /* true if x is a power of 2 */
 #define POWEROF2(x) ((((x)-1) & (x)) == 0)
 
+/* by default set head/tail distance as 1/8 of ring capacity */
+#define HTD_MAX_DEF	8
+
 /* return the size of memory occupied by a ring */
 ssize_t
 rte_ring_get_memsize_elem(unsigned int esize, unsigned int count)
@@ -79,11 +82,84 @@ rte_ring_get_memsize(unsigned int count)
 	return rte_ring_get_memsize_elem(sizeof(void *), count);
 }
 
+/*
+ * internal helper function to reset prod/cons head-tail values.
+ */
+static void
+reset_headtail(void *p)
+{
+	struct rte_ring_headtail *ht;
+	struct rte_ring_rts_headtail *ht_rts;
+
+	ht = p;
+	ht_rts = p;
+
+	switch (ht->sync_type) {
+	case RTE_RING_SYNC_MT:
+	case RTE_RING_SYNC_ST:
+		ht->head = 0;
+		ht->tail = 0;
+		break;
+	case RTE_RING_SYNC_MT_RTS:
+		ht_rts->head.raw = 0;
+		ht_rts->tail.raw = 0;
+		break;
+	default:
+		/* unknown sync mode */
+		RTE_ASSERT(0);
+	}
+}
+
 void
 rte_ring_reset(struct rte_ring *r)
 {
-	r->prod.head = r->cons.head = 0;
-	r->prod.tail = r->cons.tail = 0;
+	reset_headtail(&r->prod);
+	reset_headtail(&r->cons);
+}
+
+/*
+ * helper function, calculates sync_type values for prod and cons
+ * based on input flags. Returns zero at success or negative
+ * errno value otherwise.
+ */
+static int
+get_sync_type(uint32_t flags, enum rte_ring_sync_type *prod_st,
+	enum rte_ring_sync_type *cons_st)
+{
+	static const uint32_t prod_st_flags =
+		(RING_F_SP_ENQ | RING_F_MP_RTS_ENQ);
+	static const uint32_t cons_st_flags =
+		(RING_F_SC_DEQ | RING_F_MC_RTS_DEQ);
+
+	switch (flags & prod_st_flags) {
+	case 0:
+		*prod_st = RTE_RING_SYNC_MT;
+		break;
+	case RING_F_SP_ENQ:
+		*prod_st = RTE_RING_SYNC_ST;
+		break;
+	case RING_F_MP_RTS_ENQ:
+		*prod_st = RTE_RING_SYNC_MT_RTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (flags & cons_st_flags) {
+	case 0:
+		*cons_st = RTE_RING_SYNC_MT;
+		break;
+	case RING_F_SC_DEQ:
+		*cons_st = RTE_RING_SYNC_ST;
+		break;
+	case RING_F_MC_RTS_DEQ:
+		*cons_st = RTE_RING_SYNC_MT_RTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 int
@@ -100,16 +176,20 @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
 	RTE_BUILD_BUG_ON((offsetof(struct rte_ring, prod) &
 			  RTE_CACHE_LINE_MASK) != 0);
 
+	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, sync_type) !=
+		offsetof(struct rte_ring_rts_headtail, sync_type));
+	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, tail) !=
+		offsetof(struct rte_ring_rts_headtail, tail.val.pos));
+
 	/* init the ring structure */
 	memset(r, 0, sizeof(*r));
 	ret = strlcpy(r->name, name, sizeof(r->name));
 	if (ret < 0 || ret >= (int)sizeof(r->name))
 		return -ENAMETOOLONG;
 	r->flags = flags;
-	r->prod.sync_type = (flags & RING_F_SP_ENQ) ?
-		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
-	r->cons.sync_type = (flags & RING_F_SC_DEQ) ?
-		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
+	ret = get_sync_type(flags, &r->prod.sync_type, &r->cons.sync_type);
+	if (ret != 0)
+		return ret;
 
 	if (flags & RING_F_EXACT_SZ) {
 		r->size = rte_align32pow2(count + 1);
@@ -126,8 +206,12 @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
 		r->mask = count - 1;
 		r->capacity = r->mask;
 	}
-	r->prod.head = r->cons.head = 0;
-	r->prod.tail = r->cons.tail = 0;
+
+	/* set default values for head-tail distance */
+	if (flags & RING_F_MP_RTS_ENQ)
+		rte_ring_set_prod_htd_max(r, r->capacity / HTD_MAX_DEF);
+	if (flags & RING_F_MC_RTS_DEQ)
+		rte_ring_set_cons_htd_max(r, r->capacity / HTD_MAX_DEF);
 
 	return 0;
 }
diff --git a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h
index d4775a063..f6f084d79 100644
--- a/lib/librte_ring/rte_ring.h
+++ b/lib/librte_ring/rte_ring.h
@@ -48,6 +48,7 @@ extern "C" {
 #include <rte_branch_prediction.h>
 #include <rte_memzone.h>
 #include <rte_pause.h>
+#include <rte_debug.h>
 
 #define RTE_TAILQ_RING_NAME "RTE_RING"
 
@@ -65,10 +66,13 @@ enum rte_ring_queue_behavior {
 enum rte_ring_sync_type {
 	RTE_RING_SYNC_MT,     /**< multi-thread safe (default mode) */
 	RTE_RING_SYNC_ST,     /**< single thread only */
+#ifdef ALLOW_EXPERIMENTAL_API
+	RTE_RING_SYNC_MT_RTS, /**< multi-thread relaxed tail sync */
+#endif
 };
 
 /**
- * structure to hold a pair of head/tail values and other metadata.
+ * structures to hold a pair of head/tail values and other metadata.
  * Depending on sync_type format of that structure might be different,
  * but offset for *sync_type* and *tail* values should remain the same.
  */
@@ -84,6 +88,21 @@ struct rte_ring_headtail {
 	};
 };
 
+union rte_ring_ht_poscnt {
+	uint64_t raw;
+	struct {
+		uint32_t cnt; /**< head/tail reference counter */
+		uint32_t pos; /**< head/tail position */
+	} val;
+};
+
+struct rte_ring_rts_headtail {
+	volatile union rte_ring_ht_poscnt tail;
+	enum rte_ring_sync_type sync_type;  /**< sync type of prod/cons */
+	uint32_t htd_max;   /**< max allowed distance between head/tail */
+	volatile union rte_ring_ht_poscnt head;
+};
+
 /**
  * An RTE ring structure.
  *
@@ -111,11 +130,21 @@ struct rte_ring {
 	char pad0 __rte_cache_aligned; /**< empty cache line */
 
 	/** Ring producer status. */
-	struct rte_ring_headtail prod __rte_cache_aligned;
+	RTE_STD_C11
+	union {
+		struct rte_ring_headtail prod;
+		struct rte_ring_rts_headtail rts_prod;
+	}  __rte_cache_aligned;
+
 	char pad1 __rte_cache_aligned; /**< empty cache line */
 
 	/** Ring consumer status. */
-	struct rte_ring_headtail cons __rte_cache_aligned;
+	RTE_STD_C11
+	union {
+		struct rte_ring_headtail cons;
+		struct rte_ring_rts_headtail rts_cons;
+	}  __rte_cache_aligned;
+
 	char pad2 __rte_cache_aligned; /**< empty cache line */
 };
 
@@ -132,6 +161,9 @@ struct rte_ring {
 #define RING_F_EXACT_SZ 0x0004
 #define RTE_RING_SZ_MASK  (0x7fffffffU) /**< Ring size mask */
 
+#define RING_F_MP_RTS_ENQ 0x0008 /**< The default enqueue is "MP RTS". */
+#define RING_F_MC_RTS_DEQ 0x0010 /**< The default dequeue is "MC RTS". */
+
 #define __IS_SP RTE_RING_SYNC_ST
 #define __IS_MP RTE_RING_SYNC_MT
 #define __IS_SC RTE_RING_SYNC_ST
@@ -461,6 +493,10 @@ rte_ring_sp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
 			RTE_RING_SYNC_ST, free_space);
 }
 
+#ifdef ALLOW_EXPERIMENTAL_API
+#include <rte_ring_rts.h>
+#endif
+
 /**
  * Enqueue several objects on a ring.
  *
@@ -484,8 +520,21 @@ static __rte_always_inline unsigned int
 rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
 		      unsigned int n, unsigned int *free_space)
 {
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-			r->prod.sync_type, free_space);
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_bulk(r, obj_table, n, free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_bulk(r, obj_table, n, free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_bulk(r, obj_table, n,
+			free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 /**
@@ -619,8 +668,20 @@ static __rte_always_inline unsigned int
 rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,
 		unsigned int *available)
 {
-	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-				r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_bulk(r, obj_table, n, available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_bulk(r, obj_table, n, available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_bulk(r, obj_table, n, available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 /**
@@ -940,8 +1001,21 @@ static __rte_always_inline unsigned
 rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table,
 		      unsigned int n, unsigned int *free_space)
 {
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_VARIABLE,
-			r->prod.sync_type, free_space);
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_burst(r, obj_table, n, free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_burst(r, obj_table, n, free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_burst(r, obj_table, n,
+			free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 /**
@@ -1020,9 +1094,21 @@ static __rte_always_inline unsigned
 rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table,
 		unsigned int n, unsigned int *available)
 {
-	return __rte_ring_do_dequeue(r, obj_table, n,
-				RTE_RING_QUEUE_VARIABLE,
-				r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_burst(r, obj_table, n, available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_burst(r, obj_table, n, available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_burst(r, obj_table, n,
+			available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	return 0;
 }
 
 #ifdef __cplusplus
diff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h
index 28f9836e6..5de0850dc 100644
--- a/lib/librte_ring/rte_ring_elem.h
+++ b/lib/librte_ring/rte_ring_elem.h
@@ -542,6 +542,8 @@ rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
 			RTE_RING_QUEUE_FIXED, __IS_SP, free_space);
 }
 
+#include <rte_ring_rts_elem.h>
+
 /**
  * Enqueue several objects on a ring.
  *
@@ -571,6 +573,26 @@ rte_ring_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
 {
 	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
 			RTE_RING_QUEUE_FIXED, r->prod.sync_type, free_space);
+
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_bulk_elem(r, obj_table, esize, n,
+			free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_bulk_elem(r, obj_table, esize, n,
+			free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_bulk_elem(r, obj_table, esize, n,
+			free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (free_space != NULL)
+		*free_space = 0;
+	return 0;
 }
 
 /**
@@ -733,8 +755,25 @@ static __rte_always_inline unsigned int
 rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
 		unsigned int esize, unsigned int n, unsigned int *available)
 {
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_FIXED, r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_bulk_elem(r, obj_table, esize, n,
+			available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_bulk_elem(r, obj_table, esize, n,
+			available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_bulk_elem(r, obj_table, esize,
+			n, available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (available != NULL)
+		*available = 0;
+	return 0;
 }
 
 /**
@@ -901,8 +940,25 @@ static __rte_always_inline unsigned
 rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
 		unsigned int esize, unsigned int n, unsigned int *free_space)
 {
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_VARIABLE, r->prod.sync_type, free_space);
+	switch (r->prod.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mp_enqueue_burst_elem(r, obj_table, esize, n,
+			free_space);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sp_enqueue_burst_elem(r, obj_table, esize, n,
+			free_space);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mp_rts_enqueue_burst_elem(r, obj_table, esize,
+			n, free_space);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (free_space != NULL)
+		*free_space = 0;
+	return 0;
 }
 
 /**
@@ -993,9 +1049,25 @@ static __rte_always_inline unsigned int
 rte_ring_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
 		unsigned int esize, unsigned int n, unsigned int *available)
 {
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-				RTE_RING_QUEUE_VARIABLE,
-				r->cons.sync_type, available);
+	switch (r->cons.sync_type) {
+	case RTE_RING_SYNC_MT:
+		return rte_ring_mc_dequeue_burst_elem(r, obj_table, esize, n,
+			available);
+	case RTE_RING_SYNC_ST:
+		return rte_ring_sc_dequeue_burst_elem(r, obj_table, esize, n,
+			available);
+#ifdef ALLOW_EXPERIMENTAL_API
+	case RTE_RING_SYNC_MT_RTS:
+		return rte_ring_mc_rts_dequeue_burst_elem(r, obj_table, esize,
+			n, available);
+#endif
+	}
+
+	/* valid ring should never reach this point */
+	RTE_ASSERT(0);
+	if (available != NULL)
+		*available = 0;
+	return 0;
 }
 
 #ifdef __cplusplus
diff --git a/lib/librte_ring/rte_ring_rts.h b/lib/librte_ring/rte_ring_rts.h
new file mode 100644
index 000000000..18404fe48
--- /dev/null
+++ b/lib/librte_ring/rte_ring_rts.h
@@ -0,0 +1,316 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#ifndef _RTE_RING_RTS_H_
+#define _RTE_RING_RTS_H_
+
+/**
+ * @file rte_ring_rts.h
+ * @b EXPERIMENTAL: this API may change without prior notice
+ * It is not recommended to include this file directly.
+ * Please include <rte_ring.h> instead.
+ *
+ * Contains functions for Relaxed Tail Sync (RTS) ring mode.
+ * The main idea remains the same as for our original MP/MC synchronization
+ * mechanism.
+ * The main difference is that tail value is increased not
+ * by every thread that finished enqueue/dequeue,
+ * but only by the last one doing enqueue/dequeue.
+ * That allows threads to skip spinning on tail value,
+ * leaving actual tail value change to last thread in the update queue.
+ * RTS requires 2 64-bit CAS for each enqueue(/dequeue) operation:
+ * one for head update, second for tail update.
+ * As a gain it allows thread to avoid spinning/waiting on tail value.
+ * In comparision original MP/MC algorithm requires one 32-bit CAS
+ * for head update and waiting/spinning on tail value.
+ *
+ * Brief outline:
+ *  - introduce refcnt for both head and tail.
+ *  - increment head.refcnt for each head.value update
+ *  - write head:value and head:refcnt atomically (64-bit CAS)
+ *  - move tail.value ahead only when tail.refcnt + 1 == head.refcnt
+ *  - increment tail.refcnt when each enqueue/dequeue op finishes
+ *    (no matter is tail:value going to change or not)
+ *  - write tail.value and tail.recnt atomically (64-bit CAS)
+ *
+ * To avoid producer/consumer starvation:
+ *  - limit max allowed distance between head and tail value (HTD_MAX).
+ *    I.E. thread is allowed to proceed with changing head.value,
+ *    only when:  head.value - tail.value <= HTD_MAX
+ * HTD_MAX is an optional parameter.
+ * With HTD_MAX == 0 we'll have fully serialized ring -
+ * i.e. only one thread at a time will be able to enqueue/dequeue
+ * to/from the ring.
+ * With HTD_MAX >= ring.capacity - no limitation.
+ * By default HTD_MAX == ring.capacity / 8.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ring_rts_generic.h>
+
+/**
+ * @internal Enqueue several objects on the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param free_space
+ *   returns the amount of space after the enqueue operation has finished
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_enqueue(struct rte_ring *r, void * const *obj_table,
+		uint32_t n, enum rte_ring_queue_behavior behavior,
+		uint32_t *free_space)
+{
+	uint32_t free, head;
+
+	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
+
+	if (n != 0) {
+		ENQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
+		__rte_ring_rts_update_tail(&r->rts_prod);
+	}
+
+	if (free_space != NULL)
+		*free_space = free - n;
+	return n;
+}
+
+/**
+ * @internal Dequeue several objects from the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to pull from the ring.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param available
+ *   returns the number of remaining ring entries after the dequeue has finished
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_dequeue(struct rte_ring *r, void **obj_table,
+		uint32_t n, enum rte_ring_queue_behavior behavior,
+		uint32_t *available)
+{
+	uint32_t entries, head;
+
+	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
+
+	if (n != 0) {
+		DEQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
+		__rte_ring_rts_update_tail(&r->rts_cons);
+	}
+
+	if (available != NULL)
+		*available = entries - n;
+	return n;
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mp_rts_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS ring (multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mc_rts_dequeue_bulk(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			available);
+}
+
+/**
+ * Return producer max Head-Tail-Distance (HTD).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   Producer HTD value, if producer is set in appropriate sync mode,
+ *   or UINT32_MAX otherwise.
+ */
+__rte_experimental
+static inline uint32_t
+rte_ring_get_prod_htd_max(const struct rte_ring *r)
+{
+	if (r->prod.sync_type == RTE_RING_SYNC_MT_RTS)
+		return r->rts_prod.htd_max;
+	return UINT32_MAX;
+}
+
+/**
+ * Set producer max Head-Tail-Distance (HTD).
+ * Note that producer has to use appropriate sync mode (RTS).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param v
+ *   new HTD value to setup.
+ * @return
+ *   Zero on success, or negative error code otherwise.
+ */
+__rte_experimental
+static inline int
+rte_ring_set_prod_htd_max(struct rte_ring *r, uint32_t v)
+{
+	if (r->prod.sync_type != RTE_RING_SYNC_MT_RTS)
+		return -ENOTSUP;
+
+	r->rts_prod.htd_max = v;
+	return 0;
+}
+
+/**
+ * Return consumer max Head-Tail-Distance (HTD).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   Consumer HTD value, if consumer is set in appropriate sync mode,
+ *   or UINT32_MAX otherwise.
+ */
+__rte_experimental
+static inline uint32_t
+rte_ring_get_cons_htd_max(const struct rte_ring *r)
+{
+	if (r->cons.sync_type == RTE_RING_SYNC_MT_RTS)
+		return r->rts_cons.htd_max;
+	return UINT32_MAX;
+}
+
+/**
+ * Set consumer max Head-Tail-Distance (HTD).
+ * Note that consumer has to use appropriate sync mode (RTS).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param v
+ *   new HTD value to setup.
+ * @return
+ *   Zero on success, or negative error code otherwise.
+ */
+__rte_experimental
+static inline int
+rte_ring_set_cons_htd_max(struct rte_ring *r, uint32_t v)
+{
+	if (r->cons.sync_type != RTE_RING_SYNC_MT_RTS)
+		return -ENOTSUP;
+
+	r->rts_cons.htd_max = v;
+	return 0;
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mp_rts_enqueue_burst(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS  ring (multi-consumers safe).
+ * When the requested objects are more than the available objects,
+ * only dequeue the actual number of objects.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mc_rts_dequeue_burst(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, available);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_RING_RTS_H_ */
diff --git a/lib/librte_ring/rte_ring_rts_elem.h b/lib/librte_ring/rte_ring_rts_elem.h
new file mode 100644
index 000000000..71a331b23
--- /dev/null
+++ b/lib/librte_ring/rte_ring_rts_elem.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#ifndef _RTE_RING_RTS_ELEM_H_
+#define _RTE_RING_RTS_ELEM_H_
+
+/**
+ * @file rte_ring_rts_elem.h
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * It is not recommended to include this file directly.
+ * Please include <rte_ring_elem.h> instead.
+ * Contains *ring_elem* functions for Relaxed Tail Sync (RTS) ring mode.
+ * for more details please refer to <rte_ring_rts.h>.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ring_rts_generic.h>
+
+/**
+ * @internal Enqueue several objects on the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param free_space
+ *   returns the amount of space after the enqueue operation has finished
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_enqueue_elem(struct rte_ring *r, void * const *obj_table,
+	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
+	uint32_t *free_space)
+{
+	uint32_t free, head;
+
+	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
+
+	if (n != 0) {
+		__rte_ring_enqueue_elems(r, head, obj_table, esize, n);
+		__rte_ring_rts_update_tail(&r->rts_prod);
+	}
+
+	if (free_space != NULL)
+		*free_space = free - n;
+	return n;
+}
+
+/**
+ * @internal Dequeue several objects from the RTS ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to pull from the ring.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param available
+ *   returns the number of remaining ring entries after the dequeue has finished
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_rts_dequeue_elem(struct rte_ring *r, void **obj_table,
+	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
+	uint32_t *available)
+{
+	uint32_t entries, head;
+
+	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
+
+	if (n != 0) {
+		__rte_ring_dequeue_elems(r, head, obj_table, esize, n);
+		__rte_ring_rts_update_tail(&r->rts_cons);
+	}
+
+	if (available != NULL)
+		*available = entries - n;
+	return n;
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mp_rts_enqueue_bulk_elem(struct rte_ring *r, void * const *obj_table,
+	unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_FIXED, free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS ring (multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+__rte_experimental
+static __rte_always_inline unsigned int
+rte_ring_mc_rts_dequeue_bulk_elem(struct rte_ring *r, void **obj_table,
+	unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
+		RTE_RING_QUEUE_FIXED, available);
+}
+
+/**
+ * Enqueue several objects on the RTS ring (multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mp_rts_enqueue_burst_elem(struct rte_ring *r, void * const *obj_table,
+	unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, free_space);
+}
+
+/**
+ * Dequeue several objects from an RTS  ring (multi-consumers safe).
+ * When the requested objects are more than the available objects,
+ * only dequeue the actual number of objects.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+__rte_experimental
+static __rte_always_inline unsigned
+rte_ring_mc_rts_dequeue_burst_elem(struct rte_ring *r, void **obj_table,
+	unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, available);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_RING_RTS_ELEM_H_ */
diff --git a/lib/librte_ring/rte_ring_rts_generic.h b/lib/librte_ring/rte_ring_rts_generic.h
new file mode 100644
index 000000000..31a37924c
--- /dev/null
+++ b/lib/librte_ring/rte_ring_rts_generic.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#ifndef _RTE_RING_RTS_GENERIC_H_
+#define _RTE_RING_RTS_GENERIC_H_
+
+/**
+ * @file rte_ring_rts_generic.h
+ * It is not recommended to include this file directly,
+ * include <rte_ring.h> instead.
+ * Contains internal helper functions for Relaxed Tail Sync (RTS) ring mode.
+ * For more information please refer to <rte_ring_rts.h>.
+ */
+
+/**
+ * @internal This function updates tail values.
+ */
+static __rte_always_inline void
+__rte_ring_rts_update_tail(struct rte_ring_rts_headtail *ht)
+{
+	union rte_ring_ht_poscnt h, ot, nt;
+
+	/*
+	 * If there are other enqueues/dequeues in progress that
+	 * might preceded us, then don't update tail with new value.
+	 */
+
+	do {
+		ot.raw = ht->tail.raw;
+		rte_smp_rmb();
+
+		/* on 32-bit systems we have to do atomic read here */
+		h.raw = rte_atomic64_read((rte_atomic64_t *)
+			(uintptr_t)&ht->head.raw);
+
+		nt.raw = ot.raw;
+		if (++nt.val.cnt == h.val.cnt)
+			nt.val.pos = h.val.pos;
+
+	} while (rte_atomic64_cmpset(&ht->tail.raw, ot.raw, nt.raw) == 0);
+}
+
+/**
+ * @internal This function waits till head/tail distance wouldn't
+ * exceed pre-defined max value.
+ */
+static __rte_always_inline void
+__rte_ring_rts_head_wait(const struct rte_ring_rts_headtail *ht,
+	union rte_ring_ht_poscnt *h)
+{
+	uint32_t max;
+
+	max = ht->htd_max;
+	h->raw = ht->head.raw;
+	rte_smp_rmb();
+
+	while (h->val.pos - ht->tail.val.pos > max) {
+		rte_pause();
+		h->raw = ht->head.raw;
+		rte_smp_rmb();
+	}
+}
+
+/**
+ * @internal This function updates the producer head for enqueue.
+ *
+ * @param r
+ *   A pointer to the ring structure
+ * @param is_sp
+ *   Indicates whether multi-producer path is needed or not
+ * @param n
+ *   The number of elements we will want to enqueue, i.e. how far should the
+ *   head be moved
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param old_head
+ *   Returns head value as it was before the move, i.e. where enqueue starts
+ * @param new_head
+ *   Returns the current/new head value i.e. where enqueue finishes
+ * @param free_entries
+ *   Returns the amount of free space in the ring BEFORE head was moved
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline uint32_t
+__rte_ring_rts_move_prod_head(struct rte_ring *r, uint32_t num,
+	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
+	uint32_t *free_entries)
+{
+	uint32_t n;
+	union rte_ring_ht_poscnt nh, oh;
+
+	const uint32_t capacity = r->capacity;
+
+	do {
+		/* Reset n to the initial burst count */
+		n = num;
+
+		/* read prod head (may spin on prod tail) */
+		__rte_ring_rts_head_wait(&r->rts_prod, &oh);
+
+		/* add rmb barrier to avoid load/load reorder in weak
+		 * memory model. It is noop on x86
+		 */
+		rte_smp_rmb();
+
+		/*
+		 *  The subtraction is done between two unsigned 32bits value
+		 * (the result is always modulo 32 bits even if we have
+		 * *old_head > cons_tail). So 'free_entries' is always between 0
+		 * and capacity (which is < size).
+		 */
+		*free_entries = capacity + r->cons.tail - oh.val.pos;
+
+		/* check that we have enough room in ring */
+		if (unlikely(n > *free_entries))
+			n = (behavior == RTE_RING_QUEUE_FIXED) ?
+					0 : *free_entries;
+
+		if (n == 0)
+			return 0;
+
+		nh.val.pos = oh.val.pos + n;
+		nh.val.cnt = oh.val.cnt + 1;
+
+	} while (rte_atomic64_cmpset(&r->rts_prod.head.raw,
+			oh.raw, nh.raw) == 0);
+
+	*old_head = oh.val.pos;
+	return n;
+}
+
+/**
+ * @internal This function updates the consumer head for dequeue
+ *
+ * @param r
+ *   A pointer to the ring structure
+ * @param is_sc
+ *   Indicates whether multi-consumer path is needed or not
+ * @param n
+ *   The number of elements we will want to enqueue, i.e. how far should the
+ *   head be moved
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param old_head
+ *   Returns head value as it was before the move, i.e. where dequeue starts
+ * @param new_head
+ *   Returns the current/new head value i.e. where dequeue finishes
+ * @param entries
+ *   Returns the number of entries in the ring BEFORE head was moved
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_rts_move_cons_head(struct rte_ring *r, uint32_t num,
+	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
+	uint32_t *entries)
+{
+	uint32_t n;
+	union rte_ring_ht_poscnt nh, oh;
+
+	/* move cons.head atomically */
+	do {
+		/* Restore n as it may change every loop */
+		n = num;
+
+		/* read cons head (may spin on cons tail) */
+		__rte_ring_rts_head_wait(&r->rts_cons, &oh);
+
+
+		/* add rmb barrier to avoid load/load reorder in weak
+		 * memory model. It is noop on x86
+		 */
+		rte_smp_rmb();
+
+		/* The subtraction is done between two unsigned 32bits value
+		 * (the result is always modulo 32 bits even if we have
+		 * cons_head > prod_tail). So 'entries' is always between 0
+		 * and size(ring)-1.
+		 */
+		*entries = r->prod.tail - oh.val.pos;
+
+		/* Set the actual entries for dequeue */
+		if (n > *entries)
+			n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 : *entries;
+
+		if (unlikely(n == 0))
+			return 0;
+
+		nh.val.pos = oh.val.pos + n;
+		nh.val.cnt = oh.val.cnt + 1;
+
+	} while (rte_atomic64_cmpset(&r->rts_cons.head.raw,
+			oh.raw, nh.raw) == 0);
+
+	*old_head = oh.val.pos;
+	return n;
+}
+
+#endif /* _RTE_RING_RTS_GENERIC_H_ */
-- 
2.17.1


^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v2 0/9] New sync modes for ring
  2020-03-31 16:43  3% ` [dpdk-dev] [PATCH v1 0/8] " Konstantin Ananyev
@ 2020-04-02 22:09  3%   ` Konstantin Ananyev
  2020-04-02 22:09  1%     ` [dpdk-dev] [PATCH v2 3/9] ring: introduce RTS ring mode Konstantin Ananyev
  2020-04-03 17:42  3%     ` [dpdk-dev] [PATCH v3 0/9] New sync modes for ring Konstantin Ananyev
  0 siblings, 2 replies; 200+ results
From: Konstantin Ananyev @ 2020-04-02 22:09 UTC (permalink / raw)
  To: dev; +Cc: honnappa.nagarahalli, david.marchand, jielong.zjl, Konstantin Ananyev

V1 - v2 changes:
1. Fix compilation issues
2. Add C11 atomics support
3. Updates devtools/libabigail.abignore (workaround)

RFC - V1 changes:
1. remove ABI brekage (at least I hope I did)
2. Add support for ring_elem
3. Rework peek related API a bit
4. Rework test to make it less verbose and unite all test-cases
   in one command
5. Add new test-case for MT peek API

TODO list:
1. Update docs

These days more and more customers use(/try to use) DPDK based apps within
overcommitted systems (multiple acttive threads over same pysical cores):
VM, container deployments, etc.
One quite common problem they hit:
Lock-Holder-Preemption/Lock-Waiter-Preemption with rte_ring.
LHP is quite a common problem for spin-based sync primitives
(spin-locks, etc.) on overcommitted systems.
The situation gets much worse when some sort of
fair-locking technique is used (ticket-lock, etc.).
As now not only lock-owner but also lock-waiters scheduling
order matters a lot (LWP).
These two problems are well-known for kernel within VMs:
http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
The problem with rte_ring is that while head accusion is sort of
un-fair locking, waiting on tail is very similar to ticket lock schema -
tail has to be updated in particular order.
So while head update exibits only LHP scneario,
tail wait and update can cause an LWP. 
That makes current rte_ring implementation to perform
really pure on some overcommited scenarios.
While it is probably not possible to completely resolve LHP problem in
userspace only (without some kernel communication/intervention),
removing fairness in tail update can mitigate current LWP significantly.
This RFC proposes two new optional ring synchronization modes:
1) Head/Tail Sync (HTS) mode
In that mode enqueue/dequeue operation is fully serialized:
    only one thread at a time is allowed to perform given op.
    As another enhancement provide ability to split enqueue/dequeue
    operation into two phases:
      - enqueue/dequeue start
      - enqueue/dequeue finish
    That allows user to inspect objects in the ring without removing
    them from it (aka MT safe peek).
2) Relaxed Tail Sync (RTS)
The main difference from original MP/MC algorithm is that
tail value is increased not by every thread that finished enqueue/dequeue,
but only by the last one.
That allows threads to avoid spinning on ring tail value,
leaving actual tail value change to the last thread in the update queue.

Note that these new sync modes are optional.
For current rte_ring users nothing should change
(both in terms of API/ABI and performance).
Existing sync modes MP/MC,SP/SC kept untouched, set up in the same
way (via flags and _init_), and MP/MC remains as default one.
The only thing that changed:
Format of prod/cons now could differ depending on mode selected at _init_.
So user has to stick with one sync model through whole ring lifetime.
In other words, user can't create a ring for let say SP mode and then
in the middle of data-path change his mind and start using MP_RTS mode.
For existing modes (SP/MP, SC/MC) format remains the same and
user can still use them interchangeably, though of course it is an
error prone practice.

Test results on IA (see below) show significant improvements
for average enqueue/dequeue op times on overcommitted systems.
For 'classic' DPDK deployments (one thread per core) original MP/MC
algorithm still shows best numbers, though for 64-bit target
RTS numbers are not that far away.
Numbers were produced by new UT test-case: ring_stress_autotest, i.e.:
echo ring_stress_autotest | ./dpdk-test -n 4 --lcores='...'

X86_64 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     8.00       8.15    8.99
2thread@2core(--lcores=6-8)                     19.14      19.61   20.35
4thread@4core(--lcores=6-10)                    29.43      29.79   31.82
8thread@8core(--lcores=6-14)                    110.59     192.81  119.50
16thread@16core(--lcores=6-22)                  461.03     813.12  495.59
32thread/@32core(--lcores='6-22,55-70')         982.90     1972.38 1160.51

2thread@1core(--lcores='6,(10-11)@7'            20140.50   23.58   25.14
4thread@2core(--lcores='6,(10-11)@7,(20-21)@8'  153680.60  76.88   80.05
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  280314.32  294.72  318.79
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 643176.59  1144.02 1175.14
32thread@2core(--lcores='6,(10-25)@7,(30-45)@8' 4264238.80 4627.48 4892.68

8thread@2core(--lcores='6,(10-17)@(7,8))'       321085.98  298.59  307.47
16thread@4core(--lcores='6,(20-35)@(7-10))'     1900705.61 575.35  678.29
32thread@4core(--lcores='6,(20-51)@(7-10))'     5510445.85 2164.36 2714.12

i686 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     7.85       12.13   11.31
2thread@2core(--lcores=6-8)                     17.89      24.52   21.86
8thread@8core(--lcores=6-14)                    32.58      354.20  54.58
32thread/@32core(--lcores='6-22,55-70')         813.77     6072.41 2169.91

2thread@1core(--lcores='6,(10-11)@7'            16095.00   36.06   34.74
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  1140354.54 346.61  361.57
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 1920417.86 1314.90 1416.65

8thread@2core(--lcores='6,(10-17)@(7,8))'       594358.61  332.70  357.74
32thread@4core(--lcores='6,(20-51)@(7-10))'     5319896.86 2836.44 3028.87

Konstantin Ananyev (9):
  test/ring: add contention stress test
  ring: prepare ring to allow new sync schemes
  ring: introduce RTS ring mode
  test/ring: add contention stress test for RTS ring
  ring: introduce HTS ring mode
  test/ring: add contention stress test for HTS ring
  ring: introduce peek style API
  test/ring: add stress test for MT peek API
  ring: add C11 memory model for new sync modes

 app/test/Makefile                      |   5 +
 app/test/meson.build                   |   5 +
 app/test/test_pdump.c                  |   6 +-
 app/test/test_ring_hts_stress.c        |  32 ++
 app/test/test_ring_mpmc_stress.c       |  31 ++
 app/test/test_ring_peek_stress.c       |  43 +++
 app/test/test_ring_rts_stress.c        |  32 ++
 app/test/test_ring_stress.c            |  57 ++++
 app/test/test_ring_stress.h            |  38 +++
 app/test/test_ring_stress_impl.h       | 444 +++++++++++++++++++++++++
 devtools/libabigail.abignore           |   4 +
 lib/librte_pdump/rte_pdump.c           |   2 +-
 lib/librte_port/rte_port_ring.c        |  12 +-
 lib/librte_ring/Makefile               |  11 +-
 lib/librte_ring/meson.build            |  11 +-
 lib/librte_ring/rte_ring.c             | 114 ++++++-
 lib/librte_ring/rte_ring.h             | 244 ++++++++++++--
 lib/librte_ring/rte_ring_c11_mem.h     |  44 +++
 lib/librte_ring/rte_ring_elem.h        | 105 +++++-
 lib/librte_ring/rte_ring_generic.h     |  48 +++
 lib/librte_ring/rte_ring_hts.h         | 214 ++++++++++++
 lib/librte_ring/rte_ring_hts_c11_mem.h | 222 +++++++++++++
 lib/librte_ring/rte_ring_hts_elem.h    | 209 ++++++++++++
 lib/librte_ring/rte_ring_hts_generic.h | 235 +++++++++++++
 lib/librte_ring/rte_ring_peek.h        | 379 +++++++++++++++++++++
 lib/librte_ring/rte_ring_rts.h         | 320 ++++++++++++++++++
 lib/librte_ring/rte_ring_rts_c11_mem.h | 198 +++++++++++
 lib/librte_ring/rte_ring_rts_elem.h    | 209 ++++++++++++
 lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++
 29 files changed, 3428 insertions(+), 56 deletions(-)
 create mode 100644 app/test/test_ring_hts_stress.c
 create mode 100644 app/test/test_ring_mpmc_stress.c
 create mode 100644 app/test/test_ring_peek_stress.c
 create mode 100644 app/test/test_ring_rts_stress.c
 create mode 100644 app/test/test_ring_stress.c
 create mode 100644 app/test/test_ring_stress.h
 create mode 100644 app/test/test_ring_stress_impl.h
 create mode 100644 lib/librte_ring/rte_ring_hts.h
 create mode 100644 lib/librte_ring/rte_ring_hts_c11_mem.h
 create mode 100644 lib/librte_ring/rte_ring_hts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_hts_generic.h
 create mode 100644 lib/librte_ring/rte_ring_peek.h
 create mode 100644 lib/librte_ring/rte_ring_rts.h
 create mode 100644 lib/librte_ring/rte_ring_rts_c11_mem.h
 create mode 100644 lib/librte_ring/rte_ring_rts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_rts_generic.h

-- 
2.17.1


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-02 14:27  4%     ` David Marchand
@ 2020-04-02 15:25  4%       ` Ananyev, Konstantin
  0 siblings, 0 replies; 200+ results
From: Ananyev, Konstantin @ 2020-04-02 15:25 UTC (permalink / raw)
  To: David Marchand, Dodji Seketeli
  Cc: thomas, nhorman, honnappa.nagarahalli, dev, Richardson, Bruce,
	Yigit, Ferruh, Laatz, Kevin

> >
> > Ok, so what is the procedure here?
> > Should I submit changes to devtools/libabigail.abignore together with the
> > patch that introduced the problem?
> > BTW, I used the following changes in libabigail.abignore to supress errors:
> > $ git diff devtools/libabigail.abignore
> > diff --git a/devtools/libabigail.abignore b/devtools/libabigail.abignore
> > index a59df8f13..032479b9f 100644
> > --- a/devtools/libabigail.abignore
> > +++ b/devtools/libabigail.abignore
> > @@ -11,3 +11,9 @@
> >          type_kind = enum
> >          name = rte_crypto_asym_xform_type
> >          changed_enumerators = RTE_CRYPTO_ASYM_XFORM_TYPE_LIST_END
> > +; Ignore updates of ring prod/cons
> > +[suppress_type]
> > +        type_kind = struct
> > +        name = rte_ring
> > +        has_data_members_inserted_at = offsetof(prod)
> > +        has_data_members_inserted_at = offsetof(cons)
> 
> Hum, I could not find offsetof() in the manual but I did find offset_of().

Yep, typo from me.

> 
> But anyway, I understand this has_data_members_inserted_at is a way to
> select structs.
> Not a way to filter out changes that touches fields offsets inside the
> rte_ring structure.

Seems so.
 
> So you might as well simplify the rule and suppress the whole rte_ring
> struct changes.

Ok.

> I suspect this is what is happening here: abidiff did not complain
> about the offsetof vs offset_of thing, so the
> has_data_members_inserted_at criterias may have been ignored.
> 

Konstantin

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-02 12:36  4%   ` Ananyev, Konstantin
  2020-04-02 13:13  4%     ` Dodji Seketeli
@ 2020-04-02 14:27  4%     ` David Marchand
  2020-04-02 15:25  4%       ` Ananyev, Konstantin
  1 sibling, 1 reply; 200+ results
From: David Marchand @ 2020-04-02 14:27 UTC (permalink / raw)
  To: Ananyev, Konstantin, Dodji Seketeli
  Cc: thomas, nhorman, honnappa.nagarahalli, dev, Richardson, Bruce,
	Yigit, Ferruh, Laatz, Kevin

On Thu, Apr 2, 2020 at 2:37 PM Ananyev, Konstantin
<konstantin.ananyev@intel.com> wrote:
> > For the time being, you can waive this by adding a rule in
> > devtools/libabigail.abignore.
>
> Ok, so what is the procedure here?
> Should I submit changes to devtools/libabigail.abignore together with the
> patch that introduced the problem?
> BTW, I used the following changes in libabigail.abignore to supress errors:
> $ git diff devtools/libabigail.abignore
> diff --git a/devtools/libabigail.abignore b/devtools/libabigail.abignore
> index a59df8f13..032479b9f 100644
> --- a/devtools/libabigail.abignore
> +++ b/devtools/libabigail.abignore
> @@ -11,3 +11,9 @@
>          type_kind = enum
>          name = rte_crypto_asym_xform_type
>          changed_enumerators = RTE_CRYPTO_ASYM_XFORM_TYPE_LIST_END
> +; Ignore updates of ring prod/cons
> +[suppress_type]
> +        type_kind = struct
> +        name = rte_ring
> +        has_data_members_inserted_at = offsetof(prod)
> +        has_data_members_inserted_at = offsetof(cons)

Hum, I could not find offsetof() in the manual but I did find offset_of().

But anyway, I understand this has_data_members_inserted_at is a way to
select structs.
Not a way to filter out changes that touches fields offsets inside the
rte_ring structure.

So you might as well simplify the rule and suppress the whole rte_ring
struct changes.
I suspect this is what is happening here: abidiff did not complain
about the offsetof vs offset_of thing, so the
has_data_members_inserted_at criterias may have been ignored.


-- 
David Marchand


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-02 12:36  4%   ` Ananyev, Konstantin
@ 2020-04-02 13:13  4%     ` Dodji Seketeli
  2020-04-02 14:27  4%     ` David Marchand
  1 sibling, 0 replies; 200+ results
From: Dodji Seketeli @ 2020-04-02 13:13 UTC (permalink / raw)
  To: Ananyev, Konstantin
  Cc: David Marchand, thomas, nhorman, honnappa.nagarahalli, dev,
	Richardson, Bruce, Yigit, Ferruh, Dodji Seketeli, Laatz, Kevin

Hello,

"Ananyev, Konstantin" <konstantin.ananyev@intel.com> writes:

> Hi David,
>
>> > Have a question regarding validate-abi.sh.
>> > It complains on the following changes with that patch:
>> >
>> > @@ -111,11 +129,21 @@ struct rte_ring {
>> >         char pad0 __rte_cache_aligned; /**< empty cache line */
>> >
>> >         /** Ring producer status. */
>> > -       struct rte_ring_headtail prod __rte_cache_aligned;
>> > +       RTE_STD_C11
>> > +       union {
>> > +               struct rte_ring_headtail prod;
>> > +               struct rte_ring_rts_headtail rts_prod;
>> > +       }  __rte_cache_aligned;
>> > +
>> >         char pad1 __rte_cache_aligned; /**< empty cache line */
>> >
>> >         /** Ring consumer status. */
>> > -       struct rte_ring_headtail cons __rte_cache_aligned;
>> > +       RTE_STD_C11
>> > +       union {
>> > +               struct rte_ring_headtail cons;
>> > +               struct rte_ring_rts_headtail rts_cons;
>> > +       }  __rte_cache_aligned;
>> > +

[...]

>> It reported a warning on those fields:
>> https://travis-ci.com/github/ovsrobot/dpdk/jobs/310689008#L2380
>> I understand this as a false positive too.
>> 
>> It seems similar to the bz I opened about fields moved to anonymous
>> constructs: https://sourceware.org/bugzilla/show_bug.cgi?id=25661
>
> Yes, looks the same.
>
>
>> Cc: Dodji.
>> 
>> 
>> For the time being, you can waive this by adding a rule in
>> devtools/libabigail.abignore.
>
> Ok, so what is the procedure here?
> Should I submit changes to devtools/libabigail.abignore together with the
> patch that introduced the problem?
> BTW, I used the following changes in libabigail.abignore to supress errors:
> $ git diff devtools/libabigail.abignore
> diff --git a/devtools/libabigail.abignore b/devtools/libabigail.abignore
> index a59df8f13..032479b9f 100644
> --- a/devtools/libabigail.abignore
> +++ b/devtools/libabigail.abignore
> @@ -11,3 +11,9 @@
>          type_kind = enum
>          name = rte_crypto_asym_xform_type
>          changed_enumerators = RTE_CRYPTO_ASYM_XFORM_TYPE_LIST_END
> +; Ignore updates of ring prod/cons
> +[suppress_type]
> +        type_kind = struct
> +        name = rte_ring
> +        has_data_members_inserted_at = offsetof(prod)
> +        has_data_members_inserted_at = offsetof(cons)
>
> Do you know, is there a better (more fine-grained) approach?

I think what you did is correct.

I am teaching the tool to recognize this kind of change construct and
avoid emitting a false positive.  So that you can drop these kind of
suppression specification.

Sorry for the inconvenience.

Cheers,

-- 
		Dodji


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-04-01  6:38  9% ` David Marchand
@ 2020-04-02 12:36  4%   ` Ananyev, Konstantin
  2020-04-02 13:13  4%     ` Dodji Seketeli
  2020-04-02 14:27  4%     ` David Marchand
  0 siblings, 2 replies; 200+ results
From: Ananyev, Konstantin @ 2020-04-02 12:36 UTC (permalink / raw)
  To: David Marchand
  Cc: thomas, nhorman, honnappa.nagarahalli, dev, Richardson, Bruce,
	Yigit, Ferruh, Dodji Seketeli, Laatz, Kevin

Hi David,

> > Have a question regarding validate-abi.sh.
> > It complains on the following changes with that patch:
> >
> > @@ -111,11 +129,21 @@ struct rte_ring {
> >         char pad0 __rte_cache_aligned; /**< empty cache line */
> >
> >         /** Ring producer status. */
> > -       struct rte_ring_headtail prod __rte_cache_aligned;
> > +       RTE_STD_C11
> > +       union {
> > +               struct rte_ring_headtail prod;
> > +               struct rte_ring_rts_headtail rts_prod;
> > +       }  __rte_cache_aligned;
> > +
> >         char pad1 __rte_cache_aligned; /**< empty cache line */
> >
> >         /** Ring consumer status. */
> > -       struct rte_ring_headtail cons __rte_cache_aligned;
> > +       RTE_STD_C11
> > +       union {
> > +               struct rte_ring_headtail cons;
> > +               struct rte_ring_rts_headtail rts_cons;
> > +       }  __rte_cache_aligned;
> > +
> >
> > Complaints:
> > rte_ring.h
> > [−] struct rte_ring  2
> >
> > 1
> > Change: Field cons has been removed from this type.
> > Effect:    Applications will access incorrect memory when attempting to access this field.
> > 2
> > Change: Field prod has been removed from this type.
> > Effect:    Applications will access incorrect memory when attempting to access this field.
> >
> > From my perspective it looks false-positive:
> > *prod* and *cons* fields are still there,
> > their format, size and offset within rte_ring remain the same.
> > Is that some limitation with the tool, or am I missing something here?
> 
> - Side note, we have build failures with clang and ARM jobs:
> https://travis-ci.com/github/ovsrobot/dpdk/builds/157277423

ack, will fix.

> 
> 
> - We switched to libabigail called from devtools/check-abi.sh which
> you can run locally
> (https://doc.dpdk.org/guides/contributing/patches.html?highlight=abi#checking-abi-compatibility).
> Or you can count on Aaron's robot to do this check in Travis.
> 
> It reported a warning on those fields:
> https://travis-ci.com/github/ovsrobot/dpdk/jobs/310689008#L2380
> I understand this as a false positive too.
> 
> It seems similar to the bz I opened about fields moved to anonymous
> constructs: https://sourceware.org/bugzilla/show_bug.cgi?id=25661

Yes, looks the same.


> Cc: Dodji.
> 
> 
> For the time being, you can waive this by adding a rule in
> devtools/libabigail.abignore.

Ok, so what is the procedure here?
Should I submit changes to devtools/libabigail.abignore together with the
patch that introduced the problem?
BTW, I used the following changes in libabigail.abignore to supress errors:
$ git diff devtools/libabigail.abignore
diff --git a/devtools/libabigail.abignore b/devtools/libabigail.abignore
index a59df8f13..032479b9f 100644
--- a/devtools/libabigail.abignore
+++ b/devtools/libabigail.abignore
@@ -11,3 +11,9 @@
         type_kind = enum
         name = rte_crypto_asym_xform_type
         changed_enumerators = RTE_CRYPTO_ASYM_XFORM_TYPE_LIST_END
+; Ignore updates of ring prod/cons
+[suppress_type]
+        type_kind = struct
+        name = rte_ring
+        has_data_members_inserted_at = offsetof(prod)
+        has_data_members_inserted_at = offsetof(cons)

Do you know, is there a better (more fine-grained) approach?
Thanks
Konstantin

  



^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 1/6] rte_ethdev: add function to check if device is owned
  2020-04-01 22:24  3%       ` Stephen Hemminger
@ 2020-04-02  8:04  3%         ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-04-02  8:04 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, ferruh.yigit, arybchenko

02/04/2020 00:24, Stephen Hemminger:
> On Wed, 01 Apr 2020 23:42:44 +0200
> Thomas Monjalon <thomas@monjalon.net> wrote:
> 
> > 16/03/2020 17:09, Stephen Hemminger:
> > > This is a simple helper function to check if device is owned
> > > (being used as a sub-device).  
> > 
> > I would suggest not restricting ownership to sub-device case.
> > 
> > > It is more convienent than having
> > > applications call rte_eth_dev_owner_get and check the result.  
> > 
> > Yes it is more convenient but I don't like adding such simple wrapper.
> > 
> > I propose to extend rte_eth_dev_owner_get() behaviour:
> > if the owner pointer is NULL, the function returns 0 only
> > if an owner (not RTE_ETH_DEV_NO_OWNER) is found.
> > 
> > So instead of using your wrapper:
> > 	if (rte_eth_dev_is_owned(port_id))
> > you can use:
> > 	if (rte_eth_dev_owner_get(port_id, NULL) == 0)
> 
> That is not how rte_eth_dev_owner_get works now.
> Passing NULL to it would crash.

Indeed this is why I am proposing to extend it
and fill this case.

> And if devices is not owned rte_eth_dev_owner_get() returns 0
> and owner is set to a magic value. We could change the ABI for this 
> since it is marked experimental. But that seems more risky.

This is not an ABI change.
Just manage a case which was crashing previously.






^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2 1/6] rte_ethdev: add function to check if device is owned
  @ 2020-04-01 22:24  3%       ` Stephen Hemminger
  2020-04-02  8:04  3%         ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Stephen Hemminger @ 2020-04-01 22:24 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, ferruh.yigit, arybchenko

On Wed, 01 Apr 2020 23:42:44 +0200
Thomas Monjalon <thomas@monjalon.net> wrote:

> 16/03/2020 17:09, Stephen Hemminger:
> > This is a simple helper function to check if device is owned
> > (being used as a sub-device).  
> 
> I would suggest not restricting ownership to sub-device case.
> 
> > It is more convienent than having
> > applications call rte_eth_dev_owner_get and check the result.  
> 
> Yes it is more convenient but I don't like adding such simple wrapper.
> 
> I propose to extend rte_eth_dev_owner_get() behaviour:
> if the owner pointer is NULL, the function returns 0 only
> if an owner (not RTE_ETH_DEV_NO_OWNER) is found.
> 
> So instead of using your wrapper:
> 	if (rte_eth_dev_is_owned(port_id))
> you can use:
> 	if (rte_eth_dev_owner_get(port_id, NULL) == 0)

That is not how rte_eth_dev_owner_get works now.
Passing NULL to it would crash.

And if devices is not owned rte_eth_dev_owner_get() returns 0
and owner is set to a magic value. We could change the ABI for this 
since it is marked experimental. But that seems more risky.

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v3 00/33] DPDK Trace support
  2020-04-01 14:12  0%         ` David Marchand
@ 2020-04-01 14:16  0%           ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-04-01 14:16 UTC (permalink / raw)
  To: Jerin Jacob Kollanukkaran, David Marchand
  Cc: dev, Bruce Richardson, Mattias Rönnblom, Sunil Kumar Kori,
	Yigit, Ferruh, Andrew Rybchenko, Declan Doherty, Olivier Matz,
	Neil Horman, Ray Kinsella

01/04/2020 16:12, David Marchand:
> On Wed, Apr 1, 2020 at 12:05 PM Jerin Jacob <jerinjacobk@gmail.com> wrote:
> > On Wed, Apr 1, 2020 at 1:49 PM David Marchand <david.marchand@redhat.com> wrote:
> > > - Regardless of the trace framework, the ALLOW_EXPERIMENTAL_API flag
> > > gates access to APIs so that external users are aware of their status.
> > > I have been considering setting this flag unconditionally for internal
> > > users in the top Makefile/meson for app/ lib/ and drivers/.
> > > I could look at this and prepare a patch about this, but this is not
> > > enough here.
> >
> > It makes sense to me. Let me know when you are planning to send that patch,
> > I will rebase this series on top of that.
> 
> Feel free to take over, thanks.
> 
> 
> >
> > If you don't have time then I can send the patch too.
> > I assume the patch content will be:
> > 1) Removing experimental API from app, lib, drivers, examples with
> > make and meson
> > 2) Have it enabled at the global level.
> 
> examples are a special case as they can be compiled out of the dpdk sources.
> This is why I excluded them of the list in my mail before.
> 
> 
> > > How about:
> > > * we introduce a global config switch that enables/disables the trace
> > > framework (off by default): the people who want to test it and help
> > > stabilize it will have to deal with the experimental flag for now,
> > > * in 20.11, the trace points are put into the stable ABI, and the
> > > option is removed,
> >
> > IMO, the better alternative  would be:
> >
> > Since the trace changes in the "inline" functions of the specific
> > library already
> > disabled under _compile time_ RTE_ENABLE_TRACE_DP flag and
> > it is using RTE_TRACE_POINT_DP() to define the trace unlike slow path
> > trace like RTE_TRACE_POINT().
> 
> Ah indeed.
> Note: RTE_ENABLE_TRACE_DP is not plugged with meson.
> 
> 
> > So I can improve RTE_TRACE_POINT_DP() to make absolute NOP if
> > ALLOW_EXPERIMENTAL_API not defined.
> >
> > On the upside,
> > The tracing code will be enabled by default(runtime it is disabled by
> > default anyway).
> > If some need to fastpath API tracing then  ALLOW_EXPERIMENTAL_API need
> > to enable.
> > So this won't break applications.
> 
> So either keep the RTE_ENABLE_TRACE_DP flag or use
> ALLOW_EXPERIMENTAL_API... no opinion.
> Thomas?

Anyway we need a compile-time option?
The option is just for compatibility?
Then ALLOW_EXPERIMENTAL_API looks to be the right option.




^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3 00/33] DPDK Trace support
  2020-04-01 10:04  0%       ` Jerin Jacob
@ 2020-04-01 14:12  0%         ` David Marchand
  2020-04-01 14:16  0%           ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-04-01 14:12 UTC (permalink / raw)
  To: Jerin Jacob Kollanukkaran, Thomas Monjalon
  Cc: dev, Bruce Richardson, Mattias Rönnblom, Sunil Kumar Kori,
	Yigit, Ferruh, Andrew Rybchenko, Declan Doherty, Olivier Matz,
	Neil Horman, Ray Kinsella

On Wed, Apr 1, 2020 at 12:05 PM Jerin Jacob <jerinjacobk@gmail.com> wrote:
> On Wed, Apr 1, 2020 at 1:49 PM David Marchand <david.marchand@redhat.com> wrote:
> > - Regardless of the trace framework, the ALLOW_EXPERIMENTAL_API flag
> > gates access to APIs so that external users are aware of their status.
> > I have been considering setting this flag unconditionally for internal
> > users in the top Makefile/meson for app/ lib/ and drivers/.
> > I could look at this and prepare a patch about this, but this is not
> > enough here.
>
> It makes sense to me. Let me know when you are planning to send that patch,
> I will rebase this series on top of that.

Feel free to take over, thanks.


>
> If you don't have time then I can send the patch too.
> I assume the patch content will be:
> 1) Removing experimental API from app, lib, drivers, examples with
> make and meson
> 2) Have it enabled at the global level.

examples are a special case as they can be compiled out of the dpdk sources.
This is why I excluded them of the list in my mail before.


> > How about:
> > * we introduce a global config switch that enables/disables the trace
> > framework (off by default): the people who want to test it and help
> > stabilize it will have to deal with the experimental flag for now,
> > * in 20.11, the trace points are put into the stable ABI, and the
> > option is removed,
>
> IMO, the better alternative  would be:
>
> Since the trace changes in the "inline" functions of the specific
> library already
> disabled under _compile time_ RTE_ENABLE_TRACE_DP flag and
> it is using RTE_TRACE_POINT_DP() to define the trace unlike slow path
> trace like RTE_TRACE_POINT().

Ah indeed.
Note: RTE_ENABLE_TRACE_DP is not plugged with meson.


> So I can improve RTE_TRACE_POINT_DP() to make absolute NOP if
> ALLOW_EXPERIMENTAL_API not defined.
>
> On the upside,
> The tracing code will be enabled by default(runtime it is disabled by
> default anyway).
> If some need to fastpath API tracing then  ALLOW_EXPERIMENTAL_API need
> to enable.
> So this won't break applications.

So either keep the RTE_ENABLE_TRACE_DP flag or use
ALLOW_EXPERIMENTAL_API... no opinion.
Thomas?


> > - With the patchset rebased on the current master (could be my fault,
> > so take it with a grain of salt), the ALLOW_EXPERIMENTAL_API flag is
> > not passed when compiling the l3fwd example against an installed dpdk.
>
> I will check. We have added ALLOW_EXPERIMENTAL_API flag where we got
> compilation issues.

No compilation issue, just big fat warnings reporting that l3fwd did
not enable ALLOW_EXPERIMENTAL_API and it is not built with -Werror.
I caught it with ./devtools/test-*build*.sh scripts.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-03-31 19:24  4%   ` Thomas Monjalon
@ 2020-04-01 12:52  4%     ` Neil Horman
  2020-04-06 14:02  4%       ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Neil Horman @ 2020-04-01 12:52 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: mdr, Ananyev, Konstantin, david.marchand, honnappa.nagarahalli,
	dev, Richardson, Bruce, Yigit, Ferruh, kevin.laatz

On Tue, Mar 31, 2020 at 09:24:41PM +0200, Thomas Monjalon wrote:
> 31/03/2020 21:22, Thomas Monjalon:
> > 31/03/2020 19:05, Ananyev, Konstantin:
> > > Hi everyone,
> > > 
> > > Have a question regarding validate-abi.sh.
> > 
> > devtools/validate-abi.sh should be removed.
> > Please use the new devtools/check-abi.sh
> 
> The file doc/guides/contributing/abi_versioning.rst
> should be updated as well.
> Neil? Ray?
> 
Ack, we should remove validate_abi and update the docs
Neil

> 
> 

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v3 00/33] DPDK Trace support
  2020-04-01  8:18  3%     ` David Marchand
@ 2020-04-01 10:04  0%       ` Jerin Jacob
  2020-04-01 14:12  0%         ` David Marchand
  0 siblings, 1 reply; 200+ results
From: Jerin Jacob @ 2020-04-01 10:04 UTC (permalink / raw)
  To: David Marchand
  Cc: Jerin Jacob Kollanukkaran, dev, Thomas Monjalon,
	Bruce Richardson, Mattias Rönnblom, Sunil Kumar Kori, Yigit,
	Ferruh, Andrew Rybchenko, Declan Doherty, Olivier Matz,
	Neil Horman, Ray Kinsella

On Wed, Apr 1, 2020 at 1:49 PM David Marchand <david.marchand@redhat.com> wrote:
>
> Hello Jerin,

Hello David,

Thanks for the review.

>
> On Sun, Mar 29, 2020 at 4:43 PM <jerinj@marvell.com> wrote:
> > Items that needs to be sort it out
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > # Makefile and meson.build are updated to allow experimental APIs.
> >
> > As multiple EXPERIMENTAL symbols, exported by trace library, are
> > used in various drivers, lib, app and examples. So to fix compilation
> > warning/error, Makefile and meson.build are updated for all required
> > components to support EXPERIMENTAL APIs.
> > It results same code changes at multiple components as well as
> > increases source code line changes in patchset too.
> > Suggestions are welcome to resolve this issue with lesser code changes.
>
> - Regardless of the trace framework, the ALLOW_EXPERIMENTAL_API flag
> gates access to APIs so that external users are aware of their status.
> I have been considering setting this flag unconditionally for internal
> users in the top Makefile/meson for app/ lib/ and drivers/.
> I could look at this and prepare a patch about this, but this is not
> enough here.

It makes sense to me. Let me know when you are planning to send that patch,
I will rebase this series on top of that.

If you don't have time then I can send the patch too.
I assume the patch content will be:
1) Removing experimental API from app, lib, drivers, examples with
make and meson
2) Have it enabled at the global level.

> With the trace framework, we add experimental symbols in mempool or
> ethdev inlines, which then inherit the experimental check.
> This would break compilation of external code. Users are then forced
> to enable experimental API.

I agree with the analysis.

>
> How about:
> * we introduce a global config switch that enables/disables the trace
> framework (off by default): the people who want to test it and help
> stabilize it will have to deal with the experimental flag for now,
> * in 20.11, the trace points are put into the stable ABI, and the
> option is removed,

IMO, the better alternative  would be:

Since the trace changes in the "inline" functions of the specific
library already
disabled under _compile time_ RTE_ENABLE_TRACE_DP flag and
it is using RTE_TRACE_POINT_DP() to define the trace unlike slow path
trace like RTE_TRACE_POINT().
So I can improve RTE_TRACE_POINT_DP() to make absolute NOP if
ALLOW_EXPERIMENTAL_API not defined.

On the upside,
The tracing code will be enabled by default(runtime it is disabled by
default anyway).
If some need to fastpath API tracing then  ALLOW_EXPERIMENTAL_API need
to enable.
So this won't break applications.

>
>
> - With the patchset rebased on the current master (could be my fault,
> so take it with a grain of salt), the ALLOW_EXPERIMENTAL_API flag is
> not passed when compiling the l3fwd example against an installed dpdk.

I will check. We have added ALLOW_EXPERIMENTAL_API flag where we got
compilation issues.

>
>
> - On the MAINTAINERS update:
>
> Trace
> M: Jerin Jacob <jerinj@marvell.com>
> M: Sunil Kumar Kori <skori@marvell.com>
> F: lib/librte_eal/include/rte_trace*.h
> F: lib/librte_eal/common/eal_common_trace*.c
> F: lib/librte_eal/common/eal_trace.h
> F: lib/librte_ethdev/ethdev_trace_points.c
> F: lib/librte_ethdev/rte_trace_ethdev*.h
> F: lib/librte_eventdev/eventdev_trace_points.c
> F: lib/librte_eventdev/rte_trace_eventdev*.h
> F: lib/librte_cryptodev/cryptodev_trace_points.c
> F: lib/librte_cryptodev/rte_trace_cryptodev*.h
> F: lib/librte_mempool/mempool_trace_points.c
> F: lib/librte_mempool/rte_trace_mempool*.h
>
> Once we exclude the trace framework, the trace points themselves
> should be the responsibility of the component (ethdev, eventdev...)
> maintainers (copied them).

Yes. I will remove the following from the MAINTAINERS update in the
next version.

 F: lib/librte_ethdev/ethdev_trace_points.c
 F: lib/librte_ethdev/rte_trace_ethdev*.h
 F: lib/librte_eventdev/eventdev_trace_points.c
 F: lib/librte_eventdev/rte_trace_eventdev*.h
 F: lib/librte_cryptodev/cryptodev_trace_points.c
 F: lib/librte_cryptodev/rte_trace_cryptodev*.h
 F: lib/librte_mempool/mempool_trace_points.c
 F: lib/librte_mempool/rte_trace_mempool*.h


>
>
> - I had something more dynamic in mind for gathering traces: like
> enabling/disabling trace points in a running process and getting the
> traces on the fly.

rte_trace_enable() and rte_trace_disable() already avilable for this.

> But I suppose the current framework is enough and we can work on this later.

Yes. for all new features.

>
>
>
> >
> > More details:
> > ~~~~~~~~~~~~~
> >
> > # The Native DPDK CTF trace support does not have any dependency on
> > third-party library.
> > The generated output file is compatible with LTTng as both are using
> > CTF trace format.
> >
> > The performance gain comes from:
> > 1) exploit dpdk worker thread usage model to avoid atomics and use per
> > core variables
> > 2) use hugepage,
> > 3) avoid a lot function pointers in fast-path etc
> > 4) avoid unaligned store for arm64 etc
> >
> > Features:
> > ~~~~~~~~~
> > - APIs and Features are similar to rte_log dynamic framework
> > API(expect log prints on stdout vs it dumps on trace file)
>
> I am not sure about the global and per tracepoint levels.
> We must enable each tracepoint anyway, the level is just a commodity.
>
> I don't have strong arguments against it, but it feels odd to
> copy/paste the rte_log framework.

I have intentionally kept public API similar to rte_log wherever it is
possible. Reason being,
1) In the future, it is easy to replace rte_log with trace _if needed_.
2) Avoid the new API learning curve.

/Jerin


>
>
> --
> David Marchand
>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v3 00/33] DPDK Trace support
  2020-03-29 14:43  1%   ` [dpdk-dev] [PATCH v3 00/33] " jerinj
@ 2020-04-01  8:18  3%     ` David Marchand
  2020-04-01 10:04  0%       ` Jerin Jacob
  2020-04-03 15:36  1%     ` [dpdk-dev] [PATCH v4 " jerinj
  1 sibling, 1 reply; 200+ results
From: David Marchand @ 2020-04-01  8:18 UTC (permalink / raw)
  To: Jerin Jacob Kollanukkaran
  Cc: dev, Thomas Monjalon, Bruce Richardson, Mattias Rönnblom,
	Sunil Kumar Kori, Yigit, Ferruh, Andrew Rybchenko,
	Declan Doherty, Olivier Matz, Neil Horman

Hello Jerin,

On Sun, Mar 29, 2020 at 4:43 PM <jerinj@marvell.com> wrote:
> Items that needs to be sort it out
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> # Makefile and meson.build are updated to allow experimental APIs.
>
> As multiple EXPERIMENTAL symbols, exported by trace library, are
> used in various drivers, lib, app and examples. So to fix compilation
> warning/error, Makefile and meson.build are updated for all required
> components to support EXPERIMENTAL APIs.
> It results same code changes at multiple components as well as
> increases source code line changes in patchset too.
> Suggestions are welcome to resolve this issue with lesser code changes.

- Regardless of the trace framework, the ALLOW_EXPERIMENTAL_API flag
gates access to APIs so that external users are aware of their status.
I have been considering setting this flag unconditionally for internal
users in the top Makefile/meson for app/ lib/ and drivers/.
I could look at this and prepare a patch about this, but this is not
enough here.

With the trace framework, we add experimental symbols in mempool or
ethdev inlines, which then inherit the experimental check.
This would break compilation of external code. Users are then forced
to enable experimental API.

How about:
* we introduce a global config switch that enables/disables the trace
framework (off by default): the people who want to test it and help
stabilize it will have to deal with the experimental flag for now,
* in 20.11, the trace points are put into the stable ABI, and the
option is removed,


- With the patchset rebased on the current master (could be my fault,
so take it with a grain of salt), the ALLOW_EXPERIMENTAL_API flag is
not passed when compiling the l3fwd example against an installed dpdk.


- On the MAINTAINERS update:

Trace
M: Jerin Jacob <jerinj@marvell.com>
M: Sunil Kumar Kori <skori@marvell.com>
F: lib/librte_eal/include/rte_trace*.h
F: lib/librte_eal/common/eal_common_trace*.c
F: lib/librte_eal/common/eal_trace.h
F: lib/librte_ethdev/ethdev_trace_points.c
F: lib/librte_ethdev/rte_trace_ethdev*.h
F: lib/librte_eventdev/eventdev_trace_points.c
F: lib/librte_eventdev/rte_trace_eventdev*.h
F: lib/librte_cryptodev/cryptodev_trace_points.c
F: lib/librte_cryptodev/rte_trace_cryptodev*.h
F: lib/librte_mempool/mempool_trace_points.c
F: lib/librte_mempool/rte_trace_mempool*.h

Once we exclude the trace framework, the trace points themselves
should be the responsibility of the component (ethdev, eventdev...)
maintainers (copied them).


- I had something more dynamic in mind for gathering traces: like
enabling/disabling trace points in a running process and getting the
traces on the fly.
But I suppose the current framework is enough and we can work on this later.



>
> More details:
> ~~~~~~~~~~~~~
>
> # The Native DPDK CTF trace support does not have any dependency on
> third-party library.
> The generated output file is compatible with LTTng as both are using
> CTF trace format.
>
> The performance gain comes from:
> 1) exploit dpdk worker thread usage model to avoid atomics and use per
> core variables
> 2) use hugepage,
> 3) avoid a lot function pointers in fast-path etc
> 4) avoid unaligned store for arm64 etc
>
> Features:
> ~~~~~~~~~
> - APIs and Features are similar to rte_log dynamic framework
> API(expect log prints on stdout vs it dumps on trace file)

I am not sure about the global and per tracepoint levels.
We must enable each tracepoint anyway, the level is just a commodity.

I don't have strong arguments against it, but it feels odd to
copy/paste the rte_log framework.


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-03-31 17:05  7% [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode Ananyev, Konstantin
  2020-03-31 19:22  8% ` Thomas Monjalon
@ 2020-04-01  6:38  9% ` David Marchand
  2020-04-02 12:36  4%   ` Ananyev, Konstantin
  1 sibling, 1 reply; 200+ results
From: David Marchand @ 2020-04-01  6:38 UTC (permalink / raw)
  To: Ananyev, Konstantin
  Cc: thomas, nhorman, honnappa.nagarahalli, dev, Richardson, Bruce,
	Yigit, Ferruh, Dodji Seketeli, Kevin Laatz

On Tue, Mar 31, 2020 at 7:05 PM Ananyev, Konstantin
<konstantin.ananyev@intel.com> wrote:
>
> Hi everyone,
>
> Have a question regarding validate-abi.sh.
> It complains on the following changes with that patch:
>
> @@ -111,11 +129,21 @@ struct rte_ring {
>         char pad0 __rte_cache_aligned; /**< empty cache line */
>
>         /** Ring producer status. */
> -       struct rte_ring_headtail prod __rte_cache_aligned;
> +       RTE_STD_C11
> +       union {
> +               struct rte_ring_headtail prod;
> +               struct rte_ring_rts_headtail rts_prod;
> +       }  __rte_cache_aligned;
> +
>         char pad1 __rte_cache_aligned; /**< empty cache line */
>
>         /** Ring consumer status. */
> -       struct rte_ring_headtail cons __rte_cache_aligned;
> +       RTE_STD_C11
> +       union {
> +               struct rte_ring_headtail cons;
> +               struct rte_ring_rts_headtail rts_cons;
> +       }  __rte_cache_aligned;
> +
>
> Complaints:
> rte_ring.h
> [−] struct rte_ring  2
>
> 1
> Change: Field cons has been removed from this type.
> Effect:    Applications will access incorrect memory when attempting to access this field.
> 2
> Change: Field prod has been removed from this type.
> Effect:    Applications will access incorrect memory when attempting to access this field.
>
> From my perspective it looks false-positive:
> *prod* and *cons* fields are still there,
> their format, size and offset within rte_ring remain the same.
> Is that some limitation with the tool, or am I missing something here?

- Side note, we have build failures with clang and ARM jobs:
https://travis-ci.com/github/ovsrobot/dpdk/builds/157277423


- We switched to libabigail called from devtools/check-abi.sh which
you can run locally
(https://doc.dpdk.org/guides/contributing/patches.html?highlight=abi#checking-abi-compatibility).
Or you can count on Aaron's robot to do this check in Travis.

It reported a warning on those fields:
https://travis-ci.com/github/ovsrobot/dpdk/jobs/310689008#L2380
I understand this as a false positive too.

It seems similar to the bz I opened about fields moved to anonymous
constructs: https://sourceware.org/bugzilla/show_bug.cgi?id=25661
Cc: Dodji.


For the time being, you can waive this by adding a rule in
devtools/libabigail.abignore.

-- 
David Marchand


^ permalink raw reply	[relevance 9%]

* [dpdk-dev] [PATCH v3] doc: use svg file type for ice PMD
  2020-03-31 12:01  1% [dpdk-dev] [PATCH v1] doc: use svg file type for ice nic Haiyue Wang
  2020-03-31 12:06  1% ` [dpdk-dev] [PATCH v2] doc: use svg file type for ice Haiyue Wang
@ 2020-04-01  5:44  1% ` Haiyue Wang
  1 sibling, 0 replies; 200+ results
From: Haiyue Wang @ 2020-04-01  5:44 UTC (permalink / raw)
  To: dev, xiaolong.ye, ferruh.yigit; +Cc: Haiyue Wang

Replace the PNG binary format with SVG text format.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
v3: Recreate it as .svg from scratch
v2: Fix the commit tile log format error
---
 doc/guides/nics/img/ice_dcf.png | Bin 39168 -> 0 bytes
 doc/guides/nics/img/ice_dcf.svg | 516 ++++++++++++++++++++++++++++++++
 2 files changed, 516 insertions(+)
 delete mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 doc/guides/nics/img/ice_dcf.svg

diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
deleted file mode 100644
index 540823c4a05e9ea9d558d233fea77016d1ae5df3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 39168
zcmZ6ybzD?k*FH`NDBT?jlF}e8B?Hn74BeolfOLbDz);d%Lw70NNOyNPNO%7Z_x(KY
z`+k3a@X<4KW}m&+Uh7)dy4F6yN(xdKsHCWHaBvvXpCpvw;1KwLKlqmjz$g7i%71`=
z;O&*A#NkSZ$ajH@7p7wJVsLO35oq^@NWk^0Z=W>n;oxu`p8w#NOsHJo;1Xh`CBz^u
zdIzZ}I(W`x-6a%La{^jclNOU&`_)rTS4-}zY76d1P4w1CVq)-OmrKC^5#ZY~-}pzu
zy$L?@i@zdO6jl2qp0>O_?^V0~==_TKu;0E)6AT_jK}Ys$GuU9xpl6NmUq4AAAS8rZ
z5<h>~BQL7h+1bg!^v{JkDk^GFZXt;WZK)wU@I4Lh>Nma-8Py=vX58uL5BwsNv0+TC
ztdd|ub|{f>I#qBR_r=Ecc2+(+F$m*+POs4gtgWq$;%5$Zz1W+)IolS4AR!?E!%MzF
zY^hc+(<6BKV$B>q*BptIQ5gaPfd*IJosgp=XT25!8zwm^L5M@!Q9uFabHF7#DiuCK
zt~qeo#^9j@Nyw!ThkWHBd%m>z=MtX)IqO&q%qUT-Q<|7KJNMhNs;a6pC&Kl7XSB)v
z3KtLW;^N}!aM9A*nl<f&LypeAH;UH%@~=<W?^;Mic5d!cle_a$qiaVX7S(%;iC{c>
zPEJmL@k|#dzb#-e#WW$n3TwM=5&|%zK#w5Rj~l++vL_;_xx2ZfV1g5o&-OTVud|dg
zY)p8a+CN(%s#Jb5B@9dFyIC8&!|9!kw<)+dnAUfkUON7RZe*>j5V@t@LFIjKzBWN}
zl6bSB?AXD@u-6mJ^$s$%>{fg;H**<Wy_z$R_0fFyxQl_NC8(r`t&yYbC$Wq!ZhWiR
zaQO>2)_CPI7Ur}ViP+8SHXAZ(qCX-8Pgw>@)`d8#Ub}%C2oieVUWG5$Z;wDPw0oh!
z(MS2V(Mt&eBO3Siyc1oDi4_JnN!?`_!F7~4=LJ<;7i4@c?GuTsp&oXOubJN~j*nRE
zr*(v=l`h&IUu)Y-G0<(qS?nZJwYZ$k+*tNcTf2SvjF$-h6dEDNR%>@OyFp@~wx8sm
zQ@KkHCa?M<DDa*q5JkVi|7}X6ooQlUmnxZR*#{T+GPIBvv|B=xJdNM>M<?%wx7c)l
zdn}q*;Wg|Gzyh^yRZNGE1Xt2+qw~^RE=E{lE|-=pha<-cjHj$U3eSXtS-y9ciA;Qt
zg#X2CIXogbtk+gV#pepYbkK~qZROc+2-nD3e6SS4d#n~;vgmMgi02}r<bB>}Fg(g-
zTDmx2YrO0kRzm_}D5S%J%DnQ0DdV>iV*NTt#-ch%|0xYIm~S%Q_BwvyfdQLqe%iUU
za<4uRAr<XM?#|y&3?~<aXTr-Hgaz#tT;9D;cK$2uv9~aYB8Zi$G+Wuxv-FN9+5PYR
zh4qI=trjcZ;=wL@A=W&9;v>?i^7Yn}O(rs$G1Q(|Z2z1sn<Yns)V;&#c$@TE2Q)Ru
z)6)`Bt!gQksJ*lfL=-F}Q=R&|&-+U>DkcK~7vFVi4u!dmmta<R;msWO$55HcDm$Mq
zYzuC++dJmp5`L=_vy^#UbXhfEraEBcG`ZP)uwPnpl~qe?xmmf+NiO2ax1Om+(c=}a
z!GBS0w-`sWU7FHRP;K|H)xhT98<o%yk#hLBt#8R=)!=YcP~pc5m_`)LD5eB~iYqs_
zj?tLy72jM<E{lrbr1en>*bVr_*W;KI;3E7^sdYFjoC{%b$NVtKVTT^7+2BYNw7pYj
zi4R5^w->W9pqU==f1#Eb;6C!>z+DXeb>TXZwZp;G`tJ%B5BYEu=0)FDN%x4fNM_s}
z&3d^+eysZRo^x@R*na2q(uHz@x%b$Uaf>KVBm(XH446M${l^6#mQ=@EaW_yr=YvCd
z+ccCShFQ?$1}?+o10_*^aev+*-pN^+qy-`EqoDYuWpSd~d>GvmJf>Q%JrCl>)WF6k
zmNOMMMp+hgneL-`A#pMMbJc=vS<;lS;}#5&f&14fUK<#DZv350Jd6LHkN$NrFqGJ8
zlLQ^XPt!kNF7<(R!K>C~vVL6sXh^GeVu@|f9?Xx@{W00`WXRZv(|^df><;rf5PNdx
zBpMO7vZw8Z5tyP#0>Vqx1X*<dv&0Kc;4ZffjQvQ21Vb2S)~HS*e}&q3vP0X5Ck>{p
zL|PgxQ2d3lia{mhxO*i0u!<pNN+=Dr*xkF}rL@3)H_B6SSLCd3U(-4g(^%Ggi&~71
zLC)Opd9psBf9m^tF-R2=i~Y+Wx~{DJ7&!b`+!vr6(LbBVOG$#4e;21&m~FS))*G-=
zPa}wqkl#vdk|f?wwVSv9(#)clt1G+|;%v%L28)#;+6VXk{7iUG+jNKVTH?KH*Mg`P
z4}U@{EuUAnkMX-Hs~^?DoM;li?~cv8zY`mcjZ7JLTz<$aU4RE4@Y}g{&JAw#$bdHS
zIsj~7y#89(M|b^nq}$-hTBu4^z2sUdUo4>v8BBVg%wyU%_MXf@bERkY-D?x<$;O<b
zpvBDRefW<DBArvMWHxmVUG9o}n*WowASDGwz0FLH(Dzku6^(`Vv9TH-Or_3WQek9&
zp{?wvKs0uy5PokudTJp-5ZP7duzj+zYp+MDA<51+GTg}}+XPcyOCY#AF=5lm{bEKD
zuYwz`>Y=}WkR(4(Y2H+%2SHKL8L4sdgQdlyUB8->Fe_=z_$V35@6;>_^Sx+A)!#{y
z%vNutx>hi*td+hI$B#YrfhqfD<l~3DlzhC=#`503zteBJi#)&=g+hzrVxg$DkD{I@
zg^onlA0{~L`RpH-+6gSVF_?>R2n@E#DgbDpEt*<Z@je@xlV4BeZ%k2#RC;@KHPXI=
zTv4h`bGcu3y~M9wU$HGWe-9h0vD0j^8a@f(O+_$Xo~<oWUu<$5exr+)S7gD4{3wVn
zgrav3%g?CuuSSpayqwxe{k^|Fjm)EGSivv!zjH;?(yL3=fBQ=%uWad!A{EMEQA^#0
z1YSLDC4#7>-9zS&zAcI<8lQ|mDf7d6im6Q*Pa;o%x1R@B!{cXusK5DSe-NiT0+q(3
zJAul<M~5YH9~^lh-eTUP{6+YH%@Tq2W2W5mXeE;-FoLq>=#Q(^6LkG!bA|cqcF*pi
zs1U^jfwNgMV;A~2jK#)8*61YsCi9QR)xxWa4oeYf>?DNCwZ`dlvWs4bPp=e=C;^0@
zKx^mvbur_;)>z-nUx7=5Qf6*XICBRQBO-{5^FAFbsff<KpkO!a8>m~+y7p>YE4&LA
zuaOFs0yDxhFwwq*qMEm7{5K*3xDA#58|>mq?5K=|*ax&{U5}%6AKyg@FV2-FFZMsS
zrHF6K$F#kK%8>ZN{<(`uWDrDi_jGHzJr(KJ|1yPYc)l)sxy8H2+vzKLzZc?{M!E7v
zF8j7?Yx*gy+=(y$qRI15nG2g2=Obg4BUlV=;xP}#z2<_JKj<^R-sjvH4CwW2sL>TH
zBFbS!1ZIVePcY_hP7Oo2*3+(G-We}hkFa4=pbOcJV<M%e|C+Y!zUqG{n|J=*>)qtn
zuvYEZ1ox-boipvgxq`t_VP5lxlooZlyR(J3H(<AZF?Y%7yd%9i@7`?6^1pYM<8}vA
z(fcoCgsMf!oK2VWC%GQAgevYXL7o?Eii4GU?~V&J?0;;|X}e4MzW2UeoiA;v_Kja^
zfO*44nT%$s<HJ_iHD0JS+i49q+(`zs=pvVW8i+;xuYtKK!0_&IS4RuYlSNh0LB0N0
z@7M}4b%hGL51O*{(vrSeZ6D8OHCSs;@XmhzeVhf(Slk`m&D&IY@;78t2t{dNPCng^
zl3t`DCq?X(3hcH>ORIJ6{H~eR;2X%NKo&enSZ7_?BtrJ5+S7I!1*N++VP8<HIBoPS
zs4s)hk6=@{5NU`^H+?`wcP3Bej!F{iUVeW-Vmz5k<8mL=To^D!#+Hw%%ierPJ88H_
zPv82kH0g1Ai1s0S9toBo^Lh+BR#Ex!G~`x30&(~+!!jfFHn1X}Pg@a3JmuSLTQ#Qb
zpQ{H2%o6CZ4m_;3gUII{#r0Kl7wZMxrF?pq^i$O~lx>HQg7%WjlKr9^Cy2f+@^BqY
zbx<#R&U+j$A5c+HBI@EZBVkOHH&Z}NE>JzIVq7w@Q)x#`<VnX!98`B2r8m%6Vo+<#
z6|brd_*__wX0{t1GqA?_MGCa@sMxH?;yyPPF1TB!b^Hhn>~1g2KzO8);$a8uAH*&3
zg)D9M>q1*@_xCVo#(yS{1NMP%E6V?!Zdx45c`#Zo`Hos^`dDktCFvy1sVN@{zyDdY
z>><Z7B&4vz?kkf60-^cx)}7#;WUQ;|Ust^A{Cc6ps{`J_Ho33e7$a~vXbL1#t`aT!
z2UJ5oWg&|^mMJOh+0J)(WRFNE*ofb`(PH0t*QCEMv<$k$g`L*rpQiFCT-S{2>uUSm
zw<=5E{Hpn^91&*!WTH|0=HF?*gcfcA(20pesM@XX<znYR-nMzrF*R^)xxTPuJ-mhU
z$llE1dA!{69o)n5LZtfsGN@04B+k+hUE_rgg5;a&za<srs{J-<3Qy6+aIcv(Vh0~)
zkKgAXo_BfQU6|#09=7DXY~^inHrqTNHErF7_5Idg-n+BOIH|92e|zJ_nvaQy)}E~B
z(h@~J+X?{0YlgxkKbSHfz6PX3+q1^PZ8&z^?eZ~;#lzEVFypvJwzmp*NjFhor7Ydu
z;qg_Ml8d`7>U`!J{-r<=sz9Ex<rB%wndw8n3T-!>HqoW|-MF)wvnft=dI;3KrdhMf
zMAysew~LW;pSGKW3p2yd|KC%+rqf%cE><%ubiE&Jx1%0MZ=Vj7xf*$_KBZqWak)pv
z4j1_4XAlThcpZNinfEz(+YMJ<jd{>q^T3Cm4}mOujeA_~ly2A-OCo@BUWkDw$?;>`
zNAbhK1bj9N)%iBl%U+H3#(W(f7`9(~6|64(y#)u!7m=9$ls^wV6HaD*K=}$*?`*(r
z%PAmMv7h_OPY`2waY<I!<1y{9lkvg*S2VsV;C^W>H9yql*ma~+oMt}#AG;;>^x|`8
z#R49-yL6HlpGSwi9Z64GB2a6w($eJZ>gJ#mxlbpK{v}O&29pecI1p8Qp<h1SHvO4N
z_+F)%xO0841x)wd$&8Vw&1HJ3w?MV^H)!Ha$X1O>IO*|zpZSM6>*QdWiv2AWGUOWT
zi-U3Fb<QX6QPsrlDFCm9oEyVYRmw8*Eij=nt7ZU<rce$)Tpe9zp*)({+wiPnEysrt
z%KsJKDNEN+O_ku)jJ2#;k}_W1r057%=`a*slt2m_4Ow4Dxwv;-?t_o4?>G2;iM1t1
zHTq@j=TP}0C)-I{SAz4qYL-K^qweE9?(nlNI~&!^GA8sit}QIH$3qI@ShGe{waqKL
z$gP6l!{HMFCb=eGSRp?HQ$W^k5NfTr!FhVBHe2dKhrT@y7@j_LUMO2X!U<qQcl9^w
zAMYGS1h^`W*Fliy$>29w+j$DuOrED%X?afH7nQAm*uGMru4R&AA=<D2a2dhUa`0r@
zkTJbBK6OSuwLJ5|P9q(YMcV`M$U<Wo(*mXYZ8CH?GyY$Y{x{kJ@CmLnT3u;ei(W?I
zMzAO`+bv3<e%#6GvtLFB?dSqKV^E+x%tEbya&0sX)%=q7bl~KNG#gIFFumkEV<7hU
zq)iJq1xI5@jQ(S?U1mj9Smdun_!|Kx7{jS*z}2gF{sN8ft`X>R+<Q>}*9|j&!o)35
z{$bev7y}Xb>i>Ao|77I<=gZUAg;co|EjBB;+t~N>_f;{P9o0(>CsVsQIY)8(M+{Z0
zX0uI|msFKEtT~ttnsz7Q&HG#`N0?_r9`7GV%pEN$8bm$wuu-KbwUr2qDS>DJ*c!rf
zo^{1mo!8969ZL|;%-@E-i_s)2-OJ(P&$+jIm%hVOr64opW`*}ty|pQ4f6VyiOYbe#
zc=({mBPV?e10QS2MJS$rn8*$>vA(j}V^5F$v@VUb2^BbA=Q!jU&j8~69bkn$Rr&R-
zO%6w?WLzx_VTtLj2CV!KGIodUcx>y$1FafezYvGt?k~pa`aUwZ1UZA|ee$tkNv=Cc
z{JGZu?=XZZBj@Ofc4+btE(a9d-5DgAA*&B(**VS-x*~(_)GHAM5wR(${3Wbl#jKod
z%!O|u`G9Q+|2vP8d@VU)x3xNg57CaY!$@wqG0aZHEbB+A(>?I5v+>m<Uz;jVsLJ*J
zW~+@y6zO<$tl?|lNJMu4hC=%f7vE5WJWMT(IHLy3^({EaKP?YB7ke1l@pqa|SOJ6V
zP+$pl?BYl#$__WuF_p)}{q`1!uG%lf;Sa^0L}IxMpnos@Sn`)SbPo_}$YtIzMIKdC
zPs>vd6ZxC5y|K}HBV94S<<b$`HYa;Z!TZt^q6v86x58P{wkI2UoRXG>hZ~Pm)?ev(
zXVwAnw+Kn2g}4PvdewlLVqV+5V`7&VqCwG_bUp~XJRAD!ZJ?#2yhSQ*$+5}6kL+Ty
z7n`c?qP19mF#uIzF`@8+FFFm+?x5Zv7Kf||U6sF$ie@YBg?|s!O5Yd)@?QvRXPw9W
zzAFH=P#$oWOh*kT(7*Ed?XvkR4WNH}In6(}n`hUC2FjAX9nI&<5ll~Xlj0N(M~gM9
z7W;3xm?1qmFD1O@Yps*F!w=>vJEt4sE)}`;KqRl-pB?W8e==fRQHbNR&yXn9-CPzT
zX|2+4M8JL)^24fW-lP2u?B&<ST&l#FFZ)D-uFKJC<Kab1+ygzELfogXQQ&I#70tnM
zy54n{`>H0Fw|hk<)fQE<3!TG@ud#0no9o!?oNKC!@}4eEg2_~&7N3qT-Qsh9Iv>z{
zm)0<yr)u#7_;6@3bvjJz+ggqdL`H_^?hjYdPzWpB%A2F0&w3<JB_EHSqr-ppKXP7$
zrWt>;AauX_U`)J@pMV`1Q@7$z#}5b8W-NWwOd}B|VY?aWP5mhB2UD^`MzduiO()As
zi*rJP!fC{s1^J?Ot$QRN*3s2*LB2-Q@>P<~K2Ce@@ChWHB0qvX-#@OXT6O<z6!)t8
zuHHuvKO2MQPf~XiwS5gw^y}|f;*G`8qVqEEj|<{jf0-d9z;+?Hsd8<$bJw!TNAoog
z!lOHQ@wE`4mlgY=k-F55@ok?~VYgZ9ii?83DUY{@BQPW0Kt&6>3A?52TkfiF>Svqg
z?k5mH0g<X3N|2TzLCY-?>EQvDCi4-yJ&q_ZOB?^Ly!aEOJF0~0B(D@5kKF=wuhD|l
zU+C#Q8yn1*!P{yZ%n10gV=xIA)5(n8w~GulmX=Xr!2;1WoHvT$;rkC#$)4|!vFT+X
zw1r+D=B(0|$vmpR_ND*2G9vq;Sw=C};CZDWLZX{Kby1`C&o%_Y=2S+BH<R2XLYGSE
z_=^|+ssvIdqk*Vve*U?%e-cz*yJPIOZgw1c$H2N3J9pcuYz={bj%-@o*jDZLI~QwC
zBAzvlhUpVeBJ9G0MuPyI?ZP@V^Kz#H7sx;!p1xk4&&-S`|3LqHbLRJvK%QV=Qkb{S
zvFK<?FJ<lVt5;392rQqy5=su0>1Ji8iLbg#!*Kvdbu_1a%bzZ^ESUW(q;MjVZ0*f;
z!p?7bS9101myQ#T`rwFer2+tPS}~s>qQQ4@qljMnW0?dl0Z$d)m31QSYb~j2ibvAI
z#x<niUH!DZdzYp5SBs_*horD3f0JK!rz1mnfewB4Gb?v?I8aoYjvl{!QI?LHC9;+~
zoO4O`Ss;?Z^Aldl-U@c;ZGbzXt2gmFZFi(IS+89!*Lk<F@bP}#ZyFV(^jK1WN90`~
zt=Tthn9XCnm;+Qjz8G0Z>*7Ne;3SWus}*&Z1bGmhWqu<dAv#}%Gd(=ndllitwoRIo
z=Y;_o^88@Qse8?9I6Pwi)bibdeYC$Yfnv85*zhy4D|RdlSSDYL0)*rCoha8?w<DT&
z1A2C)NtZt0&W>)}@#IQP`74&+aOIqCHv=OPy;3=g?ZXcQU_r3<9`^sxN#N(Sl-g5+
zhm%cbigdiDjZN%d1~Qg0ODQFKeyoJR`kd#k|IXA-l{D|)&PM<Niw)F*#IwjCReL1}
zYT#Hf>PQn`j?{K~c<F;FKn7kjrJhC8ZhL_tqV0FFyv`9W-^|cIJ!3w5CB}a^^%s2A
z!kZ-9CkOI{{doQP-#T1pWlE_zQTCS9g~NcX{+SG4b?_OC`xuy3j+4X;3IK1etFU|_
zwU)#L2MPfH`45d!QU<#gu>th)=$7BR;X|@wqUv5<r@H;<-%;IVy_9xGyk!FH?40`i
zh&xk1X(J4^;^f7B!0d@?mW)-O{}o#QN$MY^K{-1A05(IRQ<dU{w)@%ijcKn;(QdbU
zS>2MQW2XvUa)ii)_u`-rnYHKB?wPOvE8o>{*St4#(@XuD6t}M<Kjr}^p&@SEy-a^s
zicMrbiSmDPIzRp-EIO&}#9Z*`{%WHma(;pwaXmQj(l?ztiZhz)?1y!o?2<o%oYP^B
z6=Bgzb0(P_rjGYJ4x0Ex{g{L_v_D*Sp*kJ(f4vqey-LLa(*Ttf96(dRO5oVI*kvHS
z)Yrni5#mxk52&L1ST~|zsG-JRTfTf6_;CA&S~zwWFHy*R*chhF3+&o6)p-`N@F9?l
zoSB%vtJ+66h^$SOipE>?*&Oc(2)=DpfDruZ?u)O3FB}0j^bIi0vt%bB26EIJ=b_`j
zOA1%H`Vt?X?rOD8woVkiMxan81My~V*uaT99~-NAswewgQT>020z-bjLUXyB$=(5F
z9G~s*y0#nZkD*LO`6f}2YVh8EaNq&r+Ak|aWUE>bp(T*mSAqFG%OgQ+P>a@EZ6~h^
z>o?rr#(V;ElS_BiX$tkX(wtspX6DCW{Fg{%=6j`jPqn|>OY@nhl4Zk*<q)K-4WtE2
zT=Xw+#p}(Eb7^W#JwAPHY`QOYdJj{syXN6!1lUnlx{1dr@tqdHzW4wjf0jn517Qdg
z=!?1^@thZ2vBvf)uiJyS<5q(c)qhhM#%1R}>Uml%abT1~`U|=XaVE#c%g7PeQvGo0
z)-=6kkfAb6jV(L}fX;C^-057|Q>o|d{FD#WUvE&jnVy&A0k!CR%(MCH2e^R#JaS_N
znggoLNCg_gLo2g1SejKFNA;^kwYJ$B9v)jOBm2@Ez1!lKMa;9uhM-!^XPe#-5Da_T
z&m`v{tLN!0^5385dIR!-r_<Mz`Kp^bCju;?82igI@{uap{k-ljoM?_CwNSE!ijVV0
zz3^eE&kIb4-5Snu?08)+a0#C*>;Y-^pa!G+!0pq(t;w3<q&Bj#lW>Mmesfu0*hRc!
z9+d~O{*%Db-?Y1~yh*E<m_qESjvJr`{%e1IS9+h$W$(57K`FKllA9RK+##=SwgngC
zEztt?2qCD<Mnjl+!{OwtG*ENSHW;<0Z9W(_c)JW{tnWY8)wyTyk2BfSs+*cg7X2EQ
z=d9!RQ!e9TV3MPe5(d$xXXIzg%MsRqLI|_E<WHe8nFI9>+r4Eij&q(H_&ItXP8kY0
zhglRO!te5?*<|T1*jqku^}AWsT}=UkmNZ?_-w6}<0=A6MGLhUG6ZHH2?K<P9jEQ}8
zDC&66za{7|^II6Mi%l4p#)<PZPsg3p@u<d2FBtkyiJhz@lgzafkLJ#UM3Wkm?;XTj
zmT!p+XUhU%EmKC<2#;9CaPjnKoFz;fD2UKSp1>Vu{yM{NH3}k_`}6Qyb0P^HP783l
zsV!U7SEgrT(W^G`bA^LWUP5e($^kB;9^Du?Kna&UdyvR;Wg6I|skPDw-YJr4w#ER(
znm0{dZBp;MSFJjxQVq*<YpI?-@nYFvH8Z-zqQ4`s2@8mGHbH9ELNAkL)kb@!ZvOzL
zbaE~m)6AOw^82--vSzn$W^!$Licpx+R^5ALo10FnjySnP4)afW9Ejf9@0+$`DLTa1
zH`e)E4e_21xXsPBr%mY(v^fmgTT&&@_u<6rf17?ToV8FwGlSDB1?s>OEw3~CeL_5B
zXD#8)VY7!#1e-|^Uc=Q>)#3wU7FH2@(uewe0EqooU%ubdPph|-Zb{6lZ$-_+c=Fu$
z6$Wz0#!NBZb&#$q9@yuSlAOHCLTk97!#j{y#Pj;7dm7`?qvAWeS>%51QL`21@+god
zr-pamJ8Ep7Y5(wTr=3<(`G1$X<Jg6Mdr)LDm=W=YXEqk0J%gk~N1(175Fo?^mDiec
zM!sZqrY0JrI6@L<(R4uPysw!?#(=sMP};O-=5t2qzi1Q!!exVOpqdSv9IMm3MDf9y
zuD5@Fv(3pxMvK>!09T}tA7WAoy;OJj-=}>aRYYTSwU-{%bR=a0zf6?!E=9~z(>@6&
zK8C=U>}FrAk$gC=0rbZ&^TqERW<P)XLdr+5L|<EF)G7sjxbCO{#0Q@#47%PgmKZ=3
z{#$yRkDr5LjjD42;*<2=GR{(ean|!S`bG5m{QY(6P(ZIo*^`Hp{Z$X3(?(%!(@IPh
zS(4dY1Z)srZKK^fSh_<tsh*Vy<*<C9z#oj^8y;D|LHPEHTZ7SL?TeV#u?h0|JxM+F
z&v$a-Cm}G-mJe0>S58vXkI_a<dWy~KlD|J@-8tEqdfE`m;leCV4yK19wqxDYYM##e
zpA+IgG$D#dULW#0qAVl*HY$G&UF|!Im(?`qu;GVQWCXSgr075=y$@$)BfPSPQP`6|
zmkxU2MMw5&0g6{+u6G1DibM`6IA9M_94K+Hl3+~%XeZ%rpotU5r(X{R0jrbdfAqT9
zpnHFA+gctLP7gX6g{}tQ-p1!$-ZxzoaYY-zy(yIbD43H}_9niN20+k%wYhBhaUy~a
zogDY>^k#-ahKEh#r<;;>HWpeIB#Hg91m44lI^)OV>+6|oWTMHiMVf~DxxLd%!zj=S
zpkh(X{r2$k&`JB)d4s8sKY94&!OMIc0Wwk9$@`W)7}h?)^1ln8<=Nkg*hiLE-ASh1
z#JxLb_z8neh`oAU$Z!1k%|-|OK|tqCp=r0pn?ez<JMjL%A9Ps)>6LkUH%{PifZBg>
zCU|i5;<{*hMp}gt1~raLsrM+_UiP#R8v9x7jZ=rGn%OV;+t0WesG8>QBy9_Y_t~Zl
zI^~ok8{%#h2=bz$9n<5{@-Uw~H_y|6Le!wL4de)@>mmY=4n`dYz0}{_)>{s=YFwOM
zEl#?tC;@{231|1ZA8T%#4%kgr<NrIAVV3z{mQQR4f;-v`U0kxg^_FJ7eQ^{t-SV8y
zXm3N_iycbP9)oj|ix20U7BkXB+=cW-_0%QaOj|zyF*)}*)4tJ#-W!cbMM=t4zCCQp
zgJtNsV6X8Jtht!{zR@NyDX4FCb%BJYp|$utVtWfdqZeU2EbI1(r&uwtRXrqtYFOzB
zmXBU42b3lAKw;WVR{Az13Sfx8QU76x+49QGBSXAKJ;z{sLe}vrhwve$A28WZ?T0jZ
zl40o%_w8W`%%vOGY}C#$guce=W?{is)$3f64ji=tEC9M5H4%Kq&iJkIu;J2SIqq_p
zET#ZpEg<6wtS&1kL~O^oePwi--?(*H8i>@5m)l!C{Y+^qt%3m}fK@pR4zx&~-%Tn4
z3K&qP%<@>;9FXw4t=Pm@W5{x9VwAO)YuI~E2Q3T!s;_x!IYW#neb^pe)?OB5PfB<}
z=Cd?cb3=Ixf<5(D=sJI!eC=YhU4t3sT0_3%9obKJoO19m`$zf=$Z#dp7+{b|Z2r6y
z59t+iJEcZ|3Uo|#`Ca5`Dm8`zLebx_L_eU{g%($mR%g(AUWX>81#~y-+@2DhAxvM6
zi6W)IZMj0jhJJwfS%`LLop4suSKKl+eB<7+(BjN;fZ|r}%^t`{Md5%XK38MZ+U45B
zJ9wx4WlMja@ZtmP6zl7Lujh~V_yii*S}FWl?=Y<?z$7t%iq8ao)mYO-TKv7)>JHXS
zw*82~hH+$dcE1D^C^9^n@|R9syt#gfU6_0MUUmp_YUkc}l70g#@{)V3^x;iyMfwnm
zYA3a_=MD~U15x7*SMra9r4;bx$!CXWCye}&Pl~tvtI~34_NX0=!BN6ix`(Ce5`EOg
z)b=P~s3cD-LZ6J7-vx!vMCHfi3s-ysvEc5wa^C*XQbliv&wm#^vna_)&kp-03=U|&
z2G75Ybua2_)XsEv-FxuMG7JUa1bo}yJFg74OUMK?s9fz0IW^%ct)`lUc>!S=v%>u+
zoEABdTY;uWk*%G0?uFLRoSTD0pxP2mCI1M=hH42X)y&61S)UJ(Cw}21G$v}NTbx#9
zAWe(#@gYCzR|HL~0gxM}f@k1Sxoc7WnuEFXD+aoYlZQ~Ft472{lV*0DXxFhkiB784
zj&g*o=d0(m1tOX>K3a&hh`bvh_95};V}22-4}OCI(8X7<5f}o0$w=mJ;a#j!Hv$Py
z_7_0g_Fu-G3Az{&ygJ&?9K>{cau|F1&QBwt{)yx}1EAXeTLI{RkxWjvn?h|I+p#2&
z<Xj1j$#p-G`2F7-7Oy@#HQ>u>pqhEp8MN@z@L(k~ZHWAb?ZPr(Py<vG%Rj#bSgrG3
z(usssK#OWmk;PvA?+tE$JN8_JmBy4s^Uiz%na6R@KrwAWV?aUsk75bJS4Gg~egJ*#
zSDa_`l~#l`k$j0c`QPsY@KkZ7vT<6i-TTsE48EmAeu}duN`zwnBLgy|<gd-bfC5FE
z{3M3~nsM_cog)H<z*Sx#&h+0(z$loBLw_SttNw(-vrb`+(~6Y+5`3PnF8*UFBq4_q
z<$DKVi-OB)H;g%mf&Rb7VFr(8X7%CSX2-g6$-JU;*(}_lTe2NK`NW8{pdurrEc>yl
zpAn6^FL**iwePkySaJh__2YenuX%leBxJK4tI^K2n?C0{PWFefIDAg{YtaHx8Cbgk
zdsu>nL=N`q@rz#zQ44E!C)~(q=KmZGlNtq1e?fp_VZgyJumhMN{?$z5>6l%n3#s1?
zcONTLrjo|MCINwc=QwdFg5)TOpogInYC>Nj1AH)$2X+Dz;1hO^?L^wXs&oCS_v$gt
z0G|`eTFC1&5aNX1G9muYlVY?Wo0|w)c7;t1HL+EJf!^Odlu=z|U;lZ)B1Q^<h3o~`
zToQEu8aX%m_jYv%btD5X+cG`h!a`eYYggyE2sbAeeSH5r9ISQ&{5QY@@|HBO7CDXV
zU4XN1TjLC6`7-@|FubU*x=o+JI2r<Vfs&ns_yqAMH?O%)%+Mvnvvy#W!G?&M0bl<8
zK|y}2sJZ5>wU-aRY~+ml^&eVVBHKFg1-zihJBIpv_JqBxY#0+G3kGV$kFDS}dQ@vK
zF-`tD4=;WvHDcFrSO}_D%dtATihK+NQo&u{)PMz&O*cNVRWvYg`Rpa;<06eN`3T#A
z$qc=d-i}#wgd`NgLSaVss6q(h%;bv<T7~#hipwiK2?OLNB<XB=lzx#_5GE#to4{h_
zPJ=w#$|Pq61S!!1nompJ2c=`dGOzI^|Ip3UgNHM(Q}VC>kgMr|IpWoowe<AD>D3H2
zcw(W@!Ka^kFyj0jT0Q%I=pd2O-pi=F6Lhj1JXJTR@DN2&`MHAHKQU39LKv^I;DF6$
znN+CVjZD>G$ezHFAOWeWbzNZvm)l*!VQDtFXz;5$bArquU!@tBiV*&}zkrn1^2H{H
z3$+Y|SPU3KGCPnFv;!=`e`8`IR4#pm9h&mi_VSW#ZS4ab2P%Ldu~y2q1_~rOL9f4a
zLZP}!Jx1I1s3F&zo8p=5Om9XD_qZllQWrFD$lp*VwfA`9>q1^C6UexQ%5e6Y?<%Bu
z;fqL%n`XzKoETaYyGDqIFg1%353Q}kGi56)L8$D`W`xBi4<69M!aMFB4L3wkS(uJO
z$LJsHtP6yIDZ=4TqWo0)1R)10M7dm}0FD|gWz2p`8bBE9>ai;MvEJ)#pt2M;9Oy!f
z0k@NmPFu~hus$|gFuJqrT|T=VWdPyi{?EqLT*h46fEWQ^IEF&#+q^G)E)Zw7oQ+>{
zUi_4~?LCh8S`aor&A<}ksb9}_fx}k?CAj|GQ&h$Z3GYUkG~N&brlmBYB9dz=K$#`Z
z1P@Y;q-JGfrc0xym-g^&pFz6z{~D?zl?j^U{<Iz(#g`)=x*;ySIsX+np-F)AGT>Ej
z0Y1O9(ZS!y&H;jmE`tqD2Bt*3uAUFhSLS#h*P96by>%_y<g==G#9Yj;(9=^z9(dwV
z9Z)7{GZjplq#dVIJTnc>%+G!Sl}XXznHOY;0Uq9Nw1#%VP5{Kl2yD(K@pgoso>~3U
zJ#h~aDkGDT{|Ek6fVz7^A1|K}TRIJ8SX+-iu-1^@>ysXKM*N#G^+rChC|m|6+rIvO
zJQd>SIUXHGN5=lot!Ka2C~rB}(eUpKAq-56J}_LVx41c`n=`d8%J&jRt2=QqQIfN$
z2JEMJz?MM0VAc{|sOlBzC;yCF_!QMYbajrEdo3MxoZxT7swhMX#0bN$e7QAL@dT*n
zcT`cZ^eg;HZ$_pqHShPaHsAO{N<u|QLd7MXZTa6X*W>APbHN*LgQMg1-PEdGxRGg0
z!8%}2MSq8;hg)R3$UG5<mR1S!1bU16g~Ptcm9r@)OB>;XDg!>0sMTPD5&DiPdIllP
zK&^aDWa-~~)8DeCukYcBo<zT0<#;8eSMWTlA~5RWS>NoJq_vp#oCyM;brmBD_Kc!t
z<>jugH&wZL5x}AO^%;!PV70LNos_y^p~=|HW9MwpKkJ}pTtACeZvK|Q^!|g&^IG#5
zO7p|#b9L?eQ3qK6cR<|8Pk#oCwIO%dof@PRRIs4P4&cV6AKNVvTN0a$msX75wSxEV
zn@rUy%@@2fJ=cQ?J>(M|FGl;Jnu@<!7ra^d(e`T6T7G~S99PzrNo&$unjbar=-5Oc
zfsy67s5NO#Kc-`K%H5P8r^E_knSOa}or+QZ-GAawZ`MYMLl-1$L6e{JWAjTzMjcL1
z{aW1cb_#gYo1;>YDDAGW2ww&;?j{a9pwpVx-5}e_%HXMtr8VDVV=lO!%uUi~gbrhc
zg(8`23e=y-$QS}exmcZq#$OM2XR5x+$?veJ?r*NNZz4GWcUq&sj|&MbU_T|oj~y^)
z0PiNvVFwaJp>>q-Z=$L)BKu6X>||wrg)!6af3HuIR$~oO(KtU%Wn^U1h^Q|e%|Y3F
z%Dh}Vvo0omUdgq4_H9vtPUC~h7}uXH4&u6C@uOQbQ^tEQk&H}<FZ+A3@x#4r3@_HA
zqG(OwS2<2-bH0=|`#4WHzTKabBs_NJDL#PB*(*aB%}Ep;(ccD60zE+?Ne2AN8FB#k
zDx5BZ6h7fT$0r>sQ{hjYN1Z`FcQ=ll(je}j{KJC%7gAlEXETwuzuro^QRcM{w8f^N
ziL%8e$ET;op7o8SFbhw45s^};4{W+#t2-Dl6y~N=vrd=J1v31Q=sLdHd^WuYAZTvJ
zbtRt)b<w>7(UvC9@SAQ|wj1MdV+^D;-pls)0WsZM*BUEDYAekM(n<5l`Jnm2y-nGm
ztbx?V02efQuA;0(icKgT8U1!iER)%Thd^=&AXIL6U3vww_VTLNMV>y$II*UpFZ0TK
zX8WH`5gk3b=G$Rwp(zU}TJ;-nt%JOPHcm{+W|nPmdW*-Rt$qYsgZ7IC!)NE$HsT7<
zeBg;xz$T`=nEC@HR{5v|u_N_z<!7k_0zj2KSEi!_LVN@Dh4yimuEcoO>&Lb0OCU|?
zLz0f<qLs(15}0Yo=o28*TnY;P3|prezp0V2g}fdx_xPDF1<?c(JTfiuV}JhnT+vGz
zf=>{VdbCDiV6iO@w@%eGM&C7ojUSr=?8sK-8KYg)pQ*`rOyP9Tz$FDJ$C0j^3cWfY
z@6Xg?51`Gz6mTWVE^_yH2hayc=ZW89TpnJoGH!Gn-`~C#DlAVxL-4yG*5YSBo8jOV
zsH0rCm_A3OqPRvWeS8BQ5mTvtNgVn$D+6XBGob?EO>csR$}+PNeUDps@D&vYye86?
z+ehi;rQ5@jxScJRJCRwY5nlAgpp~wt-zggEqK98k9RpL&%a+CkL57L;$U+9(vQ{Mp
zvB+l}K>;*!*PQr~5dRpMud*Vzsj7U~q_Wb^?qk+EVms`mFOBg|sKX33=+CIA$i|vQ
zQa#5jY1f;Spc#J`Hw!zhAGtn^{6wG}e4ph@7dL2*O6--g-Q{U_GLRyfpbUi@Mx$OK
z69&2MA}f9wX)si15G&J`fZMgMcOeL~;a*91cp^7Do13j=<??Jgs?_cT^SdNeMI$D;
z`x4_7{XQT#Ga{r@Uf0yv6`syQToO=eY`_xWfQ`6|CX%h(>nnNs{D}O+7LVkp$i(RW
zsrSD#Lm}fH$pfF*h+fJaq_7n<z23KxD~=lH3=lU|uucoeBGW`sg7o3;{BD!P7l~{Q
zY-M|^6XcxN*&~my05NaGB77BqmnPwE8lz;w$nYC?a#D&-{y=xEs?yW1qfBIqyTU#^
zFVF2Z(8Eh@>7tvBg<NNxv&s`t;Ew3s4^CvI6h$OWc)o@NolQuKLXHNk08jI4&tlB0
zo(4i#2jy|h_6n<XOJR@FORTdI_Zgw5z<l5wJJ9gGz54E0QY)hHOAA^i5Il%>8Xnw9
zH&&u6#Nb8kQ=J+aN&D<y0?-*Sf1X`B%0|})Zvfc?&<Oz2T_LNcT%6V9m9noU_~hA6
zY~Vk}5P9@}@`7qSr|@!HN8lPgE}9hYQLEC467X0ta4&Gq2uK^MM3J91R;j*fUetM)
z3j5IJP<i_khZbiAb>~lb*qH^$ucqO@0G{$D54LvVa(8(^_QCB}YAQv1e}IgPOkag@
z_YdzR>1aCLdIv^kW;q6YTr@9AdU|@|I+v5R)>cv5-6v@onYk*{;nj{nLyWaC(_op5
z*?KkC5L6Vb<<PIWE@m`zyu4SPAw>OgELGLjgz@Y$RGql0q(>h=Q?_)+u8imie~DZ3
z1t@?WQ{md$8gL@Z^X{O=&CTt2D+8B^sOEET)KIFRU+Z6yuCcMxllAWM3gq;*&*tWg
z70k3he*6HA=~#~E4t9l+1*=8|L!n6=#$CQhXpN1He{zPSB2z!k-d%O|d>ziD;o2T*
zag!=pvnceJI2n<YGcnn!v)^{RIxNY`qG2_R5r)z-ndOm3*EN*}_-E#C0PVO~KnwAH
zxR^fM9uDR>M(Z`I$jI55saT&VP)Qu<6C@Ld3?}m)Ej2YHCMJGb>&r_Dg7&Z1x!lP@
zWmJa0^+Ht_-R@mCCirFPosV9Vkmrhn4TU3&f}whECtjH<x)S0gPD?1<0Ifx3aUT%q
zEgPH7Shlpt{V`%sZgFu`2k3R7T8Y-h{&bo5)8k6j-@jk&L=5F6ko=kuKC;l3=0@QY
z$O*XJp4@nx>~x_*QO{iQWg)$t)cyXjam-!$_2%6d7eujje)F=PCoFeBFrj&)3cB11
zyOnqY4o#FUy3*J2#Cnb7F!*)h!Ec#ZUC3zfWZ!v%0s-EX&6~nlwinHR9~oNMH=zSz
zcV2GxWFMQEA&$dUr$vC>ZpQ1!vFUql4J015JUt#RHV9EhB&ZhT13YegeB97Vy;R2s
z#H!!y@i3)pg=nmzO+PXguwS#qqBWMM-@;=xA5JRhb(8da-uXy&xThXi;cS&@(cWHA
zt0JKqT1RDN<x9=DxVYP!n<kGNT)oZn-SOika&mIfoIftq$jHdNHcQ!~X2Qb4$4u-4
zy}i5kV6nWH%R|2{r_V1gioD4Za!CUOB?&qRU9wM<>!|yfJ98dkP=!wj>TN{4Y0Z@m
zrx{$FjehN|8a4W6+nYqkGBV2v8oFK?3g}+9UD#bj_O2^$6Z|!i0ze9Sk3&n3<@g`o
zf8Yo>8EVITD-~Ks#!$$l@(xVF_YLS5&sAG#o0;td;n3Wk?;`4Be;C<@`KB>bQ?CK8
z0=WKsgY!}5$H0}RGa}}hUsl~J@)X}DXZxp32NI`?oR6lg=FrLbEmp?}$f^sGr6h)v
zMOuLNPk4AZE$y1S>I-D#cJ23ETr|JoACrYW1sW4$V(_sE?lT-69c#P>+Wb(Q0Vi}l
z+hWnK)@kwjz|Wtk@uJdVvhea?zC#3S2ldCna?A46R2((a3=b_WZJS%Y^ARRze{b)b
zxK0LDz-i>8e&9~h{w8uWsjdh<AK9s;r#cFg2m(?V86}?g-HoMDxnH0St6)ocegeL#
zmI;rC?c-9_zT&S?tCU37zxlO)=7bp|5uRPeVtP4-QAMlz>+b3*c=rb1KVKBFTwzDo
zU?Y-7%HShb;k6C~9T`y|jq-z=s9<bzGMW`?NT)AduKv@b;1$)_d!8qc>GYiF<Yb$S
zuKxHE?HVA;f4<m3jkB1qKG^7uPEAeCL`aS}K0XG3VK{|9nlECstIK3(Br}AFt-8AU
zN4g;XM{)6R3PB#1V}ox5b!2!F7wZusLy275K)4$4iC09yeBb*a7>a4!q<wJb<UAhj
zkRc72zu5jcV8w}b{n`v0tSRVjv6uWqqO)scXM-zW6jJAUgH!R!^@f~+M%Jv5vU$u;
zS_$lAO$ma$^;sP)ZuGFzH(CS`H!&#)RSxlpI4MCPRlujHkU!BEn?QqJP>>8bf;raN
z-j1N>OI>(+YNtWwVsyArcdYW7FtD}Uu;a&IV#{%2+|V|x^4quHwkO%6xPnf9YmGXg
zfBrzD;Z~pCsh578EF>sC0QOtSC*Cg&E9UHcSLG*mM7JNjZi5rjIQ9}XE<XN?GECXd
zt}a{xaY%Orm7=^nEfcmfq)e|#Mpm}L^Nz<u1sL}`N6Z1fq$^AV1~rOjbN?99%ci&v
zHf3bRpawRb&&)51gyg7%qE{e@DX_EJ@xtiy7Zi}h^0dqP#sQV0qVy*j!_S{pX_+jE
z6nAPE6m^P$&H<B3Y`)ji!xiw_UV}IKCy=hL=k8d}#~<jn_Vz{Ra;PsEnXXA8FCOG;
ztQR2=Nb3t692{ULY@P#O<mvuwYcM%D{xu>Shxy()%CNo{D^qLVtluCb@p}tMy09k#
zB4S%mZf>qho&v=OH*N=rp!1<WGMYe%Y&@&jI3gxuXZzFL#Xhh3*js)5<p>)Ua`wRj
zmAsYtiK!_%CjWfy_wNn4Bp|Q-^B=F*v98S*8eQ?4#YQMychIs@z^}m^E(F7}_cwB)
zMsJ)T>2R<<HijNHhR~p#58h{wYY*EJsra#BMe33~<2_v*tc<ho*eAGNXOn{4rV293
zUxH{$fI~({&3Bm97l@Bk-#QYxOvS~;3ui@Tq0k<{&E|fYBc>+i<>h7Px6+o61`;7D
z2I;Rn?atR6LEi(XT=L<7EOCvvbAN;Onja4j@A?g;pwn02ElB6Xh1qH=vPOx|pWlW_
zBIfxf23^4k-`yRxsH&>2-cd72XfRI!HqVsu?+O9VD^^xjMGMvZ#8wR<WLe3BU$O$i
z=I-jKx5JotGZY~h^*);@QDjZ*?cr?}9IVp$3aB|g4fkP&gwtTLMZ)UuMN{LV;`Ehb
z;u5p0KEIkzw~*NUdw>OV`(nnb`R_JI>w3Q*002();%M1>rrfZcX~+E&m?LpuzQ*Qb
z^68DNXvYihI&7_59S9*+y8Pza8t~SpI(A+}1Xi&<fQAN2-zGD}{D7BI;XxW)1GH+y
z<m3wgLWYs?cK!K-O+Z~&S9f)^i~<(3k%GJgM@o$b{cLzN7#z{O+?%vKUTIrhT^-?s
zN*Tnkp}sA2314x2ZF!UIzp<8U-$yl~M6aUbevX?G6C1rxM(%Y1?&Nm|+$<N>M3dir
z!KF|&HXkToogRWsggy{#342>g;Qy24KB+=}qF_-v?2dhzt^D$EdqD$2TCR(WQwzkT
z0DzR<RhK<m=k+mGSg{P`dsv96CJEJ4wb>{PNY5XOoY%WBSmV)BM}Rby8Si$nN6<)Z
zYlP(AW`Iu4_YJ@%YinzXfKSTGV?Kx|qAs_$w-PyS;N6{_V;3PZGP0fb^onWdMLCW3
zp{Ei)5=dUBGHk9CNy96d`NBTf1Rl0hy4{1k3@sTWf((D#AGV`lQRG-;RMKET2+?uN
z@Vd!F{$(_JLSR}tUw5<MrgoBYC*TJw<QyX;2<c4XHXplM_Fisu1?o<0AU1GlB<~-t
zmZMBrv0p`m(Wl7+X&dhPlh0~K6$$6(p1-qICB?-Cj4tyHP6vBSO?P{fMVWy#&R|~!
zC%_k*J@4`q)7!C98N?f#n!3X&(9-;-p!ptP2>UCM(*Ah1r{fN+5tvU=5C`#>5WwL+
zt$Ugo#UTLob1Nc?Zh8j0nsE2fV#5!ZFNQ2Xj?e4lUf<IFEiRVc6Gu3Z>X&R5ChQ*-
z6(`@}5dm&T$5`0dDCFpPvFvq+K}thJM0CCV1J=^=1SE!~<fK_|51!b}fP?DAJAwP#
z`GGn#y%sJyQ0&hE7gGbc)9*D+-cMenC2L^S<1itQ>*M{h765d)i1*h+g7C=51i$p*
zn-y|%bBoFzX9ZrOB?-BxAE!y@OiDnGcm31HQuyrw*A1KoGg|$VC2vFaZt({Du{xRR
zzdg+Y6@-njyW?hL*NyuyQ?pCH?c?|f`*oK}NfDKeh^_Pi(sk&It_~dyB|8raAUBYh
zhoB-X)9++|48)9rA$$<6`eJNcWxZH$3wRGXANDW!GIxN4f6u@!YlU_|OfFd?-s`bw
z*KG}_c|R=u-d}ms@e+*mLyC5EcSJ$V^lWeP-5RrmQV_sjXLg1~o;<D&DNdLqu06aU
zkck}G_^sh|5n#>0hJ}-GZLPHVO-)T5Fa7bepkty2u-EhU9G=F)+`O$NrxprMV)&U)
zt#SXZRMR#k*Z%CS?`?<-rWi2k>n|apq37r4pE(o%uu(>IhlGb?zI^%Jikl<%htK=#
z>uc->4BFn_-sa|J1GL^$n+!tMcrq#~tg=lYOb-t!NlBB^()2Vm@bPiv`FeZi#AK(B
z57)P+4~1(V%3*iN<U$^(s38DWiZVqJIkxq6w6_~rjg$t<K4E!Sl8}%9qbw~g9gDLg
zFX4XD61p?aIPoQrY5w?9gB{>9?CeUFuD*|Ke0;=9T#fTxEf23Hx4`&dj#}!#jWrxB
zSkl;FG|<yg7FPh#2EzM*I>(Ds-eIb!LIHhFPZ;G#Fd)y7@<OQ#uMvFIURwHVz0FyA
zAqtKh;m<iEWSe)sci{7rCd}eIJ8T-!s*=7)yDgI7i3i%(_^K>XDRGB?FM4T27~baO
z#-5zKunqkRV}POdZ|XY^>O8RqE88Gs<bN`AT_9x93Z)e3WfKm_|DIF&!9&1gZG*OG
zI*HGfj%aF)|1(3O*4y~hBRqUbKvQXp<j|qia}0@;#|J^cuA5qKTm@EdV%+fHKp^0l
z6mH)6P*uD!y}V|%NmFE&b_p{Qa54}_Pulzwgc(q&Ydsn<bpYwle1QR)9~BaiS$98k
zpX)@2^c_YWiBFKKa@*JAahu}WKUM601Q*AYh5kqlJYNEkuScSoQx_P4qEr*;!wAU*
zL`nlQkSE3`c*V#R(c?m)QUtu4&Z<$ZygXNd83%O1e#-(<LDoOo-dirt>*xA3guy>w
z847wcz^RTLp=?767~m!NVsHFtB9;s|&_vE-F<@-f#AgEkMFRskCcrwve)B@zIf3ad
zQ+3cgFJE@#@dWToFsQsQ9i>uX)>LUv9uau{o5Jb?FG>Lmhi-*bqB1SZ!>wo?rFbVm
zy`5z3)X_6@5PDwu9a05<y3Uz@8@B?!IE2!?F^k8XD7A{=A{QPC^<TKyCMU0Zx=u_3
zUdo<#?)e}T-d588a0-U}4iRMt&CAo^s|N#`^5);j)c$rqNJ3YHcu*f*g_)mNlmc-w
zuoelE@}owNdA<dRx4X8VRt$3e6l;u472T&aIh?qpDvOR>;B9juw?jKK3!X2Z<$=iw
z05YbN^%Bs7h>D79V|)5+?9;|A4onVtG{rT^c0?V#_sQyHm?_LCKF?Dv9`7v(DVh?;
zwu+GTaIEC6bKb&n20jQ@=-BL%z{D+3T7KP<*Kf=oh8KXX`n9<=tj*HR`Nq=2DLGI0
zv_C9%I{hsO((3L$ZL5-taqGOJlIpxsP6`~kaTFCdoTSV>MMXEPI6(<A{|jtVP@a2_
z6;%d9LMH)c9Tmr;G`B;3jHX@tHcW<*$@^Z$`M4YhFK?LL?i;<-)C+vo5=1ftElxi`
z^9TB4oRv=vj4a6Ge8674xuDM!Eq~M<8_s)}PeJ9|Phd=sSMX+KdQBbXx;8dx?R}Y2
zXAo&D%BT4Rcv}5i7OwfJ$>@JY3pa~;(brxX_`pz+-r(8s5Sv<4cka=UeA2MI$2xC)
ztcTm5if12%&wj0yn1N#8PvQLD{W`(4!-~j}C6Dwq(y*xhD4L+{@)e;d;h(6~1r-11
zoJL^C@d^Yu<ajMG?yi4@`rg>U8XBWx_SOh0()gsYHszJ2(+Js)i|}!hw(d}t3bPW#
z@zo~=q1^fo$dXTHo$K|ExLlUxBj{p4#JO3`L)3{eCwwAB%BwDw?S-dfe!Ft(bfBkN
zQ;us6?+G0NNHrc1SfvZh|LI|@M#m+x0ICkR%!Ur+1j$#Ma+b+Wx>x?tH8|`eY1vxW
zS#(;bhxbH$Iey#n^#8}yR|ZrSHSJ1=bfZY;p^@%7bf<JTlF}t04bmmuB_g17NH<6c
zNOwth-^KgA-@W%YoW1v|nOV=w^Nhry_ofOW4?FmR2pQ_ZVH4eEjT<Z|z;tvu;4sxq
zUcGf;f#~M_26(516DjzLIDo$)lnlF<JhUf#$NRljI`*oyJ2#VmDNBX|>^gREQSoRe
zkIbP)iB+WETB|K%iy^#OzK~`m=v~LxaH9-ibWzxP^kUxF?-EW(p(OI<xrdTR)ySyB
zLN)vFoEuH1$%;`?&1#O>@QY6<pYp}`6ztnpKGGC;S){=J%{*PUl~iW>I`sY=4;D}J
zje74kT~V?6b9$u2(bhZV8GwA~Z!GoYkUQAzDf9eTepz@T{Aufy(2nlBk@$AzC)Uc0
zYalt@waD>V`p3GG`;zwXKr&W~4qCX#^3T|jl5>q-DN344S$`%5gjg65Kz_pJ2Vn0c
zL_rC&-txSn=2~sPEkX)rj2vFy|5Obiv!yGOr8CQK<MNruoZgc@x1_aGBS*XY%QWwK
zl>G7kaynkT%q`s`br;J^OeOnoCL$>%5~T9fJ_|-c$eYhU8QijGaLT<Yd(8^_F6=9j
zyR2ee2q-o$_h|t3<v*5n#RQ^YCY24fNPOoz%ze<tlc*-W*V{}#`u0h`UBRM}5*?~}
zm6Uu^(f(y{ZeHZS85kD`zNYY#gjB@8>S)%MwFDcip1djSLfY?OwLgQ^ws55fI5QY1
zKZWdb#s>U<vWzfRxNy=-D6B~jyB>TQ94K{s1L^?nj|>+j@BoB+eed#&Fn%f1&`6_A
z4<9z=*52i2qA%wU)mFm+j`lyuyvbL=dlS=FR4$C=6D}qUOGQOuwGVy?7MvM+#rh(e
z|6RCZ4Ue?Jo_P@(W{KywTLNNHV03<}KVSAa><MS_Qu;aXgdm49IkkHPgFN`;Xcc;M
zO_0&+?Rg6kR{h_fI0mH={v-BhfUemnJb?QHw=z|4NH4ZBqayeTW@=xp+gbi~M0e*n
zGd*Qf3klfMg`|!6(@>vYoq3JfmdFzJ3we9)qc|@Y8SiROT^nGtd<F-v+bCAasU!1c
zT7tyqNEUVj<GnZ3H7sCP@xy-58S2n%dZv||B=j*~$upa-4&Z_6wUQS7xVTK+n9|JF
z2lZoHNc1^ee$$8Dgp7=gX2G6;o`d4g)9P?~ph7@>hL@KY><OYgm87B3Dk+V+Z-((F
zoX^v0yL#fOMMTpt@xI`ym|zWM^JQc?3%1|2imsOB!J6y|E(-6k2&XuxJRl`1lIOc8
z*48)Fk0g6Ud}&19v=%2droNOBo(~=!D7r$7r8bf^CG-&dGOFP@`!exKr<(`aBBW?N
zti2;)l;KSg0d~L2k~+QWf2KBCS+35-y#!3vzz}ARVu)%dd?A6uTLsRTVO(Xiy*DM-
z_cyF&R2<1O4`8*WsBtzow&pZiug0G96yMg^@S{InRz#1nvJ$Qol(Q)cABnq+&8^{U
zpc5;${|mMpkY!r92+J?``z7eExqLp>IX)u5mNd3ac;Xp7{I8!^S5AsxN3I1pVM*6H
z_JcfW%NiUq6`Nz;Ue~V$bN1P%hF>D`%e6s<f~i9IYHV<>t7ksv`fo>9{r9w}H~7T^
zebkwoP*!@T<Yv1#_DF!Cw&F<0*Em<Y9Fd7;c49m!D=4m~u2-=X@0KW#L!Pd!G0}?i
z{<GK!_^A(n0d~wv18dzV2qz9oF^;tfgFB`muzCF=KYw#lDh~)uDN82n+{2WSB9;iU
zWW9+`IwX8`u=U#dXjOg0qMgjS*7*XZV7rholD<MbuDGw6t?qS}{5CSM`VNJ7;VgWX
z*)@u>mMQ9%Twd=4tBc5U!Xb?-aB4!bH=R4@u(5GO@^rCdnHnf5qomn+&JkXlNf+cY
zlT@KJ`la|)q;Z5JIBJ#@Zd5GFyxSJ{ZZnz4#UD8;1`=tU;S7O;lr>M4E^@s$RkPP`
zt#B+c{ub<E{6PxF0v&mR+F4;k$rtC0HYqWUHGf!q??u)b1#jZ=gG;!Lf-0=u?m}$7
z?F*cD7J29PS1UyF+YsgA@9r0u5pwz4>qe>JYR8=-ju-Qi8J|p_O_XdVW+1Ue26}=-
z?ci?C$otdW(pS-G!{Se~8dmLW6=NSPb~jen$Vd}4C3WD%zCaws&!z>_{dX;r_|<qs
zm8zNYUS^eKzJWxRQ^*byN^zX}QsN#6!BJnq|Mj{?qBB=Pq>{l!e7r}J@7Y{sfiHv+
zRpk==A?WX9TC8VW7?XkdZt!o<<XcXbY#lk`P;z87+?`BJ)kfI$QgNDvU1^YkC8*Zv
z@gE=fEZp%8W)-`PX;2^Drqi=H#hYC&`8cgTDSQl9x0|5SH!-bWb>c0sZEBygS)=7x
zk(CD&J6-9qEY=znZ<*`={bmvd{w^l&>**Or`u;^i(j}f89)1uxI?DaDh`P{WyvH{j
z!$T_c9RxD{otE^y>amA+vLt)@G%(N*a+zSUZC~X64Uc9#dlG}BU!Wx8)eGIWex_pU
z*;bk5a}Gf%1RHBr=T8hI!a?Mb3I`5_ur3qG#sHh&kEJW-ApsL*hLftM0V$*}Z^5&Q
ze{z5q!%Lm`UXirC&zjJUt<yu;XCg42D_S8}Mvp&%r&+U()czhhh@QnFkC35#hAS|I
zRqbz<MmVS>pg>lm`H6#nuBO`P2@93L8NjnfsMcIAQP~?rj6@ZSgOnwgQl<s%f8!%0
zsaZP-#Y6w3=Q4nj5xvg6o77Yjm@kf1C<ih~?dLVbtfpk%+iN%e=snF&qn+9(juL$T
z?_XHTJ?r{;o19h-jz30o6tymtm_!WWwxRXwRiqN-pQkDnlw!e`C47m3Brtd$=G5!c
z#RETv##!tzKqI9ZlGKC)4rHcUyO3pvCGxMUdBvMmdVVPB{5So%#dA;3lGUdoTbA-!
z!Mryyc0>_+nuV+2o~RV~wE8oi3@dl`>BVMP!HzkfgCqB$@npe%OXyQ-`7}GE5GG;}
zAKv^pPq}C+85d7;6Wk1drcn?Y6gor*-9R?g@vJclHX+u&|IIkV5FuU0NJn2jD5e?@
z*dGYQk*JTCGias)bjd1vGK*mM7`lxbmPmWZXzU5lfq#J@L7~qAQsy)e{_S8Jh4F+L
zPC?OWm4=cedmcHMW9$L=|MxVV2uKQz24;W8r6A%hWRR)Qfk+aMq)u)I*;suKP;ARx
zR5YmRAy6@`{8M?x=Dmd0dC57)v&oO}mPvEt4gR}DNll;*u$%<kOd{n}<C04|T?S(c
zUM`0`*Go;P{C}V084U{fB-Q_v6jH^!`2Qa){t62egf14BVYZ|tH6;MJCKHrw3num}
z6_mubn~9diwtc<1>-IAH)>1sR320UM<hZI{#VKv*LmrB~Lw>J9@3I^9&=QyF9}KJ+
zz#B_Cpj`Wvj#2J!LUVj2%P^NbHp4y}JPA2vsa4_I1<Cg<bMJ6CFR9Hi4Su}^q6&EC
zlo0f%mdc|<gB|*EL~<78hMqY8C5pH7xMMl@AmHDmPbt+xI(-y!THhyFX00hux11&e
z-|_o8Ke8WN-(~o(xoB+fHVrp?n~g=^*Gac7URe^sl`9l5(ecTpe?BEK|4<_G)2TSR
zm1xyI2)!NVS*i$@3vZOqoa|j@C;EP|vCQa!zTj?||791a<cGx}Uu(*HI}z(CZKHri
zvnAa$u7jd8$P=Y$JosKpzT57#hzP;~IEkyFsy7;ruh8avQ#lfHpPDjWSM3@6uF-z`
zA?)P%sh0J<cJ_>oz&;+k@dJLV528cDK6OL+0q=G=e`EHmiR=6t#TC*YG6Ie{vSn0m
zR6z_*3L6NF4-!JcNKj2a4(#bK-%t6Df^NSqKFz32!_1GOE%`J)ZLP0lqj)S=9S<0-
zj*xnvV<=o21UMZpF+Tlk6uh4*Xp}NxY&k_d5L~tyj^0}Ko%HB3N#l|q3veUXKGg)}
zP?6m{kfJ!f(_Z17A5G{^dSgA^LY;2~WoIZn2X?iSIwmm$)$5NhKIa0e_cD)D@QJn?
ziHVL-UtEL_DXtmdiA8x9EybS;+<xokN4YFZk6ykA*Vjb1@l^#?o<>O98B*)$3|PC*
z+tLPzo}`GlXEk~5#5X5=AQic5&iRXzue+9naeLGF#Acl#Di2xhL?EaR7=HK1X6lEI
zxBuBlK|l^${hdC394=ZY%$WjJD!<jQnTGu;ttn{@;>Jt_IzybqH(Oa*UORk0BqMg2
zV%ctaQGVXnp47$LdCC#!&2t;C%8raijY?FHd{s}p6khV4H2$>bXG%l?`Tg!{Gc`ia
zFK&Rnyg`uS@X8J=S19Cjq?#lEXOgMVRs9|ouMUu6_8P4dsYR|{pDGS%eJU-sY5G9Q
zQ*oC$T|s@D=Ul)1^WSf;4FtDi^%)y^<3qIfW128IoC*NF7+1-se9^byv)#+U64(~W
zv^3#1YKl+P9FnM1o<vIyDHJ<aWSw^$b?S9hD+e$mAIIDU&t<X0KB?cWBR_=CI8d`Q
z*1#KM)*EQK-N#XRG>sX&weD+l=D8?tcQLZhsi956Gy{M~z6lfoZP}ZZr=6bfZPi)+
zOQ1V&-Zvo+Q;kO3Y(3J$v#cy6Ma&c-9yLhybBY0Q{4|1{<{0d{1e)FoPZgj(j}})o
zrY#@ANL}*hMAdh<t0libhe#-u$D=vLtGuEY=BW{9{K{!(V~0^^iUr1Kk>y&P4W)<<
z4fxq<D2mC0MLf$2f-T!^&a@RTAh=hNu~5yBwMdAtvgaW8dM@;f@~frTZ*A}vrzOHs
z)5!f%;``b#!0?z;mPcSJ%wv*_OIuXQHGCvtGZ;DuQwsP60I4~1=SC#gjXA3~h_Nt%
z9n|5r{dx2B<*z1I^7jf{7Wu-p`k5D9$F7@YrAdjrzQ1f-!X7Yl7tD<=6b%PFWvAY}
zZMZ+n)Ym>2KLJNEFZwG=3<HFa-!aPMl%|9U1T4%TVEGbge{FKhrgEeCyhYQ)ZNI6$
z8-u<Uh{>*-jnBi;S}mXMDEbZgxi|HGO`;aR4IIgr+DI;%ogonH{Kg{*pJAh`{og3~
zT|shEMick9cPVEh`6evYTcNN}sG5XoE8EooE2ONk^dsP~zk3VQ61m3=H`xE>cUr#p
zVUEWv#~U)>53WnjZ0uXy%jI5aYHTj)c^&G>3Dt%Bij={@l4+KvdO1)qijz$P84f_l
z$${%KX8DSac-&f-5G4c43R4>nL;0?~-ZnzuYx`+O4p_**l-^}->%{_PvgC)CUvac<
z2o=4}Pt@z%Z%hB_{Y&GYC$~O+v;#KW&^)JRnAvKh(W)JdNZ4uH>zxYCR}$)({E@Mz
ze{Btg;x3zZRFWI=Q@D8evRwHtC`$0E2W@&3<!8F?jW<2QTm;FKhquiKqb>U#X#MmB
zQ}McDRXe4>m5qu|BsDjhcDD}Wfkci#%TrZEZw0j#Ox=}L?9S7EW_18o;^tEM(yNyN
zca0W91k1joK`4uhIb-bs#ve+I{CR6_kQ;GiXEFAb-{05oS5=PMlXe19|LsDdd!^pj
z%ttz+&m1*sz*!g<8Fgr&_Z_;<_&%LgE&s5eHu+tOZI#1%Wgh6MbxRN}c-1nwvn%pp
z=X_E5z5k(zegEn_qw$|U1kFwawwp<^0KYSd3KKdqO(x0{$OQ~owdB&rMPE9;#2y9~
z9p}dj9$ZXT!4nQXMpg))&uJT7Qam1>wnoGa<%_yn5V^XFs&=H`rv}=$oZJ)IXs8-2
zvfs};eu10ui0QA^q2rs`JNz2p{lM|Q`>2~beDJI%h+D*;r{<|@rSO@Z1Z1b=h3Y*8
zbC#Q?Jr)HXy4@F!y`r{?+MIw!81Cc2#<{0q+oaUUByNXO6rEe@|F|%>5nX&0g|e!1
zR{gD%hvgV*N=Z9$Ic?9{)FyKlx6yZ79s2nFnm4ng9Zx1Fo7s)>25-S%m|U$o)gahU
z2RnM3Mraj5MUXx8dN?dF<g(JX9G4GE&M}>93Gj%un|-eLxog<j-3)8*n~IlhZ=DA^
zo(C=SfHK4)Vwu=>?IzA7?D#0(FZ!&|w?E$ab11Pf!RMeHXZpJ1jTyRDTo-j<ojp*)
zIPkYM@pDZ1mC>Yp)RD(-!2d({?K*4mqIX~{q@PJQz^nY`)!_GXYbR9(7J5j69F)uH
zfmuDazXkR%hDXW#r2DPBlv10A`RUZdSpV8KeSWFwyUwflkR{KJc7N*4sDCyKCRbG1
zceUROZYepirkiwH0VB=@Q1wxcv=dzS$;*AEopXM8`5&ppK4Cb(@YU_RGat-UNjLXN
z_XZVFTTKHsH535EQkH*{XAvJW-y%+r*E2pOMo8S~S9&?tUW4+n$qxDbkzZoFmSKo#
ztVL?9AbWt#Zu8BpfN2_K<esASqtZHF0li>Mz9GEjsq(zV=%4T?<CJyMDOO52Rhz8r
z22ayiAQ{&tC`7SrL&aW?0f?>@p=~;U&#wLe*(oTG4l@HaV6Ya)>~L5OlP&GNG_IL_
zU%Ot=2zmQd(;y_j!I)tX5cx7P5?)eMt@kQQiTx}b-rm<turq-KcJ139@8jK^pUquW
zvzKmHF9W?WIqft%8)@(SZBJ7OZ5vQ+X+EQ1m%@g+{mO*lrClp3yPy=5K8Da6(ZS~k
zXi}MzLlR$4Dmn}kO*B8WI4}Bg65xQDgOJZ#E?)Ndwcp$_c2zvHw+3zj>+JT*+Qaui
z1jv1{$&wV<Ua7zQ31{{RxVxZy%5)zEI9>V#z*Gi=bRmo7#B$C_i-8_lpPa9}C9SKG
zq|rtmIv(S)BPM!B4{VCQE4KHC(sr!vZ}PmK`gZC1i}n<#fO=PfeQ(t4{2?DUpQnv&
ztIRNAh()UO_S$&aD~i{u7IR+(ey%P9?F@q@VWuuy=HW^?jrOO%w(BiRVSmsl$N5Ae
zY?`x)5M6>0GI$*8KDc0}v^Jz!=G8d3SD64~)XJ6)3O%1|!Bwr{RYNRObE=2FN3trd
z-D^wQLYd@=5)70WD5t4jtKv7m#|UV)2Xa~Kh;E#1>{&-Ye?nB<9uE56$lqoyowE)!
z52?EzbSuH`voZZS-(R{+<z5C1VpMrCY%MPDUsZNi7m>dWq|hW(pEU^bfAa#Vwz5bQ
z69G*R66=Kw2R@7lec*`@(<4wJ%CRx8XV10|qV9T$zkQwmCh|hd2XG0O{U+~wB2F@6
zrCV6afi7U>!N?+2gf@(d1~67d^qikd<8HAA@JhYdwObW`gfoJBe7RUkzFfV2^Ly3h
zJU@OxevZq<<T5v0{AC}zUlmXw62%jsUyoPI#dLQ8sM<tV%5-dGd{VUeYAB3GdtZd~
zM2siQqMYl`=@$G%3?{wuG+`}f<=TV1id7SHbi2|{JkVC6_>LsBJZl-ckS%v_M?DX!
zhl3e(^l|n1``FCy4?HUFqf&ipXhq82;fE0a%}$7#LVdm~yjM-{#q%mm>R!+C-;=|U
zHpek&=;OSIbmg`nP!p=b!#DPJ?VS~S)4^WC{iw&I3bRtK`VjE`&g^CE_Dcmv&CFtF
z>x*A_lhYd?dkK@}(u~`5&ci2_eVCV*-2Sd9nOWWo`zytIK_0kC(~I`CPpofZXO6#}
zvVO_6oUmF9T&5d6;5BvGcCKw6G2{}x;Or0e^hXL2A^iH}x8@t^meOeP#OG)*WF)}q
zESFQXz1-w;^he11iQAN;g?=D+k&uS44FCBCR-T`~8MW0C?X!{f`g4iuR5E<sP9xbq
zh;yvuP@advL4ZH++;zh&ap&g9(=fx@+EiDT0Yrn!F)?Cn?$o0g1wyMb7GM4;aCQmW
zNY;#DE$_J;c;F`4<F(yuNBV|qFeUdSZe7VAn>F|CN@S&+i^4)BGw)#B|2R#gm?izT
z)1k-_29I!VJg@4N`~9O_ySU4H>YOM!8hzenrma4ffJ@y*S50!q%Vtrm>EC8osXiMC
zW_$m+7G{?MR6<Z)K6Ejb^D|4d)p~@jTOUvBFbWyJrjI!j<k!(=eo>;2@8Uh6bAOpu
z)Sz5`?;Oh5<aX-}1X}`Z&K`iLzUL&A$FMe66%*jvI6la^!ys;Xy4@2c)iJ`=5+0+@
zpFUb_9?@-_;==t>F6P7Xc&wKizik+2R=(}3T8T#g#p&pwUZgJjy5CpPnlG}P_E|-Q
zqP*L8oGbNTvZHmIjVIw>e(`M$Q3gsb$;*6LP9?>ii9F3LDD=Ch+7-|sv3Z=<{+(Z>
zS1vPZYp%-dCU?YPVX|FaTWr^;W?6|!Puj3<e|Ds+F!MnNSD(XpzAWVpKc>jVC(qJ8
z!W(@J`NbOJkmaWZlSXaQG)$-_?jA$ABi)-Dn_iT)I)8X0WnQ%8KW~+A5|7<7bm-dC
zJ<~{D`10IX12wR4y(g|5r=9J&5?SM8O!e3fIqJR{nB53SHuK-}&yQ2F_&wbZ{%$Y|
zWC@z2@xfL_GuVw-_+8?gK!DOaa_=C70m%DJH$Gsx+q%-%zS7Z9&z}21##ysAM}kq7
zq+=(3GilW5H(4`%oQMe=df%e|%;k}o&{p}dADJAn4nt0qZMMw@>qD5^E3TL{N!963
z-jTLjdE1A15!+k`{c>c<`*r@+ZK?y^g?iSe;;&q%+__v{e1EKQpsf(?W5H@WtUFJ*
z_Bb@N-fgVE&^M;pSZSg-NMxW)+q_nYY%;;t`?2BH$#<s!>=H!`-LnQ4&K0wL7`la_
z9s`d6;ccnQBKJ0*J^hC{NrIu)`kFV45Uv&-qx5YpES%#T-13!8IidOu0SEe<^OTR%
zDrBmP4UYG&%M{a5wjcM(EF9+S#0Ps9{~YnUKxQ{%%c4Txw2R1#e4i*#hsRT`#8^}G
zw*FJ&*QZK26@f}o?%4LU3hs&iGh0?cOLmvQFCj)oiYrR?Fm5jUZQpL6GD=#kW%se=
z#_64~8KuDkt#!G8tN@I^Wk9P*kp0Be9N0Nuq;KuApga<ko-8GNbLiec{j)>+o=d?!
zZ=Da%t?)#$=-rgO##J;RYd`8KeJstbf#iBdxb{Z#7<MTOA!3U8Ot}rN5mznHq*CUE
zqY{w(IMc5fT_kwd{an!oSC^GtN!IY2Hr_bh2ZOyH=#9}&NouS{5Q{lSGu-9iB){=k
zDly-rv8a(z4gArT^#Q)^(Q<9|(sitb?dl{(PRD<Xi@nW3MpnbwKF@&&$)}9}>=&cQ
zy1?!Jif@a&ch)nM<tNE?6QOw*NL5Za{hP`|+jH|l8<WA{a6s2Qk@qBUfNV0=jfBsl
zO^1^&6$CS0wDF6URsRGX2%Iq}J~ltvic^K}b@*JZT>r3h%=G@&0DF)GguC8}H)+E^
zxT<2?H(L-%4bA$ErG1@(u?dGPKiv<BUMgJh`l@(mRexr!3ui{{nWvqG0}u?jdcUk(
z3m_9I*-wJjF5RkFR$^?R^SNvTL?(Dx3(1+mHL!?<7+?_hU5*C5OP=!S2r`j!G)W>i
z5f=L*cNh!)DI_3?g%U$vE?;%P#q?nRV7f)3DRTXLxRX(?t8<1XO)I%HC37MO!~O|K
z<*OkTQj~ufdpjSk#{HVsj7P=FRHqZ%*y{>`57gwlz@FaAO$Zbits~=gxh|8g2nI}g
z;2rWbJ6YjEJxI9T#~UQbHDI+A;b<vgyhv%>MC0?l12|OQvNxR$T^!ytNBzG5%q8o^
zha;OWqZ@$frf5x~syO#_-fEZDXjLd-yufU*?Uw3RfjvFw`Zo_{_mmbAcy#F$_I8~V
z+8#y!tNHgI7y#Y2#7hT*fo0x?qo$c*O}UO2ixe}5^jb%#ztYe`IJIm$dGwk727HRL
z%3GZ`8qR*xrDuCxpDVys#dEuBLvFc~Vay&_&Xf7?5k?CaJTvrP`vj9eQ<caqIimcJ
znF3Mj9zT3L+Z9Dl(yYe;`nK^asD?p`zF>g^?wGNzx3uE?(}&)U?dkBnZdXR2jsAKK
z3Gycfkx(;z>@#_oydK&Pz<Ra3E1i`Y<}4D{lDfML%O9Viy6k*iTs3ZkNsC{9)LXUw
z?bP4we0*PmWG^&lb<ifVUG>^e#}2q1=a)qw0x(f%SL{P9%?@IJ;30eR=@~T~s*i0g
zd-*<n0~G}n49M*tAH930<pSVETEHav)uVm+je-;C*&J+V+3?)qeUOirP1n`(@77n-
z2<BOub02cL#J;GjRnnv>&#}x*bJbWJ75URG<U5hw*ZpcwDmbcq!NaF%%wqrAbg+tB
zP3Sxb)7h&NZYx^T(dKgmIb`oeA&@zG9tG?#&6i)-#Gt`f1_#ZnDo>SkQkh<IyrJ;+
z@G;|QcKpHa1|QjTE3iv)hJE)X&h>KM9;PgnMtzC0-_31Wr6c>fe|PlBM=Aj>g_i^1
zjAplXSDG+A2^Y5?^KUcL!?O1ULf+j;8cjRH+oXF*@+0;t&s}{=10|Itm@1N*U`*#_
zJ$cewgg^f=wdCjS>jpsUyIN{N3`Af<Qjj1h1nlY$-|>Cp%Y{^c3|iYuy$1Q}O+Xb=
zv&goYGLqK}crEOe#}&g-(IKYlrv#L*tVsQx*DGs7L#jfHSbeMSzjE_kUB4abDf#ht
zgilfH<Kw;qsgG@$_vDMVM~hKnX1f5KcfL#PF~Gvee6E5+XM_~r35)Ej4}aWGTDIGW
zqTYx)^kzG1cuRFGMT!m&fEZ8^keKt%jfA~uCNe9j31kKsP|<;=PtF_nV#0bs@2nNS
z)Ki}rUu^FVB<sQ#{G?g7<j<(lQNFkRxa-Ll%9SF$n+;Gw!viIC#NUt(cS|cZCkHT_
z<ZfD}$|<s$Pfe3(*UIkEf%4e%%VM5m5o=M^8@(L<f|Gx(<C=m}ny%LN@dmISsm_ok
z-#RdMO$>13d5&>&OYKKkNCQp;`~1iv%R_(jk?ALTH7lrTx5!4D=a;@B`oF-vcvrT9
z7&w6xCUct}3$C<+pWPMKKzi)r8AYXs;D9I;<bfy%s-g2S>Pw%t)+e!xo`I<Uf!6cH
zB$M}i`}_73^4CpFaiE$KIJ5c4#V>LuSpknS8Q{G@3k?;W5@J@sNN6N{@>5t*A-^>4
zFHUNgkJ;f=!0#11%qg>4kvZ(W*BNa`*Edi`jU}CCxj*edDCK|O@tAMgbR<x9a~|DW
zOLFBWi2&6UqR_ebAsx<em~-};m5+!RfcRhj*_d~17jn6@{a_it!4&IsJ9wc7x(qy=
zW`&qP00Ghe%`NP)LhL5x!?NvmUK<huS#bz`xox;rltc5jy{~ites`~33CL)~ApOr&
zf?Wo~U1C4XLL)#%$w*&b9&YvWXVC2HrEyk1i&Y718ZlKaQVV|{`=I3^g8kg9Ug6t6
zVxdXiR9#o|(C3s(59$2j(!!$kLPIrSE?!Y!ldj)W5o)VDq2~e1Q-A=d`YI1fVVywk
z5B@wDGFmXK28KO|uq>~6cHXT~%LPE6B%Sd5xP!Xo=~MlNMQ1sKCHk{Dilk#)l*sZ|
z_iqPbIj*n&nLSI<iUYOT?<%{?1&fW$60Qd`>RXhkFv}ic)#KC2S8hjk70I4Qg~Q2=
zod>aeX$Hm(B!yF|8acSx>KKuowRGh`-B>co)1JLuXg$O6%hSY`50G4bnaQJuNPddB
zcoVl*FjE=Z$lP2(H>RlBc=Y*o71^QB<;2)6o&`Z<B<#7evhTaG`*$!vKtTr?CQ>e9
zh4;N+KF7}fmJyfTpMT5k^UWd|MthAR9EkB&@NM%y&mGZQjHmzQdW^kwx8=9pDEn|K
z)wCbzhWWv8XVIkbsAyPRRTegdBbGtGG}&p9i;gW(IXw!i+tQT_y%N+{0G+YZpBd88
zS;xIoVl|IY!0in0_jujqJF?OqVDqRMQc8ZOg%-}EPjTK6tceQOwfU?3&M|;@4I}^d
z@cZ^H62Fea9fR2hympi;-INjhUzK@=7f>2mQSZ4yo*!^qHcQcJgG`@3^{(kPAw5hr
zjcgepQBA(2w$ky2A2X<N`4d#61jC+i!3wBP(sB#+yux4P=_C6wncKaboX|+Ws^Ja#
z)r<K1RL$t<feN8G`IIBHD%H>d6#qXZZ-!aTwLy&|K1$YEhhVXFJ8>6RdYHDNrZTdS
z$J!4agQg27wCD({lnK84LSK^)S|=lYUkZAam)x$+hf6%ZUQ?>!;WPFq5_w{k!RcVk
zD?5@x+^3!<tEBbLe9o@@@92ZE`92-Gm=3zFJ7WH)c3N&T&>?-<e^7?6g!-Of^GcUb
zwo`B952AHB(?am$&dCf%atzShc|1u6?J_XAE_xNxYMgpr*;TO(0=*ijDur9`TMjSK
z(8g3u)_gj&660|kC~1(m400Dt-jGkI!NWO**&(evrmV&PBDi5Yo{IPj!<<y9d>!eg
z$N#u=vG3RxI5GqJ7bqFD9pI2C6YJmtPAC#{)xzxfU4~;j%?5QkAkk#Ed|;%Ek<fvU
zXS|;n3ax<p`*ep<mTUDrq}WW-2U{Swt^_N|JW?I$w^WOBfzZ?tX*<>%i@1X+EQiQ~
zMGZZ|UQ9vDnU_k0DfvxG0%5u#R;qeJ5^FA61qwZ+5$^8>934ye^tsKmVv$JGlh=AY
zq6N0(w|6C}Q<q6k+Bv$Y*L!hSALmVI$3v1%YJx^@zN;{<rjs!y=%l_6<G@O0{Egh7
zam}ea!pIX5+*f1{gisEh(8AL>?6Th}<`hGtjslMUz8@Q(6dp$#R0|h;k?{xsxBz_&
z2mkQDO4#=<w8ml1s1^+AqC<qcA%qIPIO}rTtF#S}m8!_OSI((fwUoa%IS`;UM!!!7
zFDmr~+#dlks7m1eZ?*E17-*dFcvjV3e<<`}^-q_y?rjsnC`-o)yUulkofo`h5#i{Z
zsf<y%qTc-%?kkJ?9BqjvBMee+R@2{E$89{Fw~J^QR~*8;@|Vqj0Wx?X#W15^lV_7V
zEG~0DIb;~NfwW4aUV{i;PW}BFZ0~J{(nbH<y`n$_YuWiJhu`g8ABIW9)lW@p8)a`i
z*9jVFd83ZL4A&}e{GDvzKIs{9v$nfP0BZuGyx-{SE$Ew~LkJ1EOw-q*(iX1_@ZwZM
z52m)Mze8X6#;37H_UO?J0FLAhtRVcN+B=9qAdT=4Jw?6!{RXi|j-5n2Nhm$4)xq0u
zyjEeWbEuJU^n+|QqEzIp<Z!PUya1l_f<(~Irt7lx(qA=+pYmyz8gG8Q!Nm=3@>(!Y
zS}sBxvZR-XgEK2`&3Tp1KFVi)yS{k8fryt3YrIP;`2I3T`>4`}=^huejP*JF`F>(q
z+TX?T^`~Eyb=Ik}5MvSp<ca)Ys5wHU98CBSgHD_KWQbnu{rX#mS}ZTbS7pZ}f%<PY
z!c9<qN}O8RbT_W8KSCtl#`#S_40xgwKk~>X(1GlD$4j9}MS;uq`YRx>;ngeB`cG4(
zjal)t()b6ZwF5ReKFchnGAekn^!pViVP{$dN)eDP51zGO0&QFzgvL8@C-IR9y$7V=
zZr{X`$Qgvb>&35}ly_0+R34{;w><WnJk|+61=5oy4ZcUahXqy&nZAj$o~u!&#w3~z
zy9TFbWCTSl62^KYnGq%A{^Hi|H^g_*L!&yvHlCNCGS!Moi9*P*8Y!7*JT7jT!;}n=
zl?IE4#WxaXI{tMLpml}A${Em7YYW<nNitAYGj-@RNAHfAElImr+f!JuP||HU^`r#(
zQbL^3sg%bjCICq$F+M(Ch8ic8&4r}C8@7OrfVo~$kh%F+A5GxEnIc2?Sd6*cPza_F
zN1sUKryMk2=5MAO0`w3sWfPNCz>LBq;f>4AW??be;1!RTdGRz5NWv@F0T(;`CRCO$
z#Mc?+Y!&W)AHD>?XEP}&rJw_!7W@{|{%m1kK~#g)umvlXE$vk|H_OvUof-!$+!h8F
z6X8(S>+8Nxo~Q*cKu99$DM<Rxc6&4{J3D&~N6JuQh}nc-pe=ZSVa>?hn50%=fQ1P+
zHA%qcrYKhMZO)x}R0%sOK3=jZ;DRhPx!HlfXR4~I;Fph}ZcW4@(H6IhKzWFzXp?ez
zLp-(+_8$rP@l2PFUN54Mt^&8RekZ*K*ap~nDnz8D{(Dnpes`A^=H}rQ9CFUG>B<_X
z7d)e&8=1}rHCK>(m53dVUg%7}!P!oPSeVv&&7<KeQk`{Aa-i2MywitZDbqXuQqz7j
z$-Pe(R5uh-`aT2=EWMhV+S=+WOn#HgW@H0()Un(ROUDm<E2E=UN0)<`#Ny;9Ke+m7
z!Vk1Ze)$fE86zw>vFd}o-J3^Tc>=wz-IFykHjQjK+N101H}-4h_$eLjQR=W^tfKM^
zpdVahQfH_5%a>8Wk6T+?|7y={_}jp+nJPVA%gN;1N|l&?13j)V8fJ7wmnHdrxOHt1
zt1p4uv!29p>3lPjIRQsh^W&$H?W%nHzqk(;M-D^ql=%TT$WU^}A4%d!&>~|Kj&y#0
zegHnV`QEs=yVu?8>;L>WT=9J2cSFWeX0%Y7Eix{%pUc89)PS@YkMTOB<75_3RWe%-
zye<31%`L**t^p<)gieu!*GO;K*}>}Yx$S9qdh+J5-nkAp6y0xH8P%t|o&J3PvEfrZ
z^xxWPeM<rHr!4}8lW_*6h+iCE{JJSO1Enn~<uA1j&GtZvggD^uGLe%T|M{weghBHC
z#}B|z#YQ%7G&zlxCH}FhmD)q7xIooSvnk)GlBBAlrB6E)Ea74Bmej{`BH3sEA68EL
zgWnp$-H%eHh>T-nJP=Mp(bE{f$7yQ1Z4M@bje2}}IXXNH9~fc9V>*$Z*?JWdpy%Xp
zfshpkzuD?1#b5HT$jJSxg7U{pWoFaw^2zrLb=oj|w-k-XV-(rF^!`8*mkcZm;9Pw(
zY}Hj%9GRZxqNSzf;^JatjOsD%Xt!~$#=|U+lFXm7zvNS#UnVr#X+JD(w4$z3@H+Zq
zMy6LiKN4j~pY5=4d@XMA2iJH1>zYg3i>g<4UqE0RKRY+~9&p3@<0xFWhWP*u1-xl$
zdKyqxD=RA#6B2&u9gi)1v@-nlW$=1amiX(1_Jx1CtM|XrFoGr35d9)yr^?+_zur*n
zbeiDLsJir4ufj&uC$v!8>@2aLs;vm9+BI?)7R}X1=<<UCOeOPVb7^$n=?eK>-k+z}
z>eav3tG1oqU{DX(pR(C3*Nn{(1QZp9b?y6cS)FnWC;1yg?15HIhkLe*>lWNEfzHu5
z{ykc1>3sI_rwcp+S?W?{@~;DrB@_r8Kj}8ODfp}E^n~h`t-OS$hgi^6s)5T6s?vH2
z@~f5gn0~l~0B2vy@*fG9pj40|*5@q3`zkvihDhKsCgi<fMH)wL9W{PR2K>0sx5mej
zZYm_h+1?s?2Dqfeur>uoT~+bGIJH#n2xw>H7w0=B;#DSL3#~*tP@=80IjRzyb<D}n
zS<jR#{pKS*i$X+jG^kl@-GG}o2Rc7HnG<RDqxe7jsCuI_TAixPYNcJoh%MfYILC}-
zd#-q8=#(h!H*^OVc}~F$qO`tC8pQ8lB`RXk#NiDZVo85mK=Cj;UYTZaO%5z=ap7{b
zR8eAp6A4p{(#K17!Rcc{R#0g6y;}WLHd!U&OOTu{O{{|3SsTf+(^Q}C=RFa)UHuhj
zP`@x<cGLfO3^E-%9M%@eQDKv)#*~kby7CfH8PACP<CFX-^vesNR6$EAq&?Jcx|Fcl
z$7+aDY^Ad0kA3wiGdcAlz`*J7*2i&>$zscZx{o1Uo-rwqIX6CN=KY3}Qt0of5X+Mg
zq)H-f{aX6kxMH9`G#4?(>}}>yQDZURwr;i1X-e-}(ML&bu~Ub{TugFM|9IIAH^#8z
z-J{yeh~hJ>mW{X}wUw;CHvv*+?O)aMD^y6=cwsB!T7KTjHjk)hsWl`uJ{P}-_~vdp
zD;l)8lkquU|AQW-Q4cQIB9F0n?_=L}a~G=lCg>!c48E8(J*~BF4ZoM#FU^f|QD9lJ
z%ijA^uK(IjUU!_YFM8i$ZnR8)Q;@bqFt;=gRV`{L=FOt!6{(>6s;wk{A_rj^1rVgD
zi+}<_3V{-**9V^dqV99h?O|rAfxJfF!LP+J0a|4SYR*ndi^>S%cnEm-l(d1GUvHM|
zAL_E|b8J;CDY&RBH-fn;cYa8C7w}PKQ~gFZt(+(#?!i;B<dWTiiU-qwW(-cHkCONp
z{uR_7K4GWFdni9lCul-$xj!fA$SA&0h1L%FamelT#QY$RSx5drHJh6G*5sv9`t*5t
zKV$oLR_!$XjR78An`k3OKLap98@Rsti5NMp4If6Da{uPQhxfzl=CLWDxZlzczN~7p
zWcGa%(8D#vQ;UZw#{iNypCZ*&Hgu=o5FVBSmdgd3XTGszx`&jkT!FoW4MHa}fk<`%
zUJMk7L5K&6LPbt2oDB7aFV*CbB2n|iht}J;t4X-M?a7&AI9`^87K*P5Id19nMf2_s
z!RcF*YF`VI&t!EJ440#Nn|R4c1)3=oLuDfM#4#+s`6gVRkdkeT;l7f#FH8aj6>2E{
zCkz?x|K{ATJzXfW)il*tSRXW-BDS;Mz82FECN63oQFG5IzP3zJv-DFE_t$aa@8e|y
z5Y-}<=1<VUf<>@Gf|x4oV`Aq!->6UG>qHn91o`%0ZRKQ`33!p9kJHUn5~4&vAt}li
z<Nko`%g~WC*Q`*b<lle`2?4hr8rKT!R$8lDpn7IdbqzMWPi5n{_f{D|-|n4nQEmt|
zU8?)vwr+ftxcx+@3IszKT(K?SpdlJc8U%O8=`Y`IGl!2c7Y>UH)0N3sztUzq_lK_(
z-LqP5EOzn8C|S5N`LmJjKdx|?P4}m(PDI~h{ec;GS-mO?K<3=C(25J3l8Qc}K1h$v
zmCObB>_HQ}m%gTnk2~X&e7qb*r6-4og$>lM&}<u;7^f#s&xoX0537<XMg-l~BvY8y
z?}Cjoak@-X&ar^)6H<Hq4b6eGndB(=GdR_Sa%-+pf65MLeeN|hXfwc4;oXQ#J@ry)
zIY6O|cr8)G9&#+9Rm3f^W3poM6l7wm6q>M#$<mVgIgfA;xN0C8mL<|x4LZNNhPi5W
z{XlhEFze>%w5g@xP}VYXlt^ILXBSre`oP6TQWfmu>3Fq%GC|)BiAo-JKF=-9<Zc)E
zzj^;~>vog8yYg{+vrCAP^2^5-g8@%~wi<zPdBQ!ts3mGma%=Ta_!AJxxPb-6$Ka=b
ztuj-VnzW4XTlxA7>gCg<KRvQGG-UT2@`TnsS+2v#{pB<3cAM&8bI_0*r)snWlc_x)
zftL;N(lHsFJyShVEybvRnOfQ+KXu^hjH8ychMy=@?f$I)i6Ci_uJU0jbhUS-2ybSe
zEiE$~5<?ehnc9wF(MO0p;fYUIKu7qpI$j*$CLz9ovm~QabFQ%l4X64u$JtGPdIT^r
zavF~%rA7E(j(sovs6{^&J8X24LOV^xD8`4+W0g-hePxag8s?bB|7JmH$*5bTrU~ll
zdrKP!-~{nf>hF<nU^_X{6&;0CMSLDc0~4+8(1@lyR&pt*qyQ1Ge)7oRqmZ<6ulagd
zVNfAup7bkaRyBx74Bj_-w!5LL>{31sLVV9f!8YRzY`<pN8cP|{12btTaWFZaiUxA>
zto`TEz=0hUTyVL3xJzMfe{On`vvt(=0NNJjGlg*S=8A@yAA0pgBmSE<XL%-8I@@<R
z&vT|~*c>oGzmNjUAZJ_si-y{J>psMk)h~tEbvvWkTRlZhDOUv9>ZHiI`NO*s#^B~Y
zCbukqoJy6r%ejwD6u7EI{{O&rNG`mYoWqk+&<6H7LtKah#O`{PNVA$h;8(~}GPgbX
z-#toDoGT0heM?u=t3XWkSFypUCa0{8<}AM>YxD6{EvLhJ2{pw7f3Z|w=ezd0)!Vnf
zS`a4`1LdFK#3{HxR=?ENeLRM<m@xu=T<G^yF`Aar4z#n+e;A=^eUVrn)X%ObbuQX`
zF(q33m0FdKKo`4o;km4CCublhdUh`SrB*k!?jBuHAUdlMK9)kN5GE3}Ea7^glc9FY
z7s%U~O8X6O5Z5jVG^j~I=p4|NR5N~bajSXRYD2Uo88xQv{siZQv##jPI>vkdj$HjL
zT^Q&6F<-o#I)*N&t=w#Tx!rat^ScI6Oz<ET#E~&m0Z(!4Jga|AC($QbHiLAmZkiWo
z*dA46F5i<L$ybEmH+}p;xG)f$A0yHEsq!wzHz=xZyMG=Uzfo9xoLI|JH6=AlQ~4d|
z7Yh|%#kT8}FrqE`M*p$s*FwNDGT%`ecKpn7*df*?{PTX@5PvL>$<V8}fy@8G>sMTz
zhy<R|xe{UAyr8nZ4pZ!mV0V!ys=<B}d8LnU4Z5BIvK^gBtSY8y&-bC~0`XU<c=)Fl
zzUw>dw2C(4Yj*}=u{V7sDq9c=S!gF>J7$Onzhj2;DMq5XHli{%&&i7Y@^HewgN_55
zp?Dw`a|kCnIEO=QkqA}M!{96)Ye<v50`vl!?k`#&=4jM;@+kro^XE20RY@3iO={Li
za$)u6$D@9B%>wbR-#VQFVXPZZdHUg?^Hc)6)L7?qoj|{cw$^KAGT)6^N_05`;fV0W
z!?Pj4Lp<P?uU7o(*=;1zu@ZrU3Loi0W3Lw9&t0|?Epe;%<}Y@}4;2P|*-&z7dI<5^
zzqt9pjw<}1EV!J*2kBt7BxTrO7Y31S#BRC*^Lm{<i`1{zu~#~!bYgrKz|t85>_2lo
z-O%MPg;}iEo_auv1P38&oOmJVRnQB_*m%fgk$Zk<+h5H>RTbbk-**hxJP?%mjHn4t
z;7Mrs>l8_j5st29^y2@e#pf9<h{2{og3^Er)d|t^{L@i-XN4`Pt?B*l7S3$?Pde_u
zBdeuiFS#=n7vPm00zLLqbzJ7D?!vjc_(Cc~rN`p{K~}C8bRG!QfKHRMdE#&Pzvq;h
zi0W64bCeHEQCLU){Ej_kpE}d6-${8ruQW~yz&!tXnOr`q#c5uaZQLQ<!Ftxrn}n#%
zvmFdiyd|RQRLsXGCUTD|uX6VuI4@^uGD;wI!~uSYUPxWu=ilhj;^MpS{PI}i8$D;L
zW7cdOkEG)}QB}Zru9JmUNz84Xgs8}_Yc9aN`6XX~rSrUA^bi|zbk#uPKRYx_m%}J#
z(<d7LHcYWO&1V*Cx!X(BEe9|kb&6tr(~mK<+lm%1hl_`ySm_`Q@!ww>xDV(*hFYd-
z^x2iDHBgRmE-~Dl&#{_~tU>tkZ(y3}KU$|{Bh{p|7iD=2A`f<0NmHD{f|=>p*C?Ug
z%gJ%L=G!hN&P+c&?B;C^eo`akW7kUMxOV;g*;hiRoE^wKYwb;B-)&3P?t9jdfzQ%^
zyKU2(;kS@OOZPhp>P!;oXeq0rMC|+{+K{?CDj&-W4$LDkk}^D@*ULtflt5lHEk|+N
zlejl4GdI8~yl#UM<JIb#v*z|D4B-Iu6*0q`f^s_co6V)u4<@W1R71xzTer%Bk3w^R
z&l+VYKoiB{0}5ki!2L-|QpT&0n-&o+8d>>yHefV@#E6z?u=pkYsjINKTy;NvlkwlE
z+4VXbaI#F}zr#4f#gd}~EU33XqSQqVHQMnyUf}Q>3+K4db~08PLhUDURbBg~i=N^Q
z%1@=deEM{i$S&BZik35EtumgoUslt#VD;Pwzp^I0qxRex0{r(~z$xXBr~Qo@qV*%c
z&wq^!!`BWR!V?mhB`Jb<SFjnRlq8dr)1J1HkaPrjCGW1^8N{h4`F#1VPft(Sxv;+e
zA)@h9>8wtVR&3A!bR#kp2j6}!2jP3MU~EMH`b-@$YCmMrvEyA?#&v%zG3~xj9pZM9
z(D{JQw?sDSw}-_(+)G!;s({$bAteljI$5WU7BIUP=?kMBb4Rudj-{0{MwBKrQug5;
zUel>wwYcs%`3G7$En(Y*x)TXR8jQwWkcu=H=7UC?GYd6LIH(e77PI0MkpR-`1#DD|
z`@7qn()yOp$T68r$KH|6ElC4eN&G}s&#j#1j*l1*DsL2U;|%tam)Pp7OPPO&2MV=b
zr@epGkFo@(kw1sO?VOvBg#f@>vke^$q^D_NA=w-(%|e0oUbVOR->CER2~ie_1?6>B
z(Z@J|h(<Uo)`HW}=@=wA8Iwpb-shELtQYFFTNSk28|!5bUI-_sQ{w>aR5$bP*NO8m
z_X#dU##Pw<{>2ok+Sz6rx%9vBi{3E+eXwo3LztndgWiGc-IgRNJp7g)Mp_JB%>}>y
zO~|vPWBR$~l|>GuJ{U^Fmx%zwMwOG#FQ~u02aCH{n?3j8vkE<AE2(YvKqk9iIy_Qa
zgJ3(u<bn57&<T3G>tv5yBK`%oCPaB7zIPJUWahpxJQtM*(Xq;FkY&<*JuQeAV<(SY
z5<gA-l0V6BfX}sxZ#_YtKqq#j5BDaH_CGTlQHq)-7~uN%&aMr<*aNm@sn3FDv+FB|
zVPmQZ$($0*r_yp%f!dwyNPNC`w4gxZ@pnA0)gh;B#7NbyBK-~&|6oeC`TW<v8cqgA
zND7q<Jr)k-4<#mk+pM~2darf_3DyKEJ~Xi}Kz5dxiY`B2>Re2Pg^2-TR!neBM5k|H
z?P9$Xz*9mlsi~!w9sdiXx<LJSDz@?T=?u;SngzxGGSt4GT)QjupvarS5d~XH`AG-S
zA9bX%ArJ04LW{oVjJ8w9R~vDRJkqs~v5)Cn9IrGLdGi!^HS!YT(mArt-`rC3=*;l)
zB)#nPU!Ttg$ipw>Vx43!*gppZj2!hN?-eyGUK1tD+IKkAPR$$6P21ms{!mP9_?0^;
z(w91YXm(#TvghJ^D`pF1T4Dg~0E|H5C2_?E+|*s_7UcfQ?XwVU$!by60U|Hq^n3_V
zL@v`j$~u!{4J0kPMMU5)DS>H}|AEU*M7=BR5?=C>8?Q`X703zj)J_E&+LIcs#0`f~
z$_!E09cS}Qa+jrr&g@YRg8oU*4nj;bUv4$BQ|F$X_5z0B`$g;~^3L=UHOfB(W(;1c
zY8j^?s_jr|cZsYU^ok;U)CgRJ)%PtZW6Q>(WLMO-w^3<!4%d?OASxJmg_q0;nxvv-
z_lI=M-)H;J@lmPfTfr)qB5f@>jkzdQS{n%?;o<aQx5TdTmN<3LCpBKc{6Vy<Q-n;Q
z4V(>?H*gSsu*MpJ!S*grrN--DF*SjYm-w%T0XaTt-2upA_tEFuM_0Q0wD<hi5vA?O
z<|8Vxtvi`IyKioQDqMl}DDuz#$NEl|W^=B87q!MC6jzk|ndl@p<fnd|*>z#$AQAl^
z-*MbnnyKzpaSmYuS;s5D`}Y^zwSqFjYA>EyD*0hoY>h;lYr4$Ob&KaoIV~k^vrE69
z&{u2x0o$={W(#{R+m>DgWITLE)Om<$dtAFq#0Aey#Gmkzy29GZ*{iUnuzFzs$Dw|t
zg!u3idY5U@fgZi^E9C{;XupGP>;vDcss8BpGfRvL`OL78+TnG~WzEngij}F32xm)!
zqnr0jpa5Q%^WAHOp!_YH9@g=^H`SIq(5=1)BaQDaPVW{s!pH|f8Sa04d|_#3LL=bD
z|K!_L)<w1U@3-n|rv9xg9(aw1LS&=NDr`HFR)No>{Pr+N9kDU=OV>)oq0d_&VrgmJ
zJvtTcw=#lerTGsMJ<RA~b=)!`ACzu^f&jbbVgN5@3mSAkd&_!l9l`nCW8>hFMjON=
z9ZhG8Koq7^>)M0OMkydN0m}f{N%^x!S10nC+=gMLLSiW~8+vDzd~1=Mu$Z7JzN&cj
z6@X&}M4ugLFNQ@?^BOH2yUxaV&F$H8yX1GIweAN$9vg;i2%V1jy&2^G%>40U=2$Bb
zIY{GqjNtu>IN};o><B|k)V>Z3K^RsbCEHsyE<c50*5})zr>0@(W$bPvNh%U)fMJBI
ztzL90`6mKOcQARCR`hLJxoJNcH%Z-@5fwz9AnKpI+y&56_Vs2bH6Dz0p0V>nUKlz0
z^GKf~rh21M+<>hQ7isP#B6I6>vOuh&i%b%13fF0xM5ox-!5$;bJ{78`mJ+wv`<%56
zu=GKt3Z^eH-f{er1&GUXpHnVeus4bHN|xc;=t{`u>Fdi(H+V66U?l)L|Ek5qcz7!O
zz1P<@l6G5_ab<WoA<TXnCH|`sCclkTp9z+S7WL3Cpegm{x&eip@W)87w&b<3VX380
zLC8Teukn(j#Z+bCaQl7$<1YUJ$J+q&=CBmAN10kcF%dnV7hG^RF4`INRpowOm55>$
zo`9oC1db;8XH~JV50g|r)$aEq9$g|LYSZ^|R|q9&rXr+4<fq`%{xkZG-CY<yi!T&j
z^NI;b%XgC6Mr4;>uSZi_QgOh4fzp%z?l@$Cx2?~@{+<Te(e});-<r*nj}B-KTpmC?
zT~g`UR)Kc{Z9w>Q(>zyHk1$!e<&3-`Hyqd+xs$(o@bLlvJ=o<q_$a|wVyp=g`V1lD
z;hFz?K0%ThIbZa@bCz3*RS2|G|8sJ|#pyqgVJ~NK>F5~SIs0ej*pW%0b+->2uWKAU
zd%_6P@J&<ieM{gJglDZ2WrvheNB#Y#l1U_7oKxc0hmeU@a!HjmMiqHJPK!fvbVZ9Z
z9EKl${@Dlug*B-E<3%RZ@|!sO=tp@Zei43IL=oh^WmfeKnC1}@j>R7F21b2&!$ZZZ
zZ3tT!{a#Hh>2)v>RYZqHPNq2q+A&W7c5+nha+hrgY+kAuiL<s_>zN_xZS?^5aCcm$
z2ce%*^fV2jBMG>APXJBV0iroj*-DHlrQu+!aR^+bRY@e-nOL|SH4c8YJQ~Xl3F(Q^
zk(*VrMT5GnS2`A=iX;s^;g@Cns>^QP#fp~-qBiGjmbQ2mTgpwg^#Avv#F27-Rjz7I
z?sD+B-V6g_s)41SHpRbd$YPU`xI5R4cToK8W*S23;QOG2-TdQ6no&$CvXZj@_B|w_
zYvc9{_0+wIHahJ8&Ic8vYAgR5!FFPNhL*KEPn;<>mZn!ad15byhumr^DiaxE4p9lx
z|0(Ru<DuNU04^pm*2t2C7|cwCCX^-al)*%pY}chy=vJ0)mh9UIV^4_4nq@4>MY=+a
z?b?!Ly{<J%5tFi1gZB)#`);4l`_5m#&*xd@{FZZ`^PK1WzGr#YKBuX5T*67WE5TM-
zzbZx|d+I0B6S|1V_F#|G19?2(Z}(~~M*yjF<ovtON^(!K_NYss&xY;J$q9d>IX=l^
zhZFqtNbv}pW%XQZ84meDrSY6c&NVbP=V~Vr;}!VavRuLWdpA=cm0cgr%IVNt;T`JG
zb2vTCMSrg@1(_;e78^(M!^H75jb(f^jB=n&#Z?WZj&V}6sS+;bF)R9=ooHOWB-$!j
z6^%t)1+cw+bji*2cj>F$`nDClT<r<#`ue2(;zj<>zg|^%5R_z*B9WY&Y{ea7Y}8X+
zP0d(zH{@vRBDTiDM(?N0HH*`{$Lg2Ri8hRS9^&$DdM)yS2_lzDA?iKkaKYa*K_fkh
zbrl_~SQU|^1*=CT&3;!V&d<~A%s9w>yFsPnv#D8ApRwgZ?FJlOKHd%YY7r^YMHQyp
zjp7LjC(E;qq6@RB6OL)}2fhrq1Y1OiXln?_nSUP#<{J8(>ltuaxy*=i;+%7x$_+7f
zf?4J#0%`x=Qa4v}#@F-mKN5M<?La?7hp+stPvt^FSyf}$4w)EhllS@iPTl{J^fPH#
zlk<f3D|#PdJv`0XDKk8;rF;n&`A{-E<9?R0!U#Y%{?bMWE79L1>iO85CmtEc%dpDL
z$zeZ+&u(IDU7ONPGpT<h7^uMa*zNH(w2OQ{!T;g4oxAaw9u3^o^WebEVo8wh(*1>Y
zPM_uj)TSnPTkdGoE|Z`Z<JdtN^VQA%_XezNv2os9#nQ>w48Qj_rFBoz(%)tPOg4mL
z@b+AFS%w~qw2KdZUu#Cix8(YbRXkyL6Fxlbzvjh%BAv+++P0iP8)&<WGJ01z{OOtF
z%SKsLBo+1MlSEyB#?7fjD=y)8R>Sh;-qRDzTps3YCj1ls@KQBZndiCOi<A?dAIp!u
zsj95K<jMp>ZJ9ZU!%&>EDIG)YcC_*&F3XYuC~$4t-+dOa*i3V|C0|r7)$m-c@I#vu
zb_-+?pT*Z!gv59i=DQud<3l}Asq)Z0{oSYZ@FccfeARx7q~kK-xRNmD%IqKcExDlX
zc9<;oSB1dG2Vg_`?VQxdwl60xHigHEubX^2<HWmtE<XZ)n_bs+F!OHqa2e^r&t2A8
zj#v3SVAmwG7YMwVD3L^)&eP!Y*%<Y0fB$%3EEp5&*Upq9REmSFth9$DJ1w-R=Cia~
z8dx%1*)JoVK@&R73q&z20?(ft3@O|k`9GJKj=r3UbE%0H=QDUXY6W4tt%I;TAn4Q&
zLybbkzKs4k#zWu27S^p~EDo}iKAUMFRn%tE(XMm1UF-6G`U|!*`~P_`p;eG@xs3d7
zFNQF4XBlNg)bVi<l?lK5ds2xdA51SlBHj_^pDabO3EAq&v>1~b!67{es}cUZntiJS
zZ7N%$=#)ZO8cud)nw<Z>G!;uoviiCMj^OQii?O5#M^SF}5Lz3sZJ3StIjG_V4Vgi3
z)1jeT8p5oW1GO_Cph$y8HE$#`1RAdUp+XKcrq$8dts8j!zZ<+2Bqb%@m1g#%3o1Lb
zq~=gM{-g<QNfK*mOZm}sTYez*{SW#7U)M33tpmJq=WET_xeqy^$2G`O9k3E7y&dhV
zep1WHexUbd%%NN3=$y!-v9_ahUd&?kj+ZK`1-18UKaTarE@kB13a;jv$(!NvH$B+l
zYXRA+NGLNKrs<Wh5a6~X_P9V14VP5k{8qZ=Fs%}^a?iV@6ca%7eqN_%j9IjTxFkjs
z-o?l{0`<|g>;wYLO&g?-a^p!67j(}<Dkw~$J-8CExSJJa9sv>px?7GQ$bz>&l^hRK
z+6J>~1^RaYjs4i!1~YGOVn#Ux;h2^A;nx!rw?AK%mX^Msp8g_TLtdiNXBp7uHa0fR
z71}X1HQxZ$+WcA!4LltLf#Ch(EO_EzDUor?IvxNUZEMrl%3PeC^_m-aI45amXP0pQ
zKKD~H^2j`ZGH=|tL5~QwY8J&Q8JL?Vi4K?m(hh{^@VyIfmxTbN@XD1h>g_%2?EC>h
z-U)<R>eABE{QUgN!YCJfoS|POSzeF+@EEEWHAe{2*(xh5OUx$eulolF!*y4Hh^xdI
z;$OtU7>XcV6HwdT51eyJO)nPz72s^P<QcoIE}ZlA^*wc}>49FH#PMH#(9_dnj0T7;
zRaiE)6;OeJ%$|v`wjMdH%?SwDz;7#u88KdOyZ5KulBBGqZ5|R)u#pljBr?b9sxk?m
zq2-^Nnu>IN3YcI>w!J1>1W4tR2FU!tmHB(Wp?0qg1JfTRCs$NhNJGt@mg3JXC~))_
z9*Px=>O;9o7kSJL)CH`IRVf0q5vZvE3ZI&uMz~!Z;Ta!=L1r)*zuCCx>r>WzHv%&>
zz0VdKozo)htUvCqp58QB>-F)Z&7C$N*<MsYJPT?E-f@HcfrAGP7&5o@^R(NG;M;~h
z5grOK2DbUp(a~>TWHzB7q?Pl>lk1t))oKj0_4V}@*@%WiL#}u|f;+bqRx6V)&Et|w
zx{P+s25>faiiPo%=F54cJ#!o^ot?d6a(qZE5gz|ldb+y0Q@cH4{35SGeh#ETI5;@i
zUb;b)Zf$L)YXHEORZ<l8yU^qh$jODJSifbiw%(K+vIUEJ(a_M3fL&tBK|Z52yDNa!
z@R=?sY^nXGEnWtX#{<iDTDSIH1X8ue!os4ZrA0zQVybtOEpS!oUKf>$zI4GNL8Koj
zqj>Gm&`>oswH~2|Ru#IMcFXT!D4JHgFa7H7?oNR(S4=I5k;4w9Jguo|dUX5o<7L1K
zXPpG*{LItpYFbqox0C&o>*Gd;`h%b>6Fyc_n>RH)GX=Pu({DHfx_hqa=;+wg`6N-5
zPmu6^eSNkgCm+0=s6Z+Bb2~w~X~1mv{6w=)5D`M$LM&h~m?KI`LG`xH{r$z0ib-8v
zhO>%~F4P-AHWJe|#Ai?^2Af)1cB(3PYPXJ!WzcLJBsb`3r?_Qwb~Zsq5v%Ma7nk$J
zb#GM+1^N47CH_F7i?BF(0{NLD&A?2|&vVzi!|>)#q~%g4*aXGIko!`B`Wt0XYzaHs
zj;X2b_2F7_%j0Ik)klCV+}Y9b!^pm4E~rR4v8<w^c!-gjmXL|qBLtc7pkz>EEG0di
z2TPV?5fB&WE+sq1c=0cMEv}<Vfog=7?g_X8sW?(L9`i#-hPd+z3Iq#C{5wcV$;t9^
za_1S!)=yl7;;2^Br_JbZF4PC`@W}ezZBu3K;u+a5DJi+u&JWrO6Vy`}RsSI__~~@)
zY^sh6VP`NOi=TjP2-o=WFT|iybs3r0P@|w(l!JoQ;-o*xS}UM$_N^@O!3TT;u}`8x
zvS4H=NHLDt(-&W{1!`RXqmmN~?Do#*&qL1~b)rNZ;pb1%M`1CTU<C`@oj^3Gl`NLS
z>E=B{ImQlm#@dY>*0jqKajR1;Q2={q%ETJXQl&R_{hM85V<W{sL?uo$3i&KKD2Qdv
zjelc9W@DqLzdy8FAo5Off0Hpc2-S(+z%aCv70wAjcbS?G?|Zk^Dc4@N#sF&iz=rM^
z(597zfw?Nq8-85mo?*hD%e#UXXq}y0RXA9}N}R5&*J+nm0ma_TLcz^{4QaSO0LeWK
zztf3Bb-u^^1pXWyoqQ7Ey3D%p6$1WSkAgnD8ULE8`oV)-0W-Eyev^%%VCg=8c3+xM
zi_gav@$6Ft0CZgEjGVlDQ~vP4fUwqO&=as(B5@{SB)plq`B5A$>moUh_T|&t$)8yh
znmwL@iD#}vrua`Iu7Pz{P*5oIh8(b)9v-3N>Q@v|Px@}>W3e2{#yux#p8j8!X25z$
z#CgInw!29s>6xXeI=i~Ml2^pE*!kDY0h}E&uJv&~4o`x#(op!Ca_YTY5fl_?tP)l2
z0nHp99`^S3270-)F)OO~7U8k)stdrI*A^y@vX5L5i_wj*Tw>0<ywQCr1*)_bXOGKS
zEl3=OlI3*$Q)VC`EaP#&;6rz0H~aGJo5Fa?A|N;F7iVKav2|)RRm!@`Df`vCvK;~(
zh%z2^kN1gQt(&iI5q4U?g&GuY)qj?k<AxSy=jKd}Y)vId_=#k+mX<`o9y*Z{6O*JF
zL+02v6TSRNe)*UP<i?(!moGt;gD+?vKK$^7v5HG$4tajGM&u7nyguSN!rN7KZ=Qe<
z<G|Y2<+-V;OKYeGy{S(JXGnjKta=nu)fhO?tougmd_5uUG4Zg9JwTtKBO8oGsA&WS
z+!--63oQP@M;A8z#&OECfQJsV>M4mb@Q7gm@i_AqXl;Z1MX;=yfdZh+?3uTI8b#Oj
zet%|r2%A43Xc79aKz4zO(O*jvs_-zK1vD0i#_HS!uNJ~B4BQg9GJBcI1knI^{s-*!
z=824i%GU9+|LH&6@w{xYD^A>;y^<#yGhWm6uf7DoECk*Ez80UDD6e>-&}Bs7h33ni
zoZ7eS)7>GzCnhHxt90i<FIt_}9PG`mt*rex`^8|}yV-IpWiZ$t!EJX@@!vho)DA++
z<S*#gOg~dc?k|5cOu7g(6vlYl4OP^SM1DpI3n^P9-hkV2NJB#V_uEdf2yNe2MoUB}
txzm|FM#w=N&LOuUh@{=$)_=2E*kqAV>Wv<iEYD+sACX|BQ+m>t{13q)j6eVY

diff --git a/doc/guides/nics/img/ice_dcf.svg b/doc/guides/nics/img/ice_dcf.svg
new file mode 100644
index 000000000..c6de820a0
--- /dev/null
+++ b/doc/guides/nics/img/ice_dcf.svg
@@ -0,0 +1,516 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="226.02977mm"
+   height="174.625mm"
+   viewBox="0 0 226.02977 174.625"
+   version="1.1"
+   id="svg8"
+   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+   sodipodi:docname="ice_dcf.svg">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.35"
+     inkscape:cx="415.71428"
+     inkscape:cy="-62.441805"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1001"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(4.1577365,-1.8005958)">
+    <g
+       id="layer1-9"
+       inkscape:label="Layer 1"
+       transform="translate(3.0238119,1.5119048)">
+      <g
+         transform="translate(-2.6458356,-49.514882)"
+         inkscape:label="Layer 1"
+         id="layer1-7">
+        <g
+           style="fill:none;stroke:none;stroke-linecap:square;stroke-miterlimit:10"
+           id="g4657"
+           transform="matrix(0.23544767,0,0,0.24253472,-4.5357128,49.803573)">
+          <g
+             id="g4558"
+             clip-path="url(#p.0)">
+            <path
+               id="path4382"
+               d="M 0,0 H 960 V 720 H 0 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4384"
+               d="M 72.002625,606.8819 H 876.63256 v 77.03937 H 72.002625 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#b7b7b7;fill-rule:evenodd" />
+            <path
+               id="path4386"
+               d="M 72.002625,606.8819 H 876.63256 v 77.03937 H 72.002625 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#b7b7b7;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4388"
+               d="m 164.20998,627.07874 h 104.85039 v 37.88977 H 164.20998 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#434343;fill-rule:evenodd" />
+            <path
+               id="path4390"
+               d="m 164.20998,627.07874 h 104.85039 v 37.88977 H 164.20998 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4392"
+               d="m 206.1529,653.9987 v -13.35938 h 5.04687 q 1.32813,0 2.03125,0.125 0.96875,0.17188 1.64063,0.64063 0.67187,0.45312 1.07812,1.28125 0.40625,0.82812 0.40625,1.82812 0,1.70313 -1.09375,2.89063 -1.07812,1.17187 -3.92187,1.17187 h -3.42188 v 5.42188 z m 1.76562,-7 h 3.45313 q 1.71875,0 2.4375,-0.64063 0.71875,-0.64062 0.71875,-1.79687 0,-0.84375 -0.42188,-1.4375 -0.42187,-0.59375 -1.125,-0.78125 -0.4375,-0.125 -1.64062,-0.125 h -3.42188 z m 10.7717,7 v -13.35938 h 9.01563 v 1.57813 h -7.25 v 4.14062 h 6.26562 v 1.57813 h -6.26562 v 6.0625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4394"
+               d="m 363.36746,627.07874 h 104.85037 v 37.88977 H 363.36746 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#434343;fill-rule:evenodd" />
+            <path
+               id="path4396"
+               d="m 363.36746,627.07874 h 104.85037 v 37.88977 H 363.36746 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4398"
+               d="m 409.12286,653.9987 -5.17188,-13.35938 h 1.92188 l 3.46875,9.70313 q 0.42187,1.17187 0.70312,2.1875 0.3125,-1.09375 0.71875,-2.1875 l 3.60938,-9.70313 h 1.79687 l -5.23437,13.35938 z m 8.72482,0 v -13.35938 h 9.01563 v 1.57813 h -7.25 v 4.14062 h 6.26562 v 1.57813 h -6.26562 v 6.0625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4400"
+               d="m 527.15485,627.07874 h 104.8504 v 37.88977 h -104.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill:#434343;fill-rule:evenodd" />
+            <path
+               id="path4402"
+               d="m 527.15485,627.07874 h 104.8504 v 37.88977 h -104.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4404"
+               d="m 572.9103,653.9987 -5.17188,-13.35938 h 1.92188 l 3.46875,9.70313 q 0.42187,1.17187 0.70312,2.1875 0.3125,-1.09375 0.71875,-2.1875 l 3.60938,-9.70313 h 1.79687 l -5.23437,13.35938 z m 8.72479,0 v -13.35938 h 9.01563 v 1.57813 h -7.25 v 4.14062 h 6.26562 v 1.57813 h -6.26562 v 6.0625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4406"
+               d="m 683.36743,627.07874 h 104.8504 v 37.88977 h -104.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill:#434343;fill-rule:evenodd" />
+            <path
+               id="path4408"
+               d="m 683.36743,627.07874 h 104.8504 v 37.88977 h -104.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4410"
+               d="m 729.12286,653.9987 -5.17188,-13.35938 h 1.92188 l 3.46875,9.70313 q 0.42187,1.17187 0.70312,2.1875 0.3125,-1.09375 0.71875,-2.1875 l 3.60938,-9.70313 h 1.79687 l -5.23437,13.35938 z m 8.72485,0 v -13.35938 h 9.01563 v 1.57813 h -7.25 v 4.14062 h 6.26562 v 1.57813 h -6.26562 v 6.0625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4412"
+               d="M 72,440.96588 H 876.62994 V 581.18634 H 72 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#cfe2f3;fill-rule:evenodd" />
+            <path
+               id="path4414"
+               d="M 72,440.96588 H 876.62994 V 581.18634 H 72 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#c9daf8;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4416"
+               d="m 840.4199,529.82153 h 36.62994 V 567.7113 H 840.4199 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4418"
+               d="m 850.81055,556.7415 v -13.35938 h 2.70313 v 5.9375 l 5.4375,-5.9375 h 3.625 l -5.01563,5.20313 5.29688,8.15625 h -3.48438 l -3.67187,-6.26563 -2.1875,2.23438 v 4.03125 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4420"
+               d="m 242.51706,463.70865 h 168.8504 v 82.11026 h -168.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill:#9900ff;fill-rule:evenodd" />
+            <path
+               id="path4422"
+               d="M 308.82507,503.42865 V 480.5224 h 7.42187 q 4.21875,0 5.5,0.34375 1.96875,0.51562 3.29688,2.25 1.32812,1.71875 1.32812,4.45312 0,2.10938 -0.76562,3.54688 -0.76563,1.4375 -1.95313,2.26562 -1.17187,0.8125 -2.39062,1.07813 -1.65625,0.32812 -4.79688,0.32812 h -3.01562 v 8.64063 z m 4.625,-19.03125 v 6.5 h 2.53125 q 2.73437,0 3.65625,-0.35938 0.92187,-0.35937 1.4375,-1.125 0.53125,-0.76562 0.53125,-1.78125 0,-1.25 -0.73438,-2.0625 -0.73437,-0.8125 -1.85937,-1.01562 -0.82813,-0.15625 -3.32813,-0.15625 z m 16.75,19.03125 V 480.5224 h 15.70312 v 3.875 h -11.07812 v 5.42187 h 9.5625 v 3.875 h -9.5625 v 9.73438 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4424"
+               d="m 302.04187,533.74866 v -17.1875 h 2.26563 v 8.53125 l 8.53125,-8.53125 h 3.07812 l -7.20312,6.96875 7.53125,10.21875 h -3 l -6.125,-8.70313 -2.8125,2.75 v 5.95313 z m 16.02344,0 v -17.1875 h 3.42187 l 4.0625,12.17187 q 0.5625,1.70313 0.82813,2.54688 0.29687,-0.9375 0.90625,-2.76563 l 4.125,-11.95312 h 3.04687 v 17.1875 h -2.1875 v -14.375 l -4.98437,14.375 h -2.0625 l -4.96875,-14.625 v 14.625 z m 20.07031,0 v -17.1875 h 5.90625 q 2.01563,0 3.0625,0.25 1.48438,0.34375 2.51563,1.23437 1.35937,1.14063 2.03125,2.9375 0.6875,1.78125 0.6875,4.07813 0,1.95312 -0.46875,3.46875 -0.45313,1.51562 -1.17188,2.51562 -0.70312,0.98438 -1.5625,1.54688 -0.84375,0.5625 -2.04687,0.85937 -1.20313,0.29688 -2.76563,0.29688 z m 2.26563,-2.03125 h 3.67187 q 1.70313,0 2.65625,-0.3125 0.96875,-0.3125 1.54688,-0.89063 0.8125,-0.8125 1.26562,-2.17187 0.45313,-1.375 0.45313,-3.3125 0,-2.70313 -0.89063,-4.14063 -0.89062,-1.45312 -2.15625,-1.9375 -0.90625,-0.35937 -2.9375,-0.35937 h -3.60937 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4426"
+               d="M 72,240.5538 H 876.62994 V 400.96325 H 72 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#c9daf8;fill-rule:evenodd" />
+            <path
+               id="path4428"
+               d="M 72,240.5538 H 876.62994 V 400.96325 H 72 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#c9daf8;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4430"
+               d="M 103.58006,269.6063 H 527.17061 V 370.64567 H 103.58006 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffd966;fill-rule:evenodd" />
+            <path
+               id="path4432"
+               d="M 103.58006,269.6063 H 527.17061 V 370.64567 H 103.58006 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#ffd966;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4434"
+               d="m 109.89764,300.6404 h 68.22047 v 51.77954 h -68.22047 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4436"
+               d="m 120.28826,327.56042 v -13.35937 h 2.625 l 5.45313,8.92187 v -8.92187 h 2.51563 v 13.35937 h -2.70313 l -5.39063,-8.70312 v 8.70312 z m 13.45733,0 v -13.35937 h 9.15625 v 2.26562 h -6.45313 v 3.15625 h 5.5625 v 2.26563 h -5.5625 v 5.67187 z m 14.7866,0 -4.78125,-13.35937 h 2.9375 l 3.375,9.89062 3.26563,-9.89062 h 2.85937 l -4.78125,13.35937 z m 8.68447,-10.98437 v -2.375 h 2.5625 v 2.375 z m 0,10.98437 v -9.67187 h 2.5625 v 9.67187 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4438"
+               d="m 194.51706,290.53018 h 104.8504 v 68.56692 h -104.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill:#00ffff;fill-rule:evenodd" />
+            <path
+               id="path4440"
+               d="m 227.57297,317.4502 v -13.35938 h 2.70312 v 5.26563 h 5.28125 v -5.26563 h 2.70313 v 13.35938 h -2.70313 v -5.84375 h -5.28125 v 5.84375 z m 12.86357,-4.96875 q 0,-1.28125 0.625,-2.46875 0.625,-1.20313 1.78125,-1.82813 1.15625,-0.625 2.57813,-0.625 2.1875,0 3.59375,1.42188 1.40625,1.42187 1.40625,3.60937 0,2.1875 -1.42188,3.64063 -1.42187,1.4375 -3.5625,1.4375 -1.32812,0 -2.54687,-0.59375 -1.20313,-0.60938 -1.82813,-1.76563 -0.625,-1.17187 -0.625,-2.82812 z m 2.625,0.125 q 0,1.45312 0.67188,2.21875 0.6875,0.75 1.6875,0.75 1,0 1.67187,-0.75 0.6875,-0.76563 0.6875,-2.23438 0,-1.42187 -0.6875,-2.1875 -0.67187,-0.76562 -1.67187,-0.76562 -1,0 -1.6875,0.76562 -0.67188,0.76563 -0.67188,2.20313 z m 8.45848,2.07812 2.5625,-0.39062 q 0.17188,0.75 0.67188,1.14062 0.5,0.39063 1.40625,0.39063 0.98437,0 1.48437,-0.375 0.34375,-0.25 0.34375,-0.67188 0,-0.29687 -0.1875,-0.48437 -0.1875,-0.1875 -0.85937,-0.34375 -3.09375,-0.6875 -3.92188,-1.25 -1.14062,-0.78125 -1.14062,-2.17188 0,-1.26562 0.98437,-2.10937 1,-0.85938 3.07813,-0.85938 1.98437,0 2.95312,0.65625 0.96875,0.64063 1.32813,1.90625 l -2.40625,0.4375 q -0.15625,-0.5625 -0.59375,-0.85937 -0.42188,-0.29688 -1.23438,-0.29688 -1,0 -1.4375,0.28125 -0.29687,0.20313 -0.29687,0.51563 0,0.26562 0.25,0.46875 0.34375,0.25 2.39062,0.71875 2.04688,0.45312 2.85938,1.14062 0.79687,0.67188 0.79687,1.89063 0,1.34375 -1.10937,2.29687 -1.10938,0.95313 -3.28125,0.95313 -1.98438,0 -3.14063,-0.79688 -1.14062,-0.8125 -1.5,-2.1875 z m 15.71948,-6.90625 v 2.03125 h -1.75 v 3.90625 q 0,1.1875 0.0469,1.39063 0.0469,0.1875 0.21875,0.3125 0.1875,0.125 0.4375,0.125 0.35937,0 1.03125,-0.25 l 0.21875,2 q -0.89063,0.375 -2.01563,0.375 -0.70312,0 -1.26562,-0.23438 -0.54688,-0.23437 -0.8125,-0.59375 -0.25,-0.375 -0.34375,-1 -0.0937,-0.45312 -0.0937,-1.8125 v -4.21875 h -1.17188 v -2.03125 h 1.17188 v -1.92187 l 2.57812,-1.5 v 3.42187 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4442"
+               d="m 220.8043,332.85645 q 0,-2.04688 0.60937,-3.42188 0.45313,-1.03125 1.23438,-1.82812 0.79687,-0.8125 1.73437,-1.20313 1.25,-0.53125 2.875,-0.53125 2.95313,0 4.71875,1.82813 1.78125,1.82812 1.78125,5.09375 0,3.23437 -1.76562,5.0625 -1.75,1.82812 -4.6875,1.82812 -2.98438,0 -4.75,-1.8125 -1.75,-1.82812 -1.75,-5.01562 z m 2.78125,-0.0937 q 0,2.26562 1.04687,3.4375 1.04688,1.17187 2.65625,1.17187 1.60938,0 2.64063,-1.15625 1.04687,-1.17187 1.04687,-3.48437 0,-2.29688 -1.01562,-3.42188 -1,-1.14062 -2.67188,-1.14062 -1.67187,0 -2.6875,1.15625 -1.01562,1.14062 -1.01562,3.4375 z m 11.58955,2.34375 2.625,-0.25 q 0.23438,1.3125 0.95313,1.9375 0.73437,0.60937 1.96875,0.60937 1.29687,0 1.95312,-0.54687 0.67188,-0.54688 0.67188,-1.28125 0,-0.48438 -0.28125,-0.8125 -0.28125,-0.32813 -0.96875,-0.57813 -0.48438,-0.15625 -2.17188,-0.57812 -2.15625,-0.54688 -3.03125,-1.32813 -1.23437,-1.09375 -1.23437,-2.6875 0,-1.01562 0.57812,-1.90625 0.57813,-0.89062 1.65625,-1.34375 1.09375,-0.46875 2.64063,-0.46875 2.51562,0 3.78125,1.10938 1.28125,1.09375 1.34375,2.9375 l -2.70313,0.10937 q -0.17187,-1.03125 -0.75,-1.46875 -0.5625,-0.45312 -1.70312,-0.45312 -1.17188,0 -1.84375,0.46875 -0.42188,0.3125 -0.42188,0.84375 0,0.46875 0.40625,0.79687 0.5,0.4375 2.46875,0.90625 1.96875,0.45313 2.90625,0.95313 0.95313,0.5 1.48438,1.35937 0.53125,0.85938 0.53125,2.125 0,1.15625 -0.64063,2.15625 -0.64062,1 -1.8125,1.48438 -1.15625,0.48437 -2.89062,0.48437 -2.53125,0 -3.89063,-1.17187 -1.35937,-1.17188 -1.625,-3.40625 z m 18.23626,4.34375 v -13.35938 h 2.68751 v 13.35938 z m 3.8708,0.23437 3.3125,-13.8125 h 1.92187 l -3.34375,13.8125 z m 6.58957,-0.23437 v -13.35938 h 9.15625 v 2.26563 h -6.45313 v 3.15625 h 5.5625 v 2.26562 h -5.5625 v 5.67188 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4444"
+               d="m 389.88715,290.53806 h 104.85037 v 68.56692 H 389.88715 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#1c4587;fill-rule:evenodd" />
+            <path
+               id="path4446"
+               d="M 424.5789,317.45807 V 304.0987 h 4.60937 q 1.54688,0 2.375,0.20312 1.14063,0.25 1.95313,0.95313 1.0625,0.89062 1.57812,2.28125 0.53125,1.39062 0.53125,3.17187 0,1.51563 -0.35937,2.70313 -0.35938,1.17187 -0.92188,1.9375 -0.54687,0.76562 -1.20312,1.21875 -0.65625,0.4375 -1.59375,0.67187 -0.9375,0.21875 -2.14063,0.21875 z m 1.76562,-1.57812 h 2.85938 q 1.3125,0 2.0625,-0.23438 0.75,-0.25 1.20312,-0.70312 0.625,-0.625 0.96875,-1.6875 0.35938,-1.0625 0.35938,-2.57813 0,-2.09375 -0.6875,-3.21875 -0.6875,-1.125 -1.67188,-1.5 -0.70312,-0.28125 -2.28125,-0.28125 h -2.8125 z m 21.23859,-3.10938 1.76563,0.45313 q -0.5625,2.17187 -2,3.32812 -1.4375,1.14063 -3.53125,1.14063 -2.15625,0 -3.51563,-0.875 -1.34375,-0.89063 -2.0625,-2.54688 -0.70312,-1.67187 -0.70312,-3.59375 0,-2.07812 0.79687,-3.625 0.79688,-1.5625 2.26563,-2.35937 1.48437,-0.8125 3.25,-0.8125 2,0 3.35937,1.01562 1.375,1.01563 1.90625,2.875 l -1.73437,0.40625 q -0.46875,-1.45312 -1.35938,-2.10937 -0.875,-0.67188 -2.20312,-0.67188 -1.54688,0 -2.57813,0.73438 -1.03125,0.73437 -1.45312,1.98437 -0.42188,1.23438 -0.42188,2.5625 0,1.70313 0.5,2.96875 0.5,1.26563 1.54688,1.90625 1.04687,0.625 2.26562,0.625 1.48438,0 2.51563,-0.85937 1.03125,-0.85938 1.39062,-2.54688 z m 4.03543,4.6875 V 304.0987 h 9.01563 v 1.57812 h -7.25 v 4.14063 h 6.26562 v 1.57812 h -6.26562 v 6.0625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4448"
+               d="m 434.4172,324.79117 h 1.26562 v 5.51563 q 0,1.4375 -0.32812,2.29687 -0.3125,0.84375 -1.17188,1.375 -0.84375,0.51563 -2.21875,0.51563 -1.34375,0 -2.20312,-0.45313 -0.84375,-0.46875 -1.21875,-1.34375 -0.35938,-0.875 -0.35938,-2.39062 v -5.51563 h 1.26563 v 5.51563 q 0,1.23437 0.21875,1.82812 0.23437,0.59375 0.79687,0.92188 0.5625,0.3125 1.39063,0.3125 1.39062,0 1.96875,-0.625 0.59375,-0.64063 0.59375,-2.4375 z m 3.32828,9.54688 v -9.54688 h 1.90625 l 2.25,6.76563 q 0.3125,0.9375 0.46875,1.40625 0.15625,-0.51563 0.5,-1.53125 l 2.28125,-6.64063 h 1.70312 v 9.54688 h -1.21875 v -7.98438 l -2.76562,7.98438 h -1.14063 l -2.76562,-8.125 v 8.125 z m 11.14932,0 v -9.54688 h 3.28125 q 1.10938,0 1.70313,0.14063 0.8125,0.1875 1.39062,0.6875 0.76563,0.64062 1.14063,1.64062 0.375,0.98438 0.375,2.25 0,1.09375 -0.26563,1.9375 -0.25,0.82813 -0.65625,1.39063 -0.39062,0.54687 -0.85937,0.85937 -0.46875,0.3125 -1.14063,0.48438 -0.65625,0.15625 -1.53125,0.15625 z m 1.26563,-1.125 h 2.03125 q 0.9375,0 1.46875,-0.17188 0.54687,-0.1875 0.875,-0.5 0.4375,-0.45312 0.6875,-1.20312 0.25,-0.76563 0.25,-1.84375 0,-1.5 -0.5,-2.29688 -0.48438,-0.8125 -1.1875,-1.07812 -0.5,-0.20313 -1.625,-0.20313 h -2 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4450"
+               d="m 840.41205,357.18372 h 36.62994 v 37.88977 h -36.62994 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4452"
+               d="m 850.7558,370.74435 h 2.6875 v 7.23437 q 0,1.71875 0.10938,2.23438 0.17187,0.82812 0.8125,1.32812 0.65625,0.48438 1.78125,0.48438 1.15625,0 1.73437,-0.46875 0.59375,-0.46875 0.70313,-1.14063 0.125,-0.6875 0.125,-2.28125 v -7.39062 h 2.6875 v 7.01562 q 0,2.40625 -0.21875,3.40625 -0.21875,0.98438 -0.8125,1.67188 -0.57813,0.6875 -1.5625,1.09375 -0.98438,0.40625 -2.5625,0.40625 -1.92188,0 -2.90625,-0.4375 -0.98438,-0.45313 -1.5625,-1.15625 -0.57813,-0.70313 -0.75,-1.48438 -0.26563,-1.14062 -0.26563,-3.39062 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4454"
+               d="m 612.63257,1.816273 h 264 V 222.4462 h -264 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:evenodd" />
+            <path
+               id="path4456"
+               d="m 612.63257,1.816273 h 264 V 222.4462 h -264 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4458"
+               d="m 622.73755,11.92126 h 240 v 90.96063 h -240 z"
+               inkscape:connector-curvature="0"
+               style="fill:#c9daf8;fill-rule:evenodd" />
+            <path
+               id="path4460"
+               d="m 622.73755,11.92126 h 240 v 90.96063 h -240 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#d0e0e3;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4462"
+               d="m 627.79004,119.28871 h 234.96063 v 90.96063 H 627.79004 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#cfe2f3;fill-rule:evenodd" />
+            <path
+               id="path4464"
+               d="m 627.79004,119.28871 h 234.96063 v 90.96063 H 627.79004 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#c9daf8;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4466"
+               d="m 636.63257,27.078741 h 84.62988 v 60.44094 h -84.62988 z"
+               inkscape:connector-curvature="0"
+               style="fill:#1c4587;fill-rule:evenodd" />
+            <path
+               id="path4468"
+               d="m 660.66064,42.529987 v -1.890625 h 1.64062 v 1.890625 z m 0,11.46875 v -9.671875 h 1.64062 v 9.671875 z m 2.87915,0 5.125,-13.359375 h 1.90625 l 5.46875,13.359375 h -2.01562 l -1.54688,-4.046875 h -5.59375 l -1.46875,4.046875 z m 3.85938,-5.484375 h 4.53125 l -1.40625,-3.703125 q -0.625,-1.6875 -0.9375,-2.765625 -0.26563,1.28125 -0.71875,2.546875 z m 12.48004,5.484375 -5.17188,-13.359375 h 1.92188 l 3.46875,9.703125 q 0.42187,1.171875 0.70312,2.1875 0.3125,-1.09375 0.71875,-2.1875 l 3.60938,-9.703125 h 1.79687 l -5.23437,13.359375 z m 8.72485,0 V 40.639362 h 9.01563 v 1.578125 h -7.25 v 4.140625 h 6.26562 v 1.578125 h -6.26562 v 6.0625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4470"
+               d="m 671.05237,61.331863 h 1.26562 v 5.515625 q 0,1.4375 -0.32812,2.296875 -0.3125,0.84375 -1.17188,1.375 -0.84375,0.515625 -2.21875,0.515625 -1.34375,0 -2.20312,-0.453125 -0.84375,-0.46875 -1.21875,-1.34375 -0.35938,-0.875 -0.35938,-2.390625 v -5.515625 h 1.26563 v 5.515625 q 0,1.234375 0.21875,1.828125 0.23437,0.59375 0.79687,0.921875 0.5625,0.3125 1.39063,0.3125 1.39062,0 1.96875,-0.625 0.59375,-0.640625 0.59375,-2.4375 z m 3.32831,9.546875 v -9.546875 h 1.90625 l 2.25,6.765625 q 0.3125,0.9375 0.46875,1.40625 0.15625,-0.515625 0.5,-1.53125 l 2.28125,-6.640625 h 1.70312 v 9.546875 h -1.21875 v -7.984375 l -2.76562,7.984375 h -1.14063 l -2.76562,-8.125 v 8.125 z m 11.14929,0 v -9.546875 h 3.28125 q 1.10937,0 1.70312,0.140625 0.8125,0.1875 1.39063,0.6875 0.76562,0.640625 1.14062,1.640625 0.375,0.984375 0.375,2.25 0,1.09375 -0.26562,1.9375 -0.25,0.828125 -0.65625,1.390625 -0.39063,0.546875 -0.85938,0.859375 -0.46875,0.3125 -1.14062,0.484375 -0.65625,0.15625 -1.53125,0.15625 z m 1.26562,-1.125 h 2.03125 q 0.9375,0 1.46875,-0.171875 0.54688,-0.1875 0.875,-0.5 0.4375,-0.453125 0.6875,-1.203125 0.25,-0.765625 0.25,-1.84375 0,-1.5 -0.5,-2.296875 -0.48437,-0.8125 -1.1875,-1.078125 -0.5,-0.203125 -1.625,-0.203125 h -2 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4472"
+               d="M 736.853,3.0787401 H 882.11283 V 27.07874 H 736.853 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4474"
+               d="m 749.603,26.158741 -3.75,-10.484376 h 2.29687 l 2.64063,7.750001 2.57812,-7.750001 h 2.25 L 751.853,26.158741 Z m 7.05682,0 V 15.674365 h 3.17188 l 1.90625,7.156251 1.89062,-7.156251 h 3.17188 v 10.484376 h -1.96875 v -8.265625 l -2.07813,8.265625 h -2.04687 l -2.07813,-8.265625 v 8.265625 z m 15.84327,-3.90625 q 0,-1 0.48437,-1.9375 0.5,-0.9375 1.40625,-1.421875 0.90625,-0.5 2.01563,-0.5 1.71875,0 2.82812,1.125 1.10938,1.109375 1.10938,2.8125 0,1.734375 -1.125,2.875 -1.10938,1.125 -2.79688,1.125 -1.04687,0 -2,-0.46875 -0.9375,-0.46875 -1.4375,-1.375 -0.48437,-0.921875 -0.48437,-2.234375 z m 2.04687,0.109375 q 0,1.125 0.53125,1.734375 0.54688,0.59375 1.34375,0.59375 0.78125,0 1.3125,-0.59375 0.53125,-0.609375 0.53125,-1.75 0,-1.125 -0.53125,-1.71875 -0.53125,-0.609375 -1.3125,-0.609375 -0.79687,0 -1.34375,0.609375 -0.53125,0.59375 -0.53125,1.734375 z m 9.29639,3.796875 h -2.01563 v -7.59375 h 1.85938 v 1.078125 q 0.48437,-0.765625 0.85937,-1 0.39063,-0.25 0.875,-0.25 0.6875,0 1.32813,0.375 l -0.625,1.75 q -0.5,-0.328125 -0.9375,-0.328125 -0.42188,0 -0.71875,0.234375 -0.29688,0.234375 -0.46875,0.84375 -0.15625,0.609375 -0.15625,2.546875 z m 14.57245,-3.859375 2.04687,0.65625 q -0.46875,1.71875 -1.57812,2.546875 -1.09375,0.828125 -2.78125,0.828125 -2.07813,0 -3.4375,-1.421875 -1.34375,-1.421875 -1.34375,-3.90625 0,-2.609375 1.35937,-4.0625 1.35938,-1.453126 3.5625,-1.453126 1.92188,0 3.125,1.140626 0.71875,0.671875 1.0625,1.9375 l -2.09375,0.5 q -0.1875,-0.828125 -0.78125,-1.296875 -0.57812,-0.46875 -1.42187,-0.46875 -1.17188,0 -1.90625,0.84375 -0.71875,0.828125 -0.71875,2.703125 0,1.984375 0.71875,2.84375 0.71875,0.84375 1.85937,0.84375 0.84375,0 1.45313,-0.53125 0.60937,-0.546875 0.875,-1.703125 z m 3.39679,-0.04687 q 0,-1 0.48437,-1.9375 0.5,-0.9375 1.40625,-1.421875 0.90625,-0.5 2.01563,-0.5 1.71875,0 2.82812,1.125 1.10938,1.109375 1.10938,2.8125 0,1.734375 -1.125,2.875 -1.10938,1.125 -2.79688,1.125 -1.04687,0 -2,-0.46875 -0.9375,-0.46875 -1.4375,-1.375 -0.48437,-0.921875 -0.48437,-2.234375 z m 2.04687,0.109375 q 0,1.125 0.53125,1.734375 0.54688,0.59375 1.34375,0.59375 0.78125,0 1.3125,-0.59375 0.53125,-0.609375 0.53125,-1.75 0,-1.125 -0.53125,-1.71875 -0.53125,-0.609375 -1.3125,-0.609375 -0.79687,0 -1.34375,0.609375 -0.53125,0.59375 -0.53125,1.734375 z m 14.28076,3.796875 h -2.01562 v -3.875 q 0,-1.234375 -0.125,-1.59375 -0.125,-0.359375 -0.42188,-0.5625 -0.29687,-0.203125 -0.70312,-0.203125 -0.51563,0 -0.9375,0.296875 -0.40625,0.28125 -0.5625,0.75 -0.15625,0.46875 -0.15625,1.75 v 3.4375 h -2.01563 v -7.59375 h 1.875 v 1.109375 q 1,-1.28125 2.5,-1.28125 0.67188,0 1.21875,0.234375 0.54688,0.234375 0.82813,0.609375 0.29687,0.375 0.40625,0.84375 0.10937,0.46875 0.10937,1.359375 z m 5.51514,-7.59375 v 1.59375 h -1.375 v 3.0625 q 0,0.9375 0.0312,1.09375 0.0469,0.140625 0.1875,0.25 0.14062,0.09375 0.34375,0.09375 0.28125,0 0.8125,-0.1875 l 0.17187,1.5625 q -0.70312,0.296875 -1.59375,0.296875 -0.54687,0 -0.98437,-0.171875 -0.42188,-0.1875 -0.64063,-0.46875 -0.20312,-0.296875 -0.28125,-0.796875 -0.0625,-0.359375 -0.0625,-1.421875 v -3.3125 h -0.92187 v -1.59375 h 0.92187 v -1.515625 l 2.01563,-1.171876 v 2.687501 z m 2.91187,2.3125 -1.82813,-0.328125 q 0.29688,-1.109375 1.04688,-1.625 0.76562,-0.53125 2.23437,-0.53125 1.35938,0 2.01563,0.3125 0.65625,0.3125 0.92187,0.8125 0.26563,0.484375 0.26563,1.796875 l -0.0156,2.34375 q 0,1 0.0937,1.484375 0.0937,0.46875 0.35938,1.015625 h -1.98438 q -0.0781,-0.203125 -0.20312,-0.59375 -0.0469,-0.171875 -0.0625,-0.234375 -0.51563,0.5 -1.10938,0.75 -0.57812,0.25 -1.25,0.25 -1.17187,0 -1.85937,-0.640625 -0.67188,-0.640625 -0.67188,-1.609375 0,-0.640625 0.3125,-1.140625 0.3125,-0.515625 0.85938,-0.78125 0.5625,-0.265625 1.60937,-0.46875 1.40625,-0.265625 1.95313,-0.484375 v -0.203125 q 0,-0.578125 -0.29688,-0.828125 -0.28125,-0.25 -1.07812,-0.25 -0.53125,0 -0.84375,0.21875 -0.29688,0.203125 -0.46875,0.734375 z m 2.6875,1.625 q -0.39063,0.140625 -1.23438,0.328125 -0.82812,0.171875 -1.09375,0.34375 -0.39062,0.265625 -0.39062,0.703125 0,0.421875 0.3125,0.734375 0.3125,0.296875 0.8125,0.296875 0.53125,0 1.03125,-0.359375 0.35937,-0.265625 0.48437,-0.65625 0.0781,-0.265625 0.0781,-0.984375 z m 3.94799,-4.96875 V 15.67437 h 2.01563 v 1.859376 z m 0,8.625 v -7.59375 h 2.01563 v 7.59375 z m 10.99384,0 h -2.01563 v -3.875 q 0,-1.234375 -0.125,-1.59375 -0.125,-0.359375 -0.42187,-0.5625 -0.29688,-0.203125 -0.70313,-0.203125 -0.51562,0 -0.9375,0.296875 -0.40625,0.28125 -0.5625,0.75 -0.15625,0.46875 -0.15625,1.75 v 3.4375 h -2.01562 v -7.59375 h 1.875 v 1.109375 q 1,-1.28125 2.5,-1.28125 0.67187,0 1.21875,0.234375 0.54687,0.234375 0.82812,0.609375 0.29688,0.375 0.40625,0.84375 0.10938,0.46875 0.10938,1.359375 z m 6.43701,-2.421875 2,0.34375 q -0.375,1.09375 -1.21875,1.671875 -0.82813,0.578125 -2.07813,0.578125 -1.98437,0 -2.9375,-1.296875 -0.75,-1.03125 -0.75,-2.625 0,-1.875 0.98438,-2.9375 0.98437,-1.078125 2.5,-1.078125 1.6875,0 2.67187,1.125 0.98438,1.109375 0.9375,3.421875 h -5.03125 q 0.0156,0.890625 0.48438,1.390625 0.46875,0.5 1.15625,0.5 0.46875,0 0.78125,-0.25 0.32812,-0.265625 0.5,-0.84375 z m 0.10937,-2.03125 q -0.0156,-0.875 -0.45312,-1.328125 -0.42188,-0.453125 -1.03125,-0.453125 -0.67188,0 -1.09375,0.484375 -0.42188,0.46875 -0.42188,1.296875 z m 5.573,4.453125 h -2.01562 v -7.59375 h 1.85937 v 1.078125 q 0.48438,-0.765625 0.85938,-1 0.39062,-0.25 0.875,-0.25 0.6875,0 1.32812,0.375 l -0.625,1.75 q -0.5,-0.328125 -0.9375,-0.328125 -0.42187,0 -0.71875,0.234375 -0.29687,0.234375 -0.46875,0.84375 -0.15625,0.609375 -0.15625,2.546875 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4476"
+               d="m 826.52496,59.92651 h 36.62988 v 37.889767 h -36.62988 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4478"
+               d="m 836.8687,73.48713 h 2.6875 v 7.234375 q 0,1.71875 0.10937,2.234375 0.17188,0.828125 0.8125,1.328125 0.65625,0.484375 1.78125,0.484375 1.15625,0 1.73438,-0.46875 0.59375,-0.46875 0.70312,-1.140625 0.125,-0.6875 0.125,-2.28125 V 73.48713 h 2.6875 v 7.015625 q 0,2.40625 -0.21875,3.40625 -0.21875,0.984375 -0.8125,1.671875 -0.57812,0.6875 -1.5625,1.09375 -0.98437,0.40625 -2.5625,0.40625 -1.92187,0 -2.90625,-0.4375 -0.98437,-0.453125 -1.5625,-1.15625 -0.57812,-0.703125 -0.75,-1.484375 -0.26562,-1.140625 -0.26562,-3.390625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4480"
+               d="m 826.5276,169.82152 h 36.62988 v 37.88977 H 826.5276 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4482"
+               d="m 836.9182,196.74152 v -13.35938 h 2.70312 v 5.9375 l 5.4375,-5.9375 h 3.625 l -5.01562,5.20313 5.29687,8.15625 h -3.48437 l -3.67188,-6.26563 -2.1875,2.23438 v 4.03125 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4484"
+               d="m 737.26245,130.83989 h 84.62994 v 60.44095 h -84.62994 z"
+               inkscape:connector-curvature="0"
+               style="fill:#999999;fill-rule:evenodd" />
+            <path
+               id="path4486"
+               d="m 761.2905,146.29114 v -1.89062 h 1.64062 v 1.89062 z m 0,11.46875 v -9.67187 h 1.64062 v 9.67187 z m 2.87921,0 5.125,-13.35937 h 1.90625 l 5.46875,13.35937 h -2.01562 l -1.54688,-4.04687 h -5.59375 l -1.46875,4.04687 z m 3.85938,-5.48437 h 4.53125 l -1.40625,-3.70313 q -0.625,-1.6875 -0.9375,-2.76562 -0.26563,1.28125 -0.71875,2.54687 z m 12.48004,5.48437 -5.17188,-13.35937 h 1.92188 l 3.46875,9.70312 q 0.42187,1.17188 0.70312,2.1875 0.3125,-1.09375 0.71875,-2.1875 l 3.60938,-9.70312 h 1.79687 l -5.23437,13.35937 z m 8.72479,0 v -13.35937 h 9.01563 v 1.57812 h -7.25 v 4.14063 h 6.26562 v 1.57812 h -6.26562 v 6.0625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4488"
+               d="m 765.7375,174.6399 v -9.54688 h 1.26562 v 4.73438 l 4.73438,-4.73438 h 1.71875 l -4,3.875 4.17187,5.67188 h -1.65625 l -3.40625,-4.82813 -1.5625,1.51563 v 3.3125 z m 8.9054,0 v -9.54688 h 1.90625 l 2.25,6.76563 q 0.3125,0.9375 0.46875,1.40625 0.15625,-0.51563 0.5,-1.53125 l 2.28125,-6.64063 h 1.70312 v 9.54688 h -1.21875 v -7.98438 l -2.76562,7.98438 h -1.14063 l -2.76562,-8.125 v 8.125 z m 11.14929,0 v -9.54688 h 3.28125 q 1.10937,0 1.70312,0.14063 0.8125,0.1875 1.39063,0.6875 0.76562,0.64062 1.14062,1.64062 0.375,0.98438 0.375,2.25 0,1.09375 -0.26562,1.9375 -0.25,0.82813 -0.65625,1.39063 -0.39063,0.54687 -0.85938,0.85937 -0.46875,0.3125 -1.14062,0.48438 -0.65625,0.15625 -1.53125,0.15625 z m 1.26562,-1.125 h 2.03125 q 0.9375,0 1.46875,-0.17188 0.54688,-0.1875 0.875,-0.5 0.4375,-0.45312 0.6875,-1.20312 0.25,-0.76563 0.25,-1.84375 0,-1.5 -0.5,-2.29688 -0.48437,-0.8125 -1.1875,-1.07812 -0.5,-0.20313 -1.625,-0.20313 h -2 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffffff;fill-rule:nonzero" />
+            <path
+               id="path4490"
+               d="m 104.41995,29.606298 h 195.7795 v 90.960632 h -195.7795 z"
+               inkscape:connector-curvature="0"
+               style="fill:#ffd966;fill-rule:evenodd" />
+            <path
+               id="path4492"
+               d="m 104.41995,29.606298 h 195.7795 v 90.960632 h -195.7795 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#ffd966;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4494"
+               d="M 134.73753,27.921259 H 264.84777 V 118.88189 H 134.73753 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4496"
+               d="M 166.94131,54.84126 V 41.481885 h 5.6875 q 2.14062,0 3.10937,0.359375 0.96875,0.359375 1.54688,1.28125 0.57812,0.921875 0.57812,2.109375 0,1.5 -0.89062,2.484375 -0.875,0.96875 -2.625,1.234375 0.875,0.5 1.4375,1.125 0.57812,0.609375 1.53125,2.15625 l 1.64062,2.609375 h -3.23437 l -1.9375,-2.90625 q -1.04688,-1.5625 -1.4375,-1.96875 -0.375,-0.40625 -0.8125,-0.546875 -0.42188,-0.15625 -1.34375,-0.15625 h -0.54688 v 5.578125 z m 2.70312,-7.703125 h 2 q 1.9375,0 2.42188,-0.15625 0.48437,-0.171875 0.75,-0.578125 0.28125,-0.40625 0.28125,-1 0,-0.671875 -0.35938,-1.078125 -0.35937,-0.421875 -1.01562,-0.53125 -0.32813,-0.04687 -1.96875,-0.04687 h -2.10938 z m 16.34795,4.625 2.54688,0.421875 q -0.48438,1.40625 -1.54688,2.140625 -1.0625,0.734375 -2.65625,0.734375 -2.51562,0 -3.73437,-1.65625 -0.95313,-1.3125 -0.95313,-3.328125 0,-2.40625 1.25,-3.765625 1.26563,-1.359375 3.1875,-1.359375 2.15625,0 3.40625,1.421875 1.25,1.421875 1.1875,4.375 h -6.40625 q 0.0312,1.140625 0.60938,1.78125 0.59375,0.625 1.48437,0.625 0.59375,0 1,-0.328125 0.42188,-0.328125 0.625,-1.0625 z m 0.15625,-2.59375 q -0.0312,-1.109375 -0.57812,-1.6875 -0.54688,-0.578125 -1.32813,-0.578125 -0.84375,0 -1.39062,0.609375 -0.54688,0.609375 -0.53125,1.65625 z m 4.42259,-4 h 2.35938 v 1.3125 q 1.26562,-1.53125 3.01562,-1.53125 0.9375,0 1.60938,0.390625 0.6875,0.375 1.125,1.140625 0.64062,-0.765625 1.375,-1.140625 0.75,-0.390625 1.57812,-0.390625 1.0625,0 1.79688,0.4375 0.75,0.421875 1.10937,1.265625 0.26563,0.625 0.26563,2 v 6.1875 h -2.5625 v -5.53125 q 0,-1.4375 -0.26563,-1.859375 -0.34375,-0.546875 -1.09375,-0.546875 -0.53125,0 -1.01562,0.328125 -0.46875,0.328125 -0.67188,0.96875 -0.20312,0.625 -0.20312,2 v 4.640625 h -2.5625 v -5.296875 q 0,-1.421875 -0.14063,-1.828125 -0.14062,-0.40625 -0.42187,-0.609375 -0.28125,-0.203125 -0.78125,-0.203125 -0.59375,0 -1.0625,0.328125 -0.46875,0.3125 -0.6875,0.921875 -0.20313,0.59375 -0.20313,1.984375 v 4.703125 h -2.5625 z m 16.19777,4.703125 q 0,-1.28125 0.625,-2.46875 0.625,-1.203125 1.78125,-1.828125 1.15625,-0.625 2.57813,-0.625 2.1875,0 3.59375,1.421875 1.40625,1.421875 1.40625,3.609375 0,2.1875 -1.42188,3.640625 -1.42187,1.4375 -3.5625,1.4375 -1.32812,0 -2.54687,-0.59375 -1.20313,-0.609375 -1.82813,-1.765625 -0.625,-1.171875 -0.625,-2.828125 z m 2.625,0.125 q 0,1.453125 0.67188,2.21875 0.6875,0.75 1.6875,0.75 1,0 1.67187,-0.75 0.6875,-0.765625 0.6875,-2.234375 0,-1.421875 -0.6875,-2.1875 -0.67187,-0.765625 -1.67187,-0.765625 -1,0 -1.6875,0.765625 -0.67188,0.765625 -0.67188,2.203125 z m 13.80223,-4.828125 v 2.03125 h -1.75 v 3.90625 q 0,1.1875 0.0469,1.390625 0.0469,0.1875 0.21875,0.3125 0.1875,0.125 0.4375,0.125 0.35937,0 1.03125,-0.25 l 0.21875,2 q -0.89063,0.375 -2.01563,0.375 -0.70312,0 -1.26562,-0.234375 -0.54688,-0.234375 -0.8125,-0.59375 -0.25,-0.375 -0.34375,-1 -0.0937,-0.453125 -0.0937,-1.8125 v -4.21875 h -1.17188 v -2.03125 h 1.17188 V 43.24751 l 2.57812,-1.5 v 3.421875 z m 7.36893,6.59375 2.54688,0.421875 q -0.48438,1.40625 -1.54688,2.140625 -1.0625,0.734375 -2.65625,0.734375 -2.51562,0 -3.73437,-1.65625 -0.95313,-1.3125 -0.95313,-3.328125 0,-2.40625 1.25,-3.765625 1.26563,-1.359375 3.1875,-1.359375 2.15625,0 3.40625,1.421875 1.25,1.421875 1.1875,4.375 h -6.40625 q 0.0312,1.140625 0.60938,1.78125 0.59375,0.625 1.48437,0.625 0.59375,0 1,-0.328125 0.42188,-0.328125 0.625,-1.0625 z m 0.15625,-2.59375 q -0.0312,-1.109375 -0.57812,-1.6875 -0.54688,-0.578125 -1.32813,-0.578125 -0.84375,0 -1.39062,0.609375 -0.54688,0.609375 -0.53125,1.65625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4498"
+               d="m 187.97444,76.841255 -4.78125,-13.359371 h 2.9375 l 3.375,9.890621 3.26562,-9.890621 h 2.85938 l -4.78125,13.359371 z m 8.9592,0 V 63.481884 h 2.6875 v 13.359371 z m 5.23018,0 V 63.481884 h 4.03125 l 2.42187,9.109371 2.39063,-9.109371 h 4.04687 v 13.359371 h -2.5 V 66.32563 l -2.65625,10.515625 h -2.59375 L 204.66382,66.32563 v 10.515625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4500"
+               d="m 165.13069,93.935005 2.60937,0.828125 q -0.59375,2.1875 -2,3.25 -1.39062,1.0625 -3.54687,1.0625 -2.65625,0 -4.375,-1.8125 -1.70313,-1.828125 -1.70313,-4.984375 0,-3.328125 1.71875,-5.171875 1.71875,-1.84375 4.51563,-1.84375 2.45312,0 3.98437,1.4375 0.92188,0.859375 1.375,2.46875 l -2.67187,0.640625 q -0.23438,-1.046875 -0.98438,-1.640625 -0.75,-0.609375 -1.82812,-0.609375 -1.48438,0 -2.42188,1.078125 -0.92187,1.0625 -0.92187,3.4375 0,2.53125 0.90625,3.609375 0.92187,1.078125 2.375,1.078125 1.07812,0 1.84375,-0.671875 0.78125,-0.6875 1.125,-2.15625 z m 4.3167,-0.0625 q 0,-1.28125 0.625,-2.46875 0.625,-1.203125 1.78125,-1.828125 1.15625,-0.625 2.57812,-0.625 2.1875,0 3.59375,1.421875 1.40625,1.421875 1.40625,3.609375 0,2.1875 -1.42187,3.640625 -1.42188,1.4375 -3.5625,1.4375 -1.32813,0 -2.54688,-0.59375 -1.20312,-0.609375 -1.82812,-1.765625 -0.625,-1.171875 -0.625,-2.828125 z m 2.625,0.125 q 0,1.453125 0.67187,2.21875 0.6875,0.75 1.6875,0.75 1,0 1.67188,-0.75 0.6875,-0.765625 0.6875,-2.234375 0,-1.421875 -0.6875,-2.1875 -0.67188,-0.765625 -1.67188,-0.765625 -1,0 -1.6875,0.765625 -0.67187,0.765625 -0.67187,2.203125 z m 18.1616,4.84375 h -2.5625 v -4.9375 q 0,-1.5625 -0.17187,-2.015625 -0.15625,-0.46875 -0.53125,-0.71875 -0.35938,-0.265625 -0.875,-0.265625 -0.67188,0 -1.20313,0.375 -0.53125,0.359375 -0.73437,0.96875 -0.1875,0.59375 -0.1875,2.21875 v 4.375 h -2.54688 V 89.16938 h 2.375 v 1.421875 q 1.26563,-1.640625 3.1875,-1.640625 0.84375,0 1.54688,0.3125 0.70312,0.296875 1.0625,0.78125 0.35937,0.46875 0.5,1.078125 0.14062,0.59375 0.14062,1.703125 z m 7.03661,-9.671875 v 2.03125 h -1.75 v 3.90625 q 0,1.1875 0.0469,1.390625 0.0469,0.1875 0.21875,0.3125 0.1875,0.125 0.4375,0.125 0.35938,0 1.03125,-0.25 l 0.21875,2 q -0.89062,0.375 -2.01562,0.375 -0.70313,0 -1.26563,-0.234375 -0.54687,-0.234375 -0.8125,-0.59375 -0.25,-0.375 -0.34375,-1 -0.0937,-0.453125 -0.0937,-1.8125 v -4.21875 h -1.17187 v -2.03125 h 1.17187 v -1.921875 l 2.57813,-1.5 v 3.421875 z m 4.2283,9.671875 h -2.5625 V 89.16938 h 2.375 v 1.375 q 0.60938,-0.984375 1.09375,-1.28125 0.48438,-0.3125 1.10938,-0.3125 0.875,0 1.6875,0.484375 l -0.79688,2.234375 q -0.64062,-0.421875 -1.20312,-0.421875 -0.53125,0 -0.90625,0.296875 -0.375,0.296875 -0.59375,1.078125 -0.20313,0.765625 -0.20313,3.234375 z m 4.21339,-4.96875 q 0,-1.28125 0.625,-2.46875 0.625,-1.203125 1.78125,-1.828125 1.15625,-0.625 2.57813,-0.625 2.1875,0 3.59375,1.421875 1.40625,1.421875 1.40625,3.609375 0,2.1875 -1.42188,3.640625 -1.42187,1.4375 -3.5625,1.4375 -1.32812,0 -2.54687,-0.59375 -1.20313,-0.609375 -1.82813,-1.765625 -0.625,-1.171875 -0.625,-2.828125 z m 2.625,0.125 q 0,1.453125 0.67188,2.21875 0.6875,0.75 1.6875,0.75 1,0 1.67187,-0.75 0.6875,-0.765625 0.6875,-2.234375 0,-1.421875 -0.6875,-2.1875 -0.67187,-0.765625 -1.67187,-0.765625 -1,0 -1.6875,0.765625 -0.67188,0.765625 -0.67188,2.203125 z m 9.36474,4.84375 V 85.48188 h 2.5625 v 13.359375 z m 5.1833,0 V 85.48188 h 2.5625 v 13.359375 z m 10.77705,-3.078125 2.54688,0.421875 q -0.48438,1.40625 -1.54688,2.140625 -1.0625,0.734375 -2.65625,0.734375 -2.51562,0 -3.73437,-1.65625 -0.95313,-1.3125 -0.95313,-3.328125 0,-2.40625 1.25,-3.765625 1.26563,-1.359375 3.1875,-1.359375 2.15625,0 3.40625,1.421875 1.25,1.421875 1.1875,4.375 h -6.40625 q 0.0312,1.140625 0.60938,1.78125 0.59375,0.625 1.48437,0.625 0.59375,0 1,-0.328125 0.42188,-0.328125 0.625,-1.0625 z m 0.15625,-2.59375 q -0.0312,-1.109375 -0.57812,-1.6875 -0.54688,-0.578125 -1.32813,-0.578125 -0.84375,0 -1.39062,0.609375 -0.54688,0.609375 -0.53125,1.65625 z m 7.07885,5.671875 h -2.5625 V 89.16938 h 2.375 v 1.375 q 0.60937,-0.984375 1.09375,-1.28125 0.48437,-0.3125 1.10937,-0.3125 0.875,0 1.6875,0.484375 l -0.79687,2.234375 q -0.64063,-0.421875 -1.20313,-0.421875 -0.53125,0 -0.90625,0.296875 -0.375,0.296875 -0.59375,1.078125 -0.20312,0.765625 -0.20312,3.234375 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4502"
+               d="m 189.47244,133.82152 9.48032,-9.48031 9.48031,9.48031 h -4.74016 v 117.25984 h 4.74016 l -9.48031,9.48032 -9.48032,-9.48032 h 4.74016 V 133.82152 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#b7b7b7;fill-rule:evenodd" />
+            <path
+               id="path4504"
+               d="m 189.47244,133.82152 9.48032,-9.48031 9.48031,9.48031 h -4.74016 v 117.25984 h 4.74016 l -9.48031,9.48032 -9.48032,-9.48032 h 4.74016 V 133.82152 Z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#b7b7b7;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4506"
+               d="m 137.68504,150.86876 h 131.37007 v 40.40945 H 137.68504 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4508"
+               d="m 147.9663,177.78876 v -13.35938 h 2.6875 v 13.35938 z m 5.26143,0 v -13.35938 h 4.32812 q 2.45313,0 3.20313,0.20313 1.14062,0.29687 1.92187,1.3125 0.78125,1 0.78125,2.59375 0,1.23437 -0.45312,2.07812 -0.45313,0.82813 -1.14063,1.3125 -0.6875,0.46875 -1.39062,0.625 -0.96875,0.20313 -2.79688,0.20313 h -1.76562 v 5.03125 z m 2.6875,-11.09375 v 3.78125 h 1.48437 q 1.59375,0 2.125,-0.20313 0.54688,-0.20312 0.84375,-0.65625 0.3125,-0.45312 0.3125,-1.03125 0,-0.73437 -0.4375,-1.20312 -0.42187,-0.48438 -1.07812,-0.59375 -0.48438,-0.0937 -1.9375,-0.0937 z m 14.63339,11.09375 v -13.35938 h 2.625 l 5.45313,8.92188 v -8.92188 h 2.51562 v 13.35938 h -2.70312 l -5.39063,-8.70313 v 8.70313 z m 19.01982,-3.07813 2.54688,0.42188 q -0.48438,1.40625 -1.54688,2.14062 -1.0625,0.73438 -2.65625,0.73438 -2.51562,0 -3.73437,-1.65625 -0.95313,-1.3125 -0.95313,-3.32813 0,-2.40625 1.25,-3.76562 1.26563,-1.35938 3.1875,-1.35938 2.15625,0 3.40625,1.42188 1.25,1.42187 1.1875,4.375 h -6.40625 q 0.0312,1.14062 0.60938,1.78125 0.59375,0.625 1.48437,0.625 0.59375,0 1,-0.32813 0.42188,-0.32812 0.625,-1.0625 z m 0.15625,-2.59375 q -0.0312,-1.10937 -0.57812,-1.6875 -0.54688,-0.57812 -1.32813,-0.57812 -0.84375,0 -1.39062,0.60937 -0.54688,0.60938 -0.53125,1.65625 z m 9.06322,-4 v 2.03125 h -1.75 v 3.90625 q 0,1.1875 0.0469,1.39063 0.0469,0.1875 0.21875,0.3125 0.1875,0.125 0.4375,0.125 0.35938,0 1.03125,-0.25 l 0.21875,2 q -0.89062,0.375 -2.01562,0.375 -0.70313,0 -1.26563,-0.23438 -0.54687,-0.23437 -0.8125,-0.59375 -0.25,-0.375 -0.34375,-1 -0.0937,-0.45312 -0.0937,-1.8125 v -4.21875 h -1.17187 v -2.03125 h 1.17187 v -1.92187 l 2.57813,-1.5 v 3.42187 z m 3.57205,9.67188 -3.0625,-9.67188 h 2.48438 l 1.8125,6.34375 1.67187,-6.34375 h 2.46875 l 1.60938,6.34375 1.85937,-6.34375 h 2.51563 l -3.10938,9.67188 h -2.45312 l -1.67188,-6.21875 -1.64062,6.21875 z m 12.1208,-4.96875 q 0,-1.28125 0.625,-2.46875 0.625,-1.20313 1.78125,-1.82813 1.15625,-0.625 2.57813,-0.625 2.1875,0 3.59375,1.42188 1.40625,1.42187 1.40625,3.60937 0,2.1875 -1.42188,3.64063 -1.42187,1.4375 -3.5625,1.4375 -1.32812,0 -2.54687,-0.59375 -1.20313,-0.60938 -1.82813,-1.76563 -0.625,-1.17187 -0.625,-2.82812 z m 2.625,0.125 q 0,1.45312 0.67188,2.21875 0.6875,0.75 1.6875,0.75 1,0 1.67187,-0.75 0.6875,-0.76563 0.6875,-2.23438 0,-1.42187 -0.6875,-2.1875 -0.67187,-0.76562 -1.67187,-0.76562 -1,0 -1.6875,0.76562 -0.67188,0.76563 -0.67188,2.20313 z m 11.81786,4.84375 h -2.5625 v -9.67188 h 2.375 v 1.375 q 0.60938,-0.98437 1.09375,-1.28125 0.48438,-0.3125 1.10938,-0.3125 0.875,0 1.6875,0.48438 l -0.79688,2.23437 q -0.64062,-0.42187 -1.20312,-0.42187 -0.53125,0 -0.90625,0.29687 -0.375,0.29688 -0.59375,1.07813 -0.20313,0.76562 -0.20313,3.23437 z m 4.71339,0 v -13.35938 h 2.5625 v 7.09375 l 3,-3.40625 h 3.14063 l -3.29688,3.53125 3.53125,6.14063 h -2.75 l -2.4375,-4.34375 -1.1875,1.25 v 3.09375 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:nonzero" />
+            <path
+               id="path4510"
+               d="m 229.9029,361.8189 c 0,25.47244 24.25984,38.20865 48.51968,50.94488 24.25983,12.73621 48.51969,25.47242 48.51969,50.94486"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4512"
+               d="m 229.9029,361.8189 c 0,25.47244 24.25984,38.20865 48.51968,50.94488 24.25983,12.73621 48.51969,25.47242 48.51969,50.94486"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4514"
+               d="m 313.46194,390.02625 h 42.96063 v 51.77951 h -42.96063 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4516"
+               d="m 338.64944,425.66812 v 4.07812 h -15.39062 q 0.25,-2.3125 1.5,-4.375 1.25,-2.07812 4.9375,-5.5 2.96875,-2.76562 3.64062,-3.75 0.90625,-1.35937 0.90625,-2.6875 0,-1.46875 -0.79687,-2.25 -0.78125,-0.79687 -2.17188,-0.79687 -1.375,0 -2.1875,0.82812 -0.8125,0.82813 -0.9375,2.75 l -4.375,-0.4375 q 0.39063,-3.625 2.45313,-5.20312 2.0625,-1.57813 5.15625,-1.57813 3.39062,0 5.32812,1.82813 1.9375,1.82812 1.9375,4.54687 0,1.54688 -0.5625,2.95313 -0.54687,1.39062 -1.75,2.92187 -0.79687,1.01563 -2.875,2.92188 -2.07812,1.90625 -2.64062,2.53125 -0.54688,0.625 -0.89063,1.21875 z"
+               inkscape:connector-curvature="0"
+               style="fill:#1155cc;fill-rule:nonzero" />
+            <path
+               id="path4518"
+               d="m 537.4619,422.02625 h 42.96063 v 51.77951 H 537.4619 Z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4520"
+               d="m 559.05566,461.74625 h -4.39063 v -16.54688 q -2.40625,2.25 -5.67187,3.32813 v -3.98438 q 1.71875,-0.5625 3.73437,-2.125 2.01563,-1.57812 2.76563,-3.67187 h 3.5625 z"
+               inkscape:connector-curvature="0"
+               style="fill:#1155cc;fill-rule:nonzero" />
+            <path
+               id="path4522"
+               d="m 442.3281,359.09448 c 0,72.83466 -15.48032,145.66931 -30.96063,145.66931"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4524"
+               d="m 442.3281,359.09448 c 0,72.83466 -15.48032,145.66931 -30.96063,145.66931"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#4a86e8;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 6" />
+            <path
+               id="path4526"
+               d="m 678.9475,87.519684 c 0,208.629906 -133.79529,417.259856 -267.59055,417.259856"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4528"
+               d="m 678.9475,87.519684 c 0,208.629906 -133.79529,417.259856 -267.59055,417.259856"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#4a86e8;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 6" />
+            <path
+               id="path4530"
+               d="m 779.57745,191.28084 c 0,156.7559 -184.09454,313.51184 -368.189,313.51184"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-opacity:0;fill-rule:evenodd" />
+            <path
+               id="path4532"
+               d="m 779.57745,191.28084 c 0,156.7559 -184.09454,313.51184 -368.189,313.51184"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#4a86e8;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 6" />
+            <path
+               id="path4534"
+               d="m 221.88715,372.1496 9.4803,-16.85037 9.48032,16.85037 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:evenodd" />
+            <path
+               id="path4536"
+               d="m 221.88715,372.1496 9.4803,-16.85037 9.48032,16.85037 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4538"
+               d="m 335.87573,450.3371 -7.59055,17.74802 -11.24411,-15.70078 z"
+               inkscape:connector-curvature="0"
+               style="fill:#000000;fill-rule:evenodd" />
+            <path
+               id="path4540"
+               d="m 335.87573,450.3371 -7.59055,17.74802 -11.24411,-15.70078 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4542"
+               d="m 432.83203,372.1496 9.48032,-16.85037 9.48031,16.85037 z"
+               inkscape:connector-curvature="0"
+               style="fill:#4a86e8;fill-rule:evenodd" />
+            <path
+               id="path4544"
+               d="m 432.83203,372.1496 9.48032,-16.85037 9.48031,16.85037 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#4a86e8;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4546"
+               d="m 669.46716,97.81628 9.48035,-16.850395 9.48028,16.850395 z"
+               inkscape:connector-curvature="0"
+               style="fill:#4a86e8;fill-rule:evenodd" />
+            <path
+               id="path4548"
+               d="m 669.46716,97.81628 9.48035,-16.850395 9.48028,16.850395 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#4a86e8;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4550"
+               d="m 768.83203,204.14961 9.48029,-16.8504 9.48034,16.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill:#4a86e8;fill-rule:evenodd" />
+            <path
+               id="path4552"
+               d="m 768.83203,204.14961 9.48029,-16.8504 9.48034,16.8504 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#4a86e8;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+            <path
+               id="path4554"
+               d="m 421.14697,514.3213 -18.88187,-4.11023 13.30707,-14 z"
+               inkscape:connector-curvature="0"
+               style="fill:#4a86e8;fill-rule:evenodd" />
+            <path
+               id="path4556"
+               d="m 421.14697,514.3213 -18.88187,-4.11023 13.30707,-14 z"
+               inkscape:connector-curvature="0"
+               style="fill-rule:evenodd;stroke:#4a86e8;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round" />
+          </g>
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>
-- 
2.26.0


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [RFC] ring: make ring implementation non-inlined
  2020-03-26  8:04  4%   ` Morten Brørup
@ 2020-03-31 23:25  5%     ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-03-31 23:25 UTC (permalink / raw)
  To: Jerin Jacob, Konstantin Ananyev, Jerin Jacob, Morten Brørup
  Cc: dev, Olivier Matz, Honnappa Nagarahalli, David Christensen,
	Stephen Hemminger

26/03/2020 09:04, Morten Brørup:
> From: Jerin Jacob
> > On Fri, Mar 20, 2020 Konstantin Ananyev wrote:
> > >
> > > As was discussed here:
> > > http://mails.dpdk.org/archives/dev/2020-February/158586.html
> > > this RFC aimed to hide ring internals into .c and make all
> > > ring functions non-inlined. In theory that might help to
> > > maintain ABI stability in future.
> > > This is just a POC to measure the impact of proposed idea,
> > > proper implementation would definetly need some extra effort.
> > > On IA box (SKX) ring_perf_autotest shows ~20-30 cycles extra for
> > > enqueue+dequeue pair. On some more realistic code, I suspect
> > > the impact it might be a bit higher.
> > > For MP/MC bulk transfers degradation seems quite small,
> > > though for SP/SC and/or small transfers it is more then noticable
> > > (see exact numbers below).
> > > From my perspective we'd probably keep it inlined for now
> > > to avoid any non-anticipated perfomance degradations.
> > > Though intersted to see perf results and opinions from
> > > other interested parties.
> > 
> > +1

Konstantin, thank you for doing some measures


> > My reasoning is a bit different, DPDK is using in embedded boxes too
> > where performance has more weight than ABI stuff.
> 
> As a network appliance vendor I can confirm that we certainly care
> more about performance than ABI stability.
> ABI stability is irrelevant for us;
> and API instability is a non-recurring engineering cost each time
> we choose to switch to a new DPDK version, which we only do if we
> cannot avoid it, e.g. due to new drivers, security fixes or
> new features that we want to use.
> 
> For us, the trend pointed in the wrong direction when DPDK switched
> the preference towards runtime configurability and deprecated compile
> time configurability. I do understand the reasoning behind it,
> and the impact is minimal, so we accept it.

The code can be optimized by removing some instructions with #ifdef.
But the complexity of managing #ifdef enabling/disabling,
depending on the platform and the use case, would be huge.
We try to have a reasonable code "always enabled" which performs well
in all cases. This is a design choice which makes DPDK a library,
not a pool of code to cherry-pick.

> However, if DPDK starts sacrificing performance of the core
> libraries for the benefits of the GNU/Linux distributors,
> network appliance vendors may put more effort into sticking
> with old DPDK versions instead of updating.

The initial choice regarding ABI compatibility was "do not care".
Recently, the decision was done to care about ABI compatibility
as priority number 2. The priority number 1 remains the performance.
That's a reason for allowing some ABI breakages in some specific
releases announced in advance.

> > I think we need to focus first on slow
> > path APIs ABI stuff.

Yes we should not degrade fast path performance for the sake
of avoiding uncertain future ABI issues.

Morten, Jerin, thank you for the feedback.



^ permalink raw reply	[relevance 5%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-03-31 19:22  8% ` Thomas Monjalon
@ 2020-03-31 19:24  4%   ` Thomas Monjalon
  2020-04-01 12:52  4%     ` Neil Horman
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-03-31 19:24 UTC (permalink / raw)
  To: nhorman, mdr
  Cc: Ananyev, Konstantin, david.marchand, honnappa.nagarahalli, dev,
	Richardson, Bruce, Yigit, Ferruh, kevin.laatz

31/03/2020 21:22, Thomas Monjalon:
> 31/03/2020 19:05, Ananyev, Konstantin:
> > Hi everyone,
> > 
> > Have a question regarding validate-abi.sh.
> 
> devtools/validate-abi.sh should be removed.
> Please use the new devtools/check-abi.sh

The file doc/guides/contributing/abi_versioning.rst
should be updated as well.
Neil? Ray?



^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
  2020-03-31 17:05  7% [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode Ananyev, Konstantin
@ 2020-03-31 19:22  8% ` Thomas Monjalon
  2020-03-31 19:24  4%   ` Thomas Monjalon
  2020-04-01  6:38  9% ` David Marchand
  1 sibling, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-03-31 19:22 UTC (permalink / raw)
  To: Ananyev, Konstantin
  Cc: david.marchand, nhorman, honnappa.nagarahalli, dev, Richardson,
	Bruce, Yigit, Ferruh, kevin.laatz

31/03/2020 19:05, Ananyev, Konstantin:
> Hi everyone,
> 
> Have a question regarding validate-abi.sh.

devtools/validate-abi.sh should be removed.
Please use the new devtools/check-abi.sh



^ permalink raw reply	[relevance 8%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-03-30 23:37  0%       ` Honnappa Nagarahalli
@ 2020-03-31 17:21  0%         ` Ananyev, Konstantin
  0 siblings, 0 replies; 200+ results
From: Ananyev, Konstantin @ 2020-03-31 17:21 UTC (permalink / raw)
  To: Honnappa Nagarahalli, dev; +Cc: olivier.matz, nd, nd

> <snip>
> >
> > > >
> > > > > Subject: [dpdk-dev] [RFC 0/6] New sync modes for ring
> > > > >
> > > > > Upfront note - that RFC is not a complete patch.
> > > > > It introduces an ABI breakage, plus it doesn't update ring_elem
> > > > > code properly,
> > > > As per the current rules, these changes (in the current form) will
> > > > be accepted only for 20.11 release. How do we address this for
> > > > immediate
> > > requirements like RCU defer APIs?
> > >
> > > I think I found a way to introduce these new modes without API/ABI
> > breakage.
> > > Working on v1 right now. Plan to submit it by end of that week/start
> > > of next one.
> > ok
> RCU defer APIs require the rte_ring_xxx_elem versions. I guess you are adding those as well.

Yes, I added it into V1, please have a look.
Also I made 'legacy' peek API (enqueue/dequeue_start/finish) to call
'elem' peek API (enqueue/dequeue_elem_start/finish).
About naming: thought about changing start/finish to reserve/commit,
but decided to left as it is for now - in case you would like to go ahead
with SG API and use reserve/commit there.
Konstantin



^ permalink raw reply	[relevance 0%]

* [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode
@ 2020-03-31 17:05  7% Ananyev, Konstantin
  2020-03-31 19:22  8% ` Thomas Monjalon
  2020-04-01  6:38  9% ` David Marchand
  0 siblings, 2 replies; 200+ results
From: Ananyev, Konstantin @ 2020-03-31 17:05 UTC (permalink / raw)
  To: david.marchand, thomas, nhorman
  Cc: honnappa.nagarahalli, dev, Richardson, Bruce, Yigit, Ferruh

Hi everyone,

Have a question regarding validate-abi.sh.
It complains on the following changes with that patch:

@@ -111,11 +129,21 @@ struct rte_ring {
        char pad0 __rte_cache_aligned; /**< empty cache line */

        /** Ring producer status. */
-       struct rte_ring_headtail prod __rte_cache_aligned;
+       RTE_STD_C11
+       union {
+               struct rte_ring_headtail prod;
+               struct rte_ring_rts_headtail rts_prod;
+       }  __rte_cache_aligned;
+
        char pad1 __rte_cache_aligned; /**< empty cache line */

        /** Ring consumer status. */
-       struct rte_ring_headtail cons __rte_cache_aligned;
+       RTE_STD_C11
+       union {
+               struct rte_ring_headtail cons;
+               struct rte_ring_rts_headtail rts_cons;
+       }  __rte_cache_aligned;
+

Complaints:
rte_ring.h
[−] struct rte_ring  2  

1
Change: Field cons has been removed from this type.
Effect:    Applications will access incorrect memory when attempting to access this field.
2
Change: Field prod has been removed from this type.
Effect:    Applications will access incorrect memory when attempting to access this field.

From my perspective it looks false-positive:
*prod* and *cons* fields are still there,
their format, size and offset within rte_ring remain the same. 
Is that some limitation with the tool, or am I missing something here?
Thanks
Konstantin 

> -----Original Message-----
> From: Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Sent: Tuesday, March 31, 2020 5:43 PM
> To: dev@dpdk.org
> Cc: honnappa.nagarahalli@arm.com; Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Subject: [PATCH v1 3/8] ring: introduce RTS ring mode
> 
> Introduce relaxed tail sync (RTS) mode for MT ring synchronization.
> Aim to reduce stall times in case when ring is used on
> overcommited cpus (multiple active threads on the same cpu).
> The main difference from original MP/MC algorithm is that
> tail value is increased not by every thread that finished enqueue/dequeue,
> but only by the last one.
> That allows threads to avoid spinning on ring tail value,
> leaving actual tail value change to the last thread in the update queue.
> 
> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> ---
>  lib/librte_ring/Makefile               |   5 +-
>  lib/librte_ring/meson.build            |   5 +-
>  lib/librte_ring/rte_ring.c             | 100 +++++++-
>  lib/librte_ring/rte_ring.h             | 109 ++++++++-
>  lib/librte_ring/rte_ring_elem.h        |  86 ++++++-
>  lib/librte_ring/rte_ring_rts.h         | 316 +++++++++++++++++++++++++
>  lib/librte_ring/rte_ring_rts_elem.h    | 205 ++++++++++++++++
>  lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++++++
>  8 files changed, 1007 insertions(+), 29 deletions(-)
>  create mode 100644 lib/librte_ring/rte_ring_rts.h
>  create mode 100644 lib/librte_ring/rte_ring_rts_elem.h
>  create mode 100644 lib/librte_ring/rte_ring_rts_generic.h
> 
> diff --git a/lib/librte_ring/Makefile b/lib/librte_ring/Makefile
> index 917c560ad..8f5c284cc 100644
> --- a/lib/librte_ring/Makefile
> +++ b/lib/librte_ring/Makefile
> @@ -18,6 +18,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_RING) := rte_ring.c
>  SYMLINK-$(CONFIG_RTE_LIBRTE_RING)-include := rte_ring.h \
>  					rte_ring_elem.h \
>  					rte_ring_generic.h \
> -					rte_ring_c11_mem.h
> +					rte_ring_c11_mem.h \
> +					rte_ring_rts.h \
> +					rte_ring_rts_elem.h \
> +					rte_ring_rts_generic.h
> 
>  include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_ring/meson.build b/lib/librte_ring/meson.build
> index f2f3ccc88..612936afb 100644
> --- a/lib/librte_ring/meson.build
> +++ b/lib/librte_ring/meson.build
> @@ -5,7 +5,10 @@ sources = files('rte_ring.c')
>  headers = files('rte_ring.h',
>  		'rte_ring_elem.h',
>  		'rte_ring_c11_mem.h',
> -		'rte_ring_generic.h')
> +		'rte_ring_generic.h',
> +		'rte_ring_rts.h',
> +		'rte_ring_rts_elem.h',
> +		'rte_ring_rts_generic.h')
> 
>  # rte_ring_create_elem and rte_ring_get_memsize_elem are experimental
>  allow_experimental_apis = true
> diff --git a/lib/librte_ring/rte_ring.c b/lib/librte_ring/rte_ring.c
> index fa5733907..222eec0fb 100644
> --- a/lib/librte_ring/rte_ring.c
> +++ b/lib/librte_ring/rte_ring.c
> @@ -45,6 +45,9 @@ EAL_REGISTER_TAILQ(rte_ring_tailq)
>  /* true if x is a power of 2 */
>  #define POWEROF2(x) ((((x)-1) & (x)) == 0)
> 
> +/* by default set head/tail distance as 1/8 of ring capacity */
> +#define HTD_MAX_DEF	8
> +
>  /* return the size of memory occupied by a ring */
>  ssize_t
>  rte_ring_get_memsize_elem(unsigned int esize, unsigned int count)
> @@ -79,11 +82,84 @@ rte_ring_get_memsize(unsigned int count)
>  	return rte_ring_get_memsize_elem(sizeof(void *), count);
>  }
> 
> +/*
> + * internal helper function to reset prod/cons head-tail values.
> + */
> +static void
> +reset_headtail(void *p)
> +{
> +	struct rte_ring_headtail *ht;
> +	struct rte_ring_rts_headtail *ht_rts;
> +
> +	ht = p;
> +	ht_rts = p;
> +
> +	switch (ht->sync_type) {
> +	case RTE_RING_SYNC_MT:
> +	case RTE_RING_SYNC_ST:
> +		ht->head = 0;
> +		ht->tail = 0;
> +		break;
> +	case RTE_RING_SYNC_MT_RTS:
> +		ht_rts->head.raw = 0;
> +		ht_rts->tail.raw = 0;
> +		break;
> +	default:
> +		/* unknown sync mode */
> +		RTE_ASSERT(0);
> +	}
> +}
> +
>  void
>  rte_ring_reset(struct rte_ring *r)
>  {
> -	r->prod.head = r->cons.head = 0;
> -	r->prod.tail = r->cons.tail = 0;
> +	reset_headtail(&r->prod);
> +	reset_headtail(&r->cons);
> +}
> +
> +/*
> + * helper function, calculates sync_type values for prod and cons
> + * based on input flags. Returns zero at success or negative
> + * errno value otherwise.
> + */
> +static int
> +get_sync_type(uint32_t flags, enum rte_ring_sync_type *prod_st,
> +	enum rte_ring_sync_type *cons_st)
> +{
> +	static const uint32_t prod_st_flags =
> +		(RING_F_SP_ENQ | RING_F_MP_RTS_ENQ);
> +	static const uint32_t cons_st_flags =
> +		(RING_F_SC_DEQ | RING_F_MC_RTS_DEQ);
> +
> +	switch (flags & prod_st_flags) {
> +	case 0:
> +		*prod_st = RTE_RING_SYNC_MT;
> +		break;
> +	case RING_F_SP_ENQ:
> +		*prod_st = RTE_RING_SYNC_ST;
> +		break;
> +	case RING_F_MP_RTS_ENQ:
> +		*prod_st = RTE_RING_SYNC_MT_RTS;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	switch (flags & cons_st_flags) {
> +	case 0:
> +		*cons_st = RTE_RING_SYNC_MT;
> +		break;
> +	case RING_F_SC_DEQ:
> +		*cons_st = RTE_RING_SYNC_ST;
> +		break;
> +	case RING_F_MC_RTS_DEQ:
> +		*cons_st = RTE_RING_SYNC_MT_RTS;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
>  }
> 
>  int
> @@ -100,16 +176,20 @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
>  	RTE_BUILD_BUG_ON((offsetof(struct rte_ring, prod) &
>  			  RTE_CACHE_LINE_MASK) != 0);
> 
> +	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, sync_type) !=
> +		offsetof(struct rte_ring_rts_headtail, sync_type));
> +	RTE_BUILD_BUG_ON(offsetof(struct rte_ring_headtail, tail) !=
> +		offsetof(struct rte_ring_rts_headtail, tail.val.pos));
> +
>  	/* init the ring structure */
>  	memset(r, 0, sizeof(*r));
>  	ret = strlcpy(r->name, name, sizeof(r->name));
>  	if (ret < 0 || ret >= (int)sizeof(r->name))
>  		return -ENAMETOOLONG;
>  	r->flags = flags;
> -	r->prod.sync_type = (flags & RING_F_SP_ENQ) ?
> -		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
> -	r->cons.sync_type = (flags & RING_F_SC_DEQ) ?
> -		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
> +	ret = get_sync_type(flags, &r->prod.sync_type, &r->cons.sync_type);
> +	if (ret != 0)
> +		return ret;
> 
>  	if (flags & RING_F_EXACT_SZ) {
>  		r->size = rte_align32pow2(count + 1);
> @@ -126,8 +206,12 @@ rte_ring_init(struct rte_ring *r, const char *name, unsigned count,
>  		r->mask = count - 1;
>  		r->capacity = r->mask;
>  	}
> -	r->prod.head = r->cons.head = 0;
> -	r->prod.tail = r->cons.tail = 0;
> +
> +	/* set default values for head-tail distance */
> +	if (flags & RING_F_MP_RTS_ENQ)
> +		rte_ring_set_prod_htd_max(r, r->capacity / HTD_MAX_DEF);
> +	if (flags & RING_F_MC_RTS_DEQ)
> +		rte_ring_set_cons_htd_max(r, r->capacity / HTD_MAX_DEF);
> 
>  	return 0;
>  }
> diff --git a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h
> index d4775a063..2b42a0211 100644
> --- a/lib/librte_ring/rte_ring.h
> +++ b/lib/librte_ring/rte_ring.h
> @@ -65,10 +65,13 @@ enum rte_ring_queue_behavior {
>  enum rte_ring_sync_type {
>  	RTE_RING_SYNC_MT,     /**< multi-thread safe (default mode) */
>  	RTE_RING_SYNC_ST,     /**< single thread only */
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	RTE_RING_SYNC_MT_RTS, /**< multi-thread relaxed tail sync */
> +#endif
>  };
> 
>  /**
> - * structure to hold a pair of head/tail values and other metadata.
> + * structures to hold a pair of head/tail values and other metadata.
>   * Depending on sync_type format of that structure might be different,
>   * but offset for *sync_type* and *tail* values should remain the same.
>   */
> @@ -84,6 +87,21 @@ struct rte_ring_headtail {
>  	};
>  };
> 
> +union rte_ring_ht_poscnt {
> +	uint64_t raw;
> +	struct {
> +		uint32_t cnt; /**< head/tail reference counter */
> +		uint32_t pos; /**< head/tail position */
> +	} val;
> +};
> +
> +struct rte_ring_rts_headtail {
> +	volatile union rte_ring_ht_poscnt tail;
> +	enum rte_ring_sync_type sync_type;  /**< sync type of prod/cons */
> +	uint32_t htd_max;   /**< max allowed distance between head/tail */
> +	volatile union rte_ring_ht_poscnt head;
> +};
> +
>  /**
>   * An RTE ring structure.
>   *
> @@ -111,11 +129,21 @@ struct rte_ring {
>  	char pad0 __rte_cache_aligned; /**< empty cache line */
> 
>  	/** Ring producer status. */
> -	struct rte_ring_headtail prod __rte_cache_aligned;
> +	RTE_STD_C11
> +	union {
> +		struct rte_ring_headtail prod;
> +		struct rte_ring_rts_headtail rts_prod;
> +	}  __rte_cache_aligned;
> +
>  	char pad1 __rte_cache_aligned; /**< empty cache line */
> 
>  	/** Ring consumer status. */
> -	struct rte_ring_headtail cons __rte_cache_aligned;
> +	RTE_STD_C11
> +	union {
> +		struct rte_ring_headtail cons;
> +		struct rte_ring_rts_headtail rts_cons;
> +	}  __rte_cache_aligned;
> +
>  	char pad2 __rte_cache_aligned; /**< empty cache line */
>  };
> 
> @@ -132,6 +160,9 @@ struct rte_ring {
>  #define RING_F_EXACT_SZ 0x0004
>  #define RTE_RING_SZ_MASK  (0x7fffffffU) /**< Ring size mask */
> 
> +#define RING_F_MP_RTS_ENQ 0x0008 /**< The default enqueue is "MP RTS". */
> +#define RING_F_MC_RTS_DEQ 0x0010 /**< The default dequeue is "MC RTS". */
> +
>  #define __IS_SP RTE_RING_SYNC_ST
>  #define __IS_MP RTE_RING_SYNC_MT
>  #define __IS_SC RTE_RING_SYNC_ST
> @@ -461,6 +492,10 @@ rte_ring_sp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
>  			RTE_RING_SYNC_ST, free_space);
>  }
> 
> +#ifdef ALLOW_EXPERIMENTAL_API
> +#include <rte_ring_rts.h>
> +#endif
> +
>  /**
>   * Enqueue several objects on a ring.
>   *
> @@ -484,8 +519,21 @@ static __rte_always_inline unsigned int
>  rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
>  		      unsigned int n, unsigned int *free_space)
>  {
> -	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
> -			r->prod.sync_type, free_space);
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_bulk(r, obj_table, n, free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_bulk(r, obj_table, n, free_space);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_bulk(r, obj_table, n,
> +			free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  /**
> @@ -619,8 +667,20 @@ static __rte_always_inline unsigned int
>  rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,
>  		unsigned int *available)
>  {
> -	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
> -				r->cons.sync_type, available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_bulk(r, obj_table, n, available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_bulk(r, obj_table, n, available);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_bulk(r, obj_table, n, available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  /**
> @@ -940,8 +1000,21 @@ static __rte_always_inline unsigned
>  rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table,
>  		      unsigned int n, unsigned int *free_space)
>  {
> -	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_VARIABLE,
> -			r->prod.sync_type, free_space);
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_burst(r, obj_table, n, free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_burst(r, obj_table, n, free_space);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_burst(r, obj_table, n,
> +			free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  /**
> @@ -1020,9 +1093,21 @@ static __rte_always_inline unsigned
>  rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table,
>  		unsigned int n, unsigned int *available)
>  {
> -	return __rte_ring_do_dequeue(r, obj_table, n,
> -				RTE_RING_QUEUE_VARIABLE,
> -				r->cons.sync_type, available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_burst(r, obj_table, n, available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_burst(r, obj_table, n, available);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_burst(r, obj_table, n,
> +			available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	return 0;
>  }
> 
>  #ifdef __cplusplus
> diff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h
> index 28f9836e6..5de0850dc 100644
> --- a/lib/librte_ring/rte_ring_elem.h
> +++ b/lib/librte_ring/rte_ring_elem.h
> @@ -542,6 +542,8 @@ rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
>  			RTE_RING_QUEUE_FIXED, __IS_SP, free_space);
>  }
> 
> +#include <rte_ring_rts_elem.h>
> +
>  /**
>   * Enqueue several objects on a ring.
>   *
> @@ -571,6 +573,26 @@ rte_ring_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
>  {
>  	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
>  			RTE_RING_QUEUE_FIXED, r->prod.sync_type, free_space);
> +
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_bulk_elem(r, obj_table, esize, n,
> +			free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_bulk_elem(r, obj_table, esize, n,
> +			free_space);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_bulk_elem(r, obj_table, esize, n,
> +			free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (free_space != NULL)
> +		*free_space = 0;
> +	return 0;
>  }
> 
>  /**
> @@ -733,8 +755,25 @@ static __rte_always_inline unsigned int
>  rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *available)
>  {
> -	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
> -			RTE_RING_QUEUE_FIXED, r->cons.sync_type, available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_bulk_elem(r, obj_table, esize, n,
> +			available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_bulk_elem(r, obj_table, esize, n,
> +			available);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_bulk_elem(r, obj_table, esize,
> +			n, available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (available != NULL)
> +		*available = 0;
> +	return 0;
>  }
> 
>  /**
> @@ -901,8 +940,25 @@ static __rte_always_inline unsigned
>  rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *free_space)
>  {
> -	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
> -			RTE_RING_QUEUE_VARIABLE, r->prod.sync_type, free_space);
> +	switch (r->prod.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mp_enqueue_burst_elem(r, obj_table, esize, n,
> +			free_space);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sp_enqueue_burst_elem(r, obj_table, esize, n,
> +			free_space);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mp_rts_enqueue_burst_elem(r, obj_table, esize,
> +			n, free_space);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (free_space != NULL)
> +		*free_space = 0;
> +	return 0;
>  }
> 
>  /**
> @@ -993,9 +1049,25 @@ static __rte_always_inline unsigned int
>  rte_ring_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
>  		unsigned int esize, unsigned int n, unsigned int *available)
>  {
> -	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
> -				RTE_RING_QUEUE_VARIABLE,
> -				r->cons.sync_type, available);
> +	switch (r->cons.sync_type) {
> +	case RTE_RING_SYNC_MT:
> +		return rte_ring_mc_dequeue_burst_elem(r, obj_table, esize, n,
> +			available);
> +	case RTE_RING_SYNC_ST:
> +		return rte_ring_sc_dequeue_burst_elem(r, obj_table, esize, n,
> +			available);
> +#ifdef ALLOW_EXPERIMENTAL_API
> +	case RTE_RING_SYNC_MT_RTS:
> +		return rte_ring_mc_rts_dequeue_burst_elem(r, obj_table, esize,
> +			n, available);
> +#endif
> +	}
> +
> +	/* valid ring should never reach this point */
> +	RTE_ASSERT(0);
> +	if (available != NULL)
> +		*available = 0;
> +	return 0;
>  }
> 
>  #ifdef __cplusplus
> diff --git a/lib/librte_ring/rte_ring_rts.h b/lib/librte_ring/rte_ring_rts.h
> new file mode 100644
> index 000000000..18404fe48
> --- /dev/null
> +++ b/lib/librte_ring/rte_ring_rts.h
> @@ -0,0 +1,316 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * Copyright (c) 2010-2017 Intel Corporation
> + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
> + * All rights reserved.
> + * Derived from FreeBSD's bufring.h
> + * Used as BSD-3 Licensed with permission from Kip Macy.
> + */
> +
> +#ifndef _RTE_RING_RTS_H_
> +#define _RTE_RING_RTS_H_
> +
> +/**
> + * @file rte_ring_rts.h
> + * @b EXPERIMENTAL: this API may change without prior notice
> + * It is not recommended to include this file directly.
> + * Please include <rte_ring.h> instead.
> + *
> + * Contains functions for Relaxed Tail Sync (RTS) ring mode.
> + * The main idea remains the same as for our original MP/MC synchronization
> + * mechanism.
> + * The main difference is that tail value is increased not
> + * by every thread that finished enqueue/dequeue,
> + * but only by the last one doing enqueue/dequeue.
> + * That allows threads to skip spinning on tail value,
> + * leaving actual tail value change to last thread in the update queue.
> + * RTS requires 2 64-bit CAS for each enqueue(/dequeue) operation:
> + * one for head update, second for tail update.
> + * As a gain it allows thread to avoid spinning/waiting on tail value.
> + * In comparision original MP/MC algorithm requires one 32-bit CAS
> + * for head update and waiting/spinning on tail value.
> + *
> + * Brief outline:
> + *  - introduce refcnt for both head and tail.
> + *  - increment head.refcnt for each head.value update
> + *  - write head:value and head:refcnt atomically (64-bit CAS)
> + *  - move tail.value ahead only when tail.refcnt + 1 == head.refcnt
> + *  - increment tail.refcnt when each enqueue/dequeue op finishes
> + *    (no matter is tail:value going to change or not)
> + *  - write tail.value and tail.recnt atomically (64-bit CAS)
> + *
> + * To avoid producer/consumer starvation:
> + *  - limit max allowed distance between head and tail value (HTD_MAX).
> + *    I.E. thread is allowed to proceed with changing head.value,
> + *    only when:  head.value - tail.value <= HTD_MAX
> + * HTD_MAX is an optional parameter.
> + * With HTD_MAX == 0 we'll have fully serialized ring -
> + * i.e. only one thread at a time will be able to enqueue/dequeue
> + * to/from the ring.
> + * With HTD_MAX >= ring.capacity - no limitation.
> + * By default HTD_MAX == ring.capacity / 8.
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <rte_ring_rts_generic.h>
> +
> +/**
> + * @internal Enqueue several objects on the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
> + * @param free_space
> + *   returns the amount of space after the enqueue operation has finished
> + * @return
> + *   Actual number of objects enqueued.
> + *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_enqueue(struct rte_ring *r, void * const *obj_table,
> +		uint32_t n, enum rte_ring_queue_behavior behavior,
> +		uint32_t *free_space)
> +{
> +	uint32_t free, head;
> +
> +	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
> +
> +	if (n != 0) {
> +		ENQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
> +		__rte_ring_rts_update_tail(&r->rts_prod);
> +	}
> +
> +	if (free_space != NULL)
> +		*free_space = free - n;
> +	return n;
> +}
> +
> +/**
> + * @internal Dequeue several objects from the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to pull from the ring.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
> + * @param available
> + *   returns the number of remaining ring entries after the dequeue has finished
> + * @return
> + *   - Actual number of objects dequeued.
> + *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_dequeue(struct rte_ring *r, void **obj_table,
> +		uint32_t n, enum rte_ring_queue_behavior behavior,
> +		uint32_t *available)
> +{
> +	uint32_t entries, head;
> +
> +	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
> +
> +	if (n != 0) {
> +		DEQUEUE_PTRS(r, &r[1], head, obj_table, n, void *);
> +		__rte_ring_rts_update_tail(&r->rts_cons);
> +	}
> +
> +	if (available != NULL)
> +		*available = entries - n;
> +	return n;
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   The number of objects enqueued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mp_rts_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
> +			 unsigned int n, unsigned int *free_space)
> +{
> +	return __rte_ring_do_rts_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
> +			free_space);
> +}
> +
> +/**
> + * Dequeue several objects from an RTS ring (multi-consumers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   The number of objects dequeued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mc_rts_dequeue_bulk(struct rte_ring *r, void **obj_table,
> +		unsigned int n, unsigned int *available)
> +{
> +	return __rte_ring_do_rts_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
> +			available);
> +}
> +
> +/**
> + * Return producer max Head-Tail-Distance (HTD).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   Producer HTD value, if producer is set in appropriate sync mode,
> + *   or UINT32_MAX otherwise.
> + */
> +__rte_experimental
> +static inline uint32_t
> +rte_ring_get_prod_htd_max(const struct rte_ring *r)
> +{
> +	if (r->prod.sync_type == RTE_RING_SYNC_MT_RTS)
> +		return r->rts_prod.htd_max;
> +	return UINT32_MAX;
> +}
> +
> +/**
> + * Set producer max Head-Tail-Distance (HTD).
> + * Note that producer has to use appropriate sync mode (RTS).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param v
> + *   new HTD value to setup.
> + * @return
> + *   Zero on success, or negative error code otherwise.
> + */
> +__rte_experimental
> +static inline int
> +rte_ring_set_prod_htd_max(struct rte_ring *r, uint32_t v)
> +{
> +	if (r->prod.sync_type != RTE_RING_SYNC_MT_RTS)
> +		return -ENOTSUP;
> +
> +	r->rts_prod.htd_max = v;
> +	return 0;
> +}
> +
> +/**
> + * Return consumer max Head-Tail-Distance (HTD).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @return
> + *   Consumer HTD value, if consumer is set in appropriate sync mode,
> + *   or UINT32_MAX otherwise.
> + */
> +__rte_experimental
> +static inline uint32_t
> +rte_ring_get_cons_htd_max(const struct rte_ring *r)
> +{
> +	if (r->cons.sync_type == RTE_RING_SYNC_MT_RTS)
> +		return r->rts_cons.htd_max;
> +	return UINT32_MAX;
> +}
> +
> +/**
> + * Set consumer max Head-Tail-Distance (HTD).
> + * Note that consumer has to use appropriate sync mode (RTS).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param v
> + *   new HTD value to setup.
> + * @return
> + *   Zero on success, or negative error code otherwise.
> + */
> +__rte_experimental
> +static inline int
> +rte_ring_set_cons_htd_max(struct rte_ring *r, uint32_t v)
> +{
> +	if (r->cons.sync_type != RTE_RING_SYNC_MT_RTS)
> +		return -ENOTSUP;
> +
> +	r->rts_cons.htd_max = v;
> +	return 0;
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   - n: Actual number of objects enqueued.
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mp_rts_enqueue_burst(struct rte_ring *r, void * const *obj_table,
> +			 unsigned int n, unsigned int *free_space)
> +{
> +	return __rte_ring_do_rts_enqueue(r, obj_table, n,
> +			RTE_RING_QUEUE_VARIABLE, free_space);
> +}
> +
> +/**
> + * Dequeue several objects from an RTS  ring (multi-consumers safe).
> + * When the requested objects are more than the available objects,
> + * only dequeue the actual number of objects.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   - n: Actual number of objects dequeued, 0 if ring is empty
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mc_rts_dequeue_burst(struct rte_ring *r, void **obj_table,
> +		unsigned int n, unsigned int *available)
> +{
> +	return __rte_ring_do_rts_dequeue(r, obj_table, n,
> +			RTE_RING_QUEUE_VARIABLE, available);
> +}
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_RING_RTS_H_ */
> diff --git a/lib/librte_ring/rte_ring_rts_elem.h b/lib/librte_ring/rte_ring_rts_elem.h
> new file mode 100644
> index 000000000..71a331b23
> --- /dev/null
> +++ b/lib/librte_ring/rte_ring_rts_elem.h
> @@ -0,0 +1,205 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * Copyright (c) 2010-2017 Intel Corporation
> + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
> + * All rights reserved.
> + * Derived from FreeBSD's bufring.h
> + * Used as BSD-3 Licensed with permission from Kip Macy.
> + */
> +
> +#ifndef _RTE_RING_RTS_ELEM_H_
> +#define _RTE_RING_RTS_ELEM_H_
> +
> +/**
> + * @file rte_ring_rts_elem.h
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * It is not recommended to include this file directly.
> + * Please include <rte_ring_elem.h> instead.
> + * Contains *ring_elem* functions for Relaxed Tail Sync (RTS) ring mode.
> + * for more details please refer to <rte_ring_rts.h>.
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <rte_ring_rts_generic.h>
> +
> +/**
> + * @internal Enqueue several objects on the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
> + * @param free_space
> + *   returns the amount of space after the enqueue operation has finished
> + * @return
> + *   Actual number of objects enqueued.
> + *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_enqueue_elem(struct rte_ring *r, void * const *obj_table,
> +	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
> +	uint32_t *free_space)
> +{
> +	uint32_t free, head;
> +
> +	n =  __rte_ring_rts_move_prod_head(r, n, behavior, &head, &free);
> +
> +	if (n != 0) {
> +		__rte_ring_enqueue_elems(r, head, obj_table, esize, n);
> +		__rte_ring_rts_update_tail(&r->rts_prod);
> +	}
> +
> +	if (free_space != NULL)
> +		*free_space = free - n;
> +	return n;
> +}
> +
> +/**
> + * @internal Dequeue several objects from the RTS ring.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to pull from the ring.
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
> + * @param available
> + *   returns the number of remaining ring entries after the dequeue has finished
> + * @return
> + *   - Actual number of objects dequeued.
> + *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_do_rts_dequeue_elem(struct rte_ring *r, void **obj_table,
> +	uint32_t esize, uint32_t n, enum rte_ring_queue_behavior behavior,
> +	uint32_t *available)
> +{
> +	uint32_t entries, head;
> +
> +	n = __rte_ring_rts_move_cons_head(r, n, behavior, &head, &entries);
> +
> +	if (n != 0) {
> +		__rte_ring_dequeue_elems(r, head, obj_table, esize, n);
> +		__rte_ring_rts_update_tail(&r->rts_cons);
> +	}
> +
> +	if (available != NULL)
> +		*available = entries - n;
> +	return n;
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   The number of objects enqueued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mp_rts_enqueue_bulk_elem(struct rte_ring *r, void * const *obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *free_space)
> +{
> +	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
> +			RTE_RING_QUEUE_FIXED, free_space);
> +}
> +
> +/**
> + * Dequeue several objects from an RTS ring (multi-consumers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   The number of objects dequeued, either 0 or n
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned int
> +rte_ring_mc_rts_dequeue_bulk_elem(struct rte_ring *r, void **obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *available)
> +{
> +	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
> +		RTE_RING_QUEUE_FIXED, available);
> +}
> +
> +/**
> + * Enqueue several objects on the RTS ring (multi-producers safe).
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects).
> + * @param n
> + *   The number of objects to add in the ring from the obj_table.
> + * @param free_space
> + *   if non-NULL, returns the amount of space in the ring after the
> + *   enqueue operation has finished.
> + * @return
> + *   - n: Actual number of objects enqueued.
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mp_rts_enqueue_burst_elem(struct rte_ring *r, void * const *obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *free_space)
> +{
> +	return __rte_ring_do_rts_enqueue_elem(r, obj_table, esize, n,
> +			RTE_RING_QUEUE_VARIABLE, free_space);
> +}
> +
> +/**
> + * Dequeue several objects from an RTS  ring (multi-consumers safe).
> + * When the requested objects are more than the available objects,
> + * only dequeue the actual number of objects.
> + *
> + * @param r
> + *   A pointer to the ring structure.
> + * @param obj_table
> + *   A pointer to a table of void * pointers (objects) that will be filled.
> + * @param n
> + *   The number of objects to dequeue from the ring to the obj_table.
> + * @param available
> + *   If non-NULL, returns the number of remaining ring entries after the
> + *   dequeue has finished.
> + * @return
> + *   - n: Actual number of objects dequeued, 0 if ring is empty
> + */
> +__rte_experimental
> +static __rte_always_inline unsigned
> +rte_ring_mc_rts_dequeue_burst_elem(struct rte_ring *r, void **obj_table,
> +	unsigned int esize, unsigned int n, unsigned int *available)
> +{
> +	return __rte_ring_do_rts_dequeue_elem(r, obj_table, esize, n,
> +			RTE_RING_QUEUE_VARIABLE, available);
> +}
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_RING_RTS_ELEM_H_ */
> diff --git a/lib/librte_ring/rte_ring_rts_generic.h b/lib/librte_ring/rte_ring_rts_generic.h
> new file mode 100644
> index 000000000..31a37924c
> --- /dev/null
> +++ b/lib/librte_ring/rte_ring_rts_generic.h
> @@ -0,0 +1,210 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * Copyright (c) 2010-2017 Intel Corporation
> + * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
> + * All rights reserved.
> + * Derived from FreeBSD's bufring.h
> + * Used as BSD-3 Licensed with permission from Kip Macy.
> + */
> +
> +#ifndef _RTE_RING_RTS_GENERIC_H_
> +#define _RTE_RING_RTS_GENERIC_H_
> +
> +/**
> + * @file rte_ring_rts_generic.h
> + * It is not recommended to include this file directly,
> + * include <rte_ring.h> instead.
> + * Contains internal helper functions for Relaxed Tail Sync (RTS) ring mode.
> + * For more information please refer to <rte_ring_rts.h>.
> + */
> +
> +/**
> + * @internal This function updates tail values.
> + */
> +static __rte_always_inline void
> +__rte_ring_rts_update_tail(struct rte_ring_rts_headtail *ht)
> +{
> +	union rte_ring_ht_poscnt h, ot, nt;
> +
> +	/*
> +	 * If there are other enqueues/dequeues in progress that
> +	 * might preceded us, then don't update tail with new value.
> +	 */
> +
> +	do {
> +		ot.raw = ht->tail.raw;
> +		rte_smp_rmb();
> +
> +		/* on 32-bit systems we have to do atomic read here */
> +		h.raw = rte_atomic64_read((rte_atomic64_t *)
> +			(uintptr_t)&ht->head.raw);
> +
> +		nt.raw = ot.raw;
> +		if (++nt.val.cnt == h.val.cnt)
> +			nt.val.pos = h.val.pos;
> +
> +	} while (rte_atomic64_cmpset(&ht->tail.raw, ot.raw, nt.raw) == 0);
> +}
> +
> +/**
> + * @internal This function waits till head/tail distance wouldn't
> + * exceed pre-defined max value.
> + */
> +static __rte_always_inline void
> +__rte_ring_rts_head_wait(const struct rte_ring_rts_headtail *ht,
> +	union rte_ring_ht_poscnt *h)
> +{
> +	uint32_t max;
> +
> +	max = ht->htd_max;
> +	h->raw = ht->head.raw;
> +	rte_smp_rmb();
> +
> +	while (h->val.pos - ht->tail.val.pos > max) {
> +		rte_pause();
> +		h->raw = ht->head.raw;
> +		rte_smp_rmb();
> +	}
> +}
> +
> +/**
> + * @internal This function updates the producer head for enqueue.
> + *
> + * @param r
> + *   A pointer to the ring structure
> + * @param is_sp
> + *   Indicates whether multi-producer path is needed or not
> + * @param n
> + *   The number of elements we will want to enqueue, i.e. how far should the
> + *   head be moved
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
> + * @param old_head
> + *   Returns head value as it was before the move, i.e. where enqueue starts
> + * @param new_head
> + *   Returns the current/new head value i.e. where enqueue finishes
> + * @param free_entries
> + *   Returns the amount of free space in the ring BEFORE head was moved
> + * @return
> + *   Actual number of objects enqueued.
> + *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline uint32_t
> +__rte_ring_rts_move_prod_head(struct rte_ring *r, uint32_t num,
> +	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
> +	uint32_t *free_entries)
> +{
> +	uint32_t n;
> +	union rte_ring_ht_poscnt nh, oh;
> +
> +	const uint32_t capacity = r->capacity;
> +
> +	do {
> +		/* Reset n to the initial burst count */
> +		n = num;
> +
> +		/* read prod head (may spin on prod tail) */
> +		__rte_ring_rts_head_wait(&r->rts_prod, &oh);
> +
> +		/* add rmb barrier to avoid load/load reorder in weak
> +		 * memory model. It is noop on x86
> +		 */
> +		rte_smp_rmb();
> +
> +		/*
> +		 *  The subtraction is done between two unsigned 32bits value
> +		 * (the result is always modulo 32 bits even if we have
> +		 * *old_head > cons_tail). So 'free_entries' is always between 0
> +		 * and capacity (which is < size).
> +		 */
> +		*free_entries = capacity + r->cons.tail - oh.val.pos;
> +
> +		/* check that we have enough room in ring */
> +		if (unlikely(n > *free_entries))
> +			n = (behavior == RTE_RING_QUEUE_FIXED) ?
> +					0 : *free_entries;
> +
> +		if (n == 0)
> +			return 0;
> +
> +		nh.val.pos = oh.val.pos + n;
> +		nh.val.cnt = oh.val.cnt + 1;
> +
> +	} while (rte_atomic64_cmpset(&r->rts_prod.head.raw,
> +			oh.raw, nh.raw) == 0);
> +
> +	*old_head = oh.val.pos;
> +	return n;
> +}
> +
> +/**
> + * @internal This function updates the consumer head for dequeue
> + *
> + * @param r
> + *   A pointer to the ring structure
> + * @param is_sc
> + *   Indicates whether multi-consumer path is needed or not
> + * @param n
> + *   The number of elements we will want to enqueue, i.e. how far should the
> + *   head be moved
> + * @param behavior
> + *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
> + *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
> + * @param old_head
> + *   Returns head value as it was before the move, i.e. where dequeue starts
> + * @param new_head
> + *   Returns the current/new head value i.e. where dequeue finishes
> + * @param entries
> + *   Returns the number of entries in the ring BEFORE head was moved
> + * @return
> + *   - Actual number of objects dequeued.
> + *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
> + */
> +static __rte_always_inline unsigned int
> +__rte_ring_rts_move_cons_head(struct rte_ring *r, uint32_t num,
> +	enum rte_ring_queue_behavior behavior, uint32_t *old_head,
> +	uint32_t *entries)
> +{
> +	uint32_t n;
> +	union rte_ring_ht_poscnt nh, oh;
> +
> +	/* move cons.head atomically */
> +	do {
> +		/* Restore n as it may change every loop */
> +		n = num;
> +
> +		/* read cons head (may spin on cons tail) */
> +		__rte_ring_rts_head_wait(&r->rts_cons, &oh);
> +
> +
> +		/* add rmb barrier to avoid load/load reorder in weak
> +		 * memory model. It is noop on x86
> +		 */
> +		rte_smp_rmb();
> +
> +		/* The subtraction is done between two unsigned 32bits value
> +		 * (the result is always modulo 32 bits even if we have
> +		 * cons_head > prod_tail). So 'entries' is always between 0
> +		 * and size(ring)-1.
> +		 */
> +		*entries = r->prod.tail - oh.val.pos;
> +
> +		/* Set the actual entries for dequeue */
> +		if (n > *entries)
> +			n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 : *entries;
> +
> +		if (unlikely(n == 0))
> +			return 0;
> +
> +		nh.val.pos = oh.val.pos + n;
> +		nh.val.cnt = oh.val.cnt + 1;
> +
> +	} while (rte_atomic64_cmpset(&r->rts_cons.head.raw,
> +			oh.raw, nh.raw) == 0);
> +
> +	*old_head = oh.val.pos;
> +	return n;
> +}
> +
> +#endif /* _RTE_RING_RTS_GENERIC_H_ */
> --
> 2.17.1


^ permalink raw reply	[relevance 7%]

* [dpdk-dev] [PATCH v1 0/8] New sync modes for ring
  2020-02-24 11:35  2% [dpdk-dev] [RFC 0/6] New sync modes for ring Konstantin Ananyev
  2020-02-24 16:59  0% ` Stephen Hemminger
  2020-03-25 20:43  0% ` Honnappa Nagarahalli
@ 2020-03-31 16:43  3% ` Konstantin Ananyev
  2020-04-02 22:09  3%   ` [dpdk-dev] [PATCH v2 0/9] " Konstantin Ananyev
  2 siblings, 1 reply; 200+ results
From: Konstantin Ananyev @ 2020-03-31 16:43 UTC (permalink / raw)
  To: dev; +Cc: honnappa.nagarahalli, Konstantin Ananyev

RFC - V1 changes:
1. remove ABI brekage (at least I hope I did)
2. Add support for ring_elem
3. Rework peek related API a bit
4. Rework test to make it less verbose and unite all test-cases
   in one command
5. Add new test-case for MT peek API

TODO list:
1. Add C11 atomics support
2. Update docs

These days many customers use(/try to use) DPDK based apps within
overcommitted systems (multiple acttive threads over same pysical cores):
VM, container deployments, etc.
One quite common problem they hit:
Lock-Holder-Preemption/Lock-Waiter-Preemption with rte_ring.
LHP/LWP are quite a common problem for spin-based sync primitives
(spin-locks, etc.) on overcommitted systems.
The situation gets much worse when some sort of
fair-locking technique is used (ticket-lock, etc.).
As now not only lock-owner but also lock-waiters scheduling
order matters a lot.
This is a well-known problem for kernel within VMs:
http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
The problem with rte_ring is that while head accusion is sort of
un-fair locking, waiting on tail is very similar to ticket lock schema -
tail has to be updated in particular order.
That makes current rte_ring implementation to perform
really pure on some overcommited scenarios.
While it is probably not possible to completely resolve LHP problem in
userspace only (without some kernel communication/intervention),
removing fairness in tail update can mitigate it significantly.
So this RFC proposes two new optional ring synchronization modes:
1) Head/Tail Sync (HTS) mode
In that mode enqueue/dequeue operation is fully serialized:
    only one thread at a time is allowed to perform given op.
    As another enhancement provide ability to split enqueue/dequeue
    operation into two phases:
      - enqueue/dequeue start
      - enqueue/dequeue finish
    That allows user to inspect objects in the ring without removing
    them from it (aka MT safe peek).
2) Relaxed Tail Sync (RTS)
The main difference from original MP/MC algorithm is that
tail value is increased not by every thread that finished enqueue/dequeue,
but only by the last one.
That allows threads to avoid spinning on ring tail value,
leaving actual tail value change to the last thread in the update queue.

Note that these new sync modes are optional.
For current rte_ring users nothing should change
(both in terms of API/ABI and performance).
Existing sync modes MP/MC,SP/SC kept untouched, set up in the same
way (via flags and _init_), and MP/MC remains as default one.
The only thing that changed:
Format of prod/cons now could differ depending on mode selected at _init_.
So user has to stick with one sync model through whole ring lifetime.
In other words, user can't create a ring for let say SP mode and then
in the middle of data-path change his mind and start using MP_RTS mode.
For existing modes (SP/MP, SC/MC) format remains the same and
user can still use them interchangeably, though of course it is an
error prone practice. 

Test results on IA (see below) show significant improvements
for average enqueue/dequeue op times on overcommitted systems.
For 'classic' DPDK deployments (one thread per core) original MP/MC
algorithm still shows best numbers, though for 64-bit target
RTS numbers are not that far away.
Numbers were produced by new UT test-case: ring_stress_autotest, i.e.:
echo ring_stress_autotest | ./dpdk-test -n 4 --lcores='...'

X86_64 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     8.00       8.15    8.99
2thread@2core(--lcores=6-8)                     19.14      19.61   20.35
4thread@4core(--lcores=6-10)                    29.43      29.79   31.82
8thread@8core(--lcores=6-14)                    110.59     192.81  119.50
16thread@16core(--lcores=6-22)                  461.03     813.12  495.59
32thread/@32core(--lcores='6-22,55-70')         982.90     1972.38 1160.51

2thread@1core(--lcores='6,(10-11)@7'            20140.50   23.58   25.14
4thread@2core(--lcores='6,(10-11)@7,(20-21)@8'  153680.60  76.88   80.05
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  280314.32  294.72  318.79
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 643176.59  1144.02 1175.14
32thread@2core(--lcores='6,(10-25)@7,(30-45)@8' 4264238.80 4627.48 4892.68

8thread@2core(--lcores='6,(10-17)@(7,8))'       321085.98  298.59  307.47
16thread@4core(--lcores='6,(20-35)@(7-10))'     1900705.61 575.35  678.29
32thread@4core(--lcores='6,(20-51)@(7-10))'     5510445.85 2164.36 2714.12

i686 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     7.85       12.13   11.31
2thread@2core(--lcores=6-8)                     17.89      24.52   21.86
8thread@8core(--lcores=6-14)                    32.58      354.20  54.58
32thread/@32core(--lcores='6-22,55-70')         813.77     6072.41 2169.91

2thread@1core(--lcores='6,(10-11)@7'            16095.00   36.06   34.74
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  1140354.54 346.61  361.57
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 1920417.86 1314.90 1416.65

8thread@2core(--lcores='6,(10-17)@(7,8))'       594358.61  332.70  357.74
32thread@4core(--lcores='6,(20-51)@(7-10))'     5319896.86 2836.44 3028.87

Konstantin Ananyev (8):
  test/ring: add contention stress test
  ring: prepare ring to allow new sync schemes
  ring: introduce RTS ring mode
  test/ring: add contention stress test for RTS ring
  ring: introduce HTS ring mode
  test/ring: add contention stress test for HTS ring
  ring: introduce peek style API
  test/ring: add stress test for MT peek API

 app/test/Makefile                      |   5 +
 app/test/meson.build                   |   5 +
 app/test/test_pdump.c                  |   6 +-
 app/test/test_ring_hts_stress.c        |  32 ++
 app/test/test_ring_mpmc_stress.c       |  31 ++
 app/test/test_ring_peek_stress.c       |  43 +++
 app/test/test_ring_rts_stress.c        |  32 ++
 app/test/test_ring_stress.c            |  57 ++++
 app/test/test_ring_stress.h            |  37 +++
 app/test/test_ring_stress_impl.h       | 436 +++++++++++++++++++++++++
 lib/librte_pdump/rte_pdump.c           |   2 +-
 lib/librte_port/rte_port_ring.c        |  12 +-
 lib/librte_ring/Makefile               |   9 +-
 lib/librte_ring/meson.build            |   9 +-
 lib/librte_ring/rte_ring.c             | 114 ++++++-
 lib/librte_ring/rte_ring.h             | 243 ++++++++++++--
 lib/librte_ring/rte_ring_c11_mem.h     |  44 +++
 lib/librte_ring/rte_ring_elem.h        | 105 +++++-
 lib/librte_ring/rte_ring_generic.h     |  48 +++
 lib/librte_ring/rte_ring_hts.h         | 210 ++++++++++++
 lib/librte_ring/rte_ring_hts_elem.h    | 205 ++++++++++++
 lib/librte_ring/rte_ring_hts_generic.h | 235 +++++++++++++
 lib/librte_ring/rte_ring_peek.h        | 379 +++++++++++++++++++++
 lib/librte_ring/rte_ring_rts.h         | 316 ++++++++++++++++++
 lib/librte_ring/rte_ring_rts_elem.h    | 205 ++++++++++++
 lib/librte_ring/rte_ring_rts_generic.h | 210 ++++++++++++
 26 files changed, 2974 insertions(+), 56 deletions(-)
 create mode 100644 app/test/test_ring_hts_stress.c
 create mode 100644 app/test/test_ring_mpmc_stress.c
 create mode 100644 app/test/test_ring_peek_stress.c
 create mode 100644 app/test/test_ring_rts_stress.c
 create mode 100644 app/test/test_ring_stress.c
 create mode 100644 app/test/test_ring_stress.h
 create mode 100644 app/test/test_ring_stress_impl.h
 create mode 100644 lib/librte_ring/rte_ring_hts.h
 create mode 100644 lib/librte_ring/rte_ring_hts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_hts_generic.h
 create mode 100644 lib/librte_ring/rte_ring_peek.h
 create mode 100644 lib/librte_ring/rte_ring_rts.h
 create mode 100644 lib/librte_ring/rte_ring_rts_elem.h
 create mode 100644 lib/librte_ring/rte_ring_rts_generic.h

-- 
2.17.1


^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v2] doc: use svg file type for ice
  2020-03-31 12:01  1% [dpdk-dev] [PATCH v1] doc: use svg file type for ice nic Haiyue Wang
@ 2020-03-31 12:06  1% ` Haiyue Wang
  2020-04-01  5:44  1% ` [dpdk-dev] [PATCH v3] doc: use svg file type for ice PMD Haiyue Wang
  1 sibling, 0 replies; 200+ results
From: Haiyue Wang @ 2020-03-31 12:06 UTC (permalink / raw)
  To: dev, xiaolong.ye, ferruh.yigit; +Cc: Haiyue Wang

Replace the binary format png with text type svg.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
v2: Fix the commit tile log format error

---
 doc/guides/nics/img/ice_dcf.png | Bin 39168 -> 0 bytes
 doc/guides/nics/img/ice_dcf.svg | 727 ++++++++++++++++++++++++++++++++
 2 files changed, 727 insertions(+)
 delete mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 doc/guides/nics/img/ice_dcf.svg

diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
deleted file mode 100644
index 540823c4a05e9ea9d558d233fea77016d1ae5df3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/doc/guides/nics/img/ice_dcf.svg b/doc/guides/nics/img/ice_dcf.svg
new file mode 100644
index 000000000..58851ca5d
--- /dev/null
+++ b/doc/guides/nics/img/ice_dcf.svg
@@ -0,0 +1,727 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="568px" height="513px" viewBox="0 0 568 513" enable-background="new 0 0 568 513" xml:space="preserve">  <image id="image0" width="568" height="513" x="0" y="0"
+    href="data:image/png;base64,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" />
+</svg>
-- 
2.26.0


^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v1] doc: use svg file type for ice nic
@ 2020-03-31 12:01  1% Haiyue Wang
  2020-03-31 12:06  1% ` [dpdk-dev] [PATCH v2] doc: use svg file type for ice Haiyue Wang
  2020-04-01  5:44  1% ` [dpdk-dev] [PATCH v3] doc: use svg file type for ice PMD Haiyue Wang
  0 siblings, 2 replies; 200+ results
From: Haiyue Wang @ 2020-03-31 12:01 UTC (permalink / raw)
  To: dev, xiaolong.ye, ferruh.yigit; +Cc: Haiyue Wang

Replace the binary format png with text type svg.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
 doc/guides/nics/img/ice_dcf.png | Bin 39168 -> 0 bytes
 doc/guides/nics/img/ice_dcf.svg | 727 ++++++++++++++++++++++++++++++++
 2 files changed, 727 insertions(+)
 delete mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 doc/guides/nics/img/ice_dcf.svg

diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
deleted file mode 100644
index 540823c4a05e9ea9d558d233fea77016d1ae5df3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/doc/guides/nics/img/ice_dcf.svg b/doc/guides/nics/img/ice_dcf.svg
new file mode 100644
index 000000000..58851ca5d
--- /dev/null
+++ b/doc/guides/nics/img/ice_dcf.svg
@@ -0,0 +1,727 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="568px" height="513px" viewBox="0 0 568 513" enable-background="new 0 0 568 513" xml:space="preserve">  <image id="image0" width="568" height="513" x="0" y="0"
+    href="data:image/png;base64,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" />
+</svg>
-- 
2.26.0


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-03-30 21:29  0%     ` Honnappa Nagarahalli
@ 2020-03-30 23:37  0%       ` Honnappa Nagarahalli
  2020-03-31 17:21  0%         ` Ananyev, Konstantin
  0 siblings, 1 reply; 200+ results
From: Honnappa Nagarahalli @ 2020-03-30 23:37 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev; +Cc: olivier.matz, nd, Honnappa Nagarahalli, nd

<snip>
> 
> > >
> > > > Subject: [dpdk-dev] [RFC 0/6] New sync modes for ring
> > > >
> > > > Upfront note - that RFC is not a complete patch.
> > > > It introduces an ABI breakage, plus it doesn't update ring_elem
> > > > code properly,
> > > As per the current rules, these changes (in the current form) will
> > > be accepted only for 20.11 release. How do we address this for
> > > immediate
> > requirements like RCU defer APIs?
> >
> > I think I found a way to introduce these new modes without API/ABI
> breakage.
> > Working on v1 right now. Plan to submit it by end of that week/start
> > of next one.
> ok
RCU defer APIs require the rte_ring_xxx_elem versions. I guess you are adding those as well.

> 
<snip>


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-03-26  1:50  3%   ` Ananyev, Konstantin
@ 2020-03-30 21:29  0%     ` Honnappa Nagarahalli
  2020-03-30 23:37  0%       ` Honnappa Nagarahalli
  0 siblings, 1 reply; 200+ results
From: Honnappa Nagarahalli @ 2020-03-30 21:29 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev; +Cc: olivier.matz, nd, Honnappa Nagarahalli, nd

<snip>

> >
> > > Subject: [dpdk-dev] [RFC 0/6] New sync modes for ring
> > >
> > > Upfront note - that RFC is not a complete patch.
> > > It introduces an ABI breakage, plus it doesn't update ring_elem code
> > > properly,
> > As per the current rules, these changes (in the current form) will be
> > accepted only for 20.11 release. How do we address this for immediate
> requirements like RCU defer APIs?
> 
> I think I found a way to introduce these new modes without API/ABI breakage.
> Working on v1 right now. Plan to submit it by end of that week/start of next
> one.
ok

> 
> > I suggest that we move forward with my RFC (taking into consideration your
> feedback) to make progress on RCU APIs.
> >
> > > etc.
> > > I plan to deal with all these things in later versions.
> > > Right now I seek an initial feedback about proposed ideas.
> > > Would also ask people to repeat performance tests (see below) on
> > > their platforms to confirm the impact.
> > >
> > > More and more customers use(/try to use) DPDK based apps within
> > > overcommitted systems (multiple acttive threads over same pysical cores):
> > > VM, container deployments, etc.
> > > One quite common problem they hit: Lock-Holder-Preemption with
> rte_ring.
> > > LHP is quite a common problem for spin-based sync primitives
> > > (spin-locks, etc.) on overcommitted systems.
> > > The situation gets much worse when some sort of fair-locking
> > > technique is used (ticket-lock, etc.).
> > > As now not only lock-owner but also lock-waiters scheduling order
> > > matters a lot.
> > > This is a well-known problem for kernel within VMs:
> > > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > > The problem with rte_ring is that while head accusion is sort of
> > > un-fair locking, waiting on tail is very similar to ticket lock
> > > schema - tail has to be updated in particular order.
> > > That makes current rte_ring implementation to perform really pure on
> > > some overcommited scenarios.
> > > While it is probably not possible to completely resolve this problem
> > > in userspace only (without some kernel communication/intervention),
> > > removing fairness in tail update can mitigate it significantly.
> > > So this RFC proposes two new optional ring synchronization modes:
> > > 1) Head/Tail Sync (HTS) mode
> > > In that mode enqueue/dequeue operation is fully serialized:
> > >     only one thread at a time is allowed to perform given op.
> > >     As another enhancement provide ability to split enqueue/dequeue
> > >     operation into two phases:
> > >       - enqueue/dequeue start
> > >       - enqueue/dequeue finish
> > >     That allows user to inspect objects in the ring without removing
> > >     them from it (aka MT safe peek).
> > IMO, this will not address the problem described above.
> 
> It does, please see the results produced by ring_stress_*autotest below.
> Let say for test-case: 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8' it
Had not looked at these tests. Please see the numbers below.

> shows:
> avg number of cycles per object for enqueue /dequeue:
> MP/MC: 280314.32
> HTS:         294.72
> RTS:         318.79
> 
> Customer who tried it reported similar level of improvement.
Is this tested with the VM/Container setup described in the slides you referred to?

> Actually if you have time - would be very interesting to see what numbers will
> be on ARM boxes.
> To reproduce, just:
> $cat ring_tests_u4
> ring_stress_autotest
> ring_stress_hts_autotest
> ring_stress_rts_autotest
> 
> /app/test/dpdk-test --lcores='6,(10-13)@7,(20-23)@8'  -n 4 < ring_tests_u4
> 2>&1 | tee res1
> 
> Then look at the ' AGGREGATE' stats.
> Right now it is a bit too verbose, so probably the easiest thing to extract same
> numbers quickly:
> grep 'cycles/obj'  res1 | grep 'cycles/obj' | cat -n | awk '{if ($(1)%9==0) print
> $(NF);}'
> 280314.32
> 1057833.55
> 294.72
> 480.10
> 318.79
> 461.52
> 
> First 2 numbers will be for MP/MC, next 2 for HTS, last 2 for RTS.
12305.05
12027.09
3.59
7.37
4.41
7.98

> 
> > For ex: when a producer updates the head and gets scheduled out, other
> > producers have to spin.
> 
> Sure, as I wrote in original cover letter:
> " While it is probably not possible to completely resolve this problem in
> userspace only (without some kernel communication/intervention), removing
> fairness in tail update can mitigate it significantly."
> Results from the ring_stress_*_autotest confirm that.
> 
> > The problem is probably worse as with non-HTS case moving of the head
> > and copying of the ring elements can happen in parallel between the
> producers (similarly for consumers).
> 
> Yes as we serialize the ring, we remove possibility of simultaneous copy.
> That's why for 'normal' cases (one thread per core) original MP/MC is usually
> faster.
> Though on overcommitted scenarios current MP/MC performance degrades
> dramatically.
> The main problem with current MP/MC implementation is in that tail update
> have to be done in strict order (sort of fair locking scheme).
> Which means that we have much-much worse LHP manifestation, then when
> we use unfair schemes.
> With serialized ring (HTS) we remove that ordering completely (same idea as
> switch from fair to unfair locking for PV spin-locks).
> 
> > IMO, HTS should not be a configurable flag.
> 
> Why?
> 
> > In RCU requirement, a MP enqueue and HTS dequeue are required.
> 
> This is supported, user can specify different modes for consumer and
> producer:
> (0 | RING_F_MC_HTS_DEQ).
> Then it is up to the user either to call generic
> rte_ring_enqueue/rte_ring_dequeue,
> or specify mode manually by function name:
> rte_ring_mp_enqueue_bulk/ rte_ring_hts_dequeue_bulk.
Ok, that should be good.

> 
> >
> > > 2) Relaxed Tail Sync (RTS)
> > > The main difference from original MP/MC algorithm is that tail value
> > > is increased not by every thread that finished enqueue/dequeue, but
> > > only by the last one.
> > > That allows threads to avoid spinning on ring tail value, leaving
> > > actual tail value change to the last thread in the update queue.
> > This can be a configurable flag on the ring.
> > I am not sure how this solves the problem you have stated above
> > completely. Updating the count from all intermediate threads is still
> > required to update the value of the head. But yes, it reduces the severity of
> the problem by not enforcing the order in which the tail is updated.
> 
> As I said above, main source of slowdown here - that we have to  update tail in
> particular order.
> So the main objective (same as for HTS) is to remove that ordering.
> 
> > I also think it introduces the problem on the other side of the ring
> > because the tail is not updated soon enough (the other side has to wait
> longer for the elements to become available).
> 
> Yes, producer/consumer starvation.
> That's why we need max allowed Head-Tail-Distance (htd_max) - to limit how
> far head can go away from tail.
> 
> > It also introduces another configuration parameter (HTD_MAX_DEF) which
> > they have to deal with.
> 
> If user doesn't provide any value, it will be set by default to ring.capacity / 8.
> From my measurements works quite well.
> Though there possibility for the user to set another value, if needed.
> 
> > Users have to still implement the current hypervisor related solutions.
> 
> Didn't get what you trying to say with that phrase.
The references you provided talked about resolving LHP by doing co-scheduling of vCPUs (which I think could be applied to DPDK applications). I am saying that we still need such mechanisms along with these solutions.

> 
> > IMO, we should run the benchmark for this on an over committed setup to
> understand the benefits.
> 
> That's why I created ring_stress_*autotest test-cases and collected numbers
> provided below.
> I suppose they clearly show the problem on overcommitted scenarios, and
> how RTS/HTS improve that situation.
> Would appreciate if you repeat these tests on your machines.
> 
> >
> > >
> > > Test results on IA (see below) show significant improvements for
> > > average enqueue/dequeue op times on overcommitted systems.
> > > For 'classic' DPDK deployments (one thread per core) original MP/MC
> > > algorithm still shows best numbers, though for 64-bit target RTS
> > > numbers are not that far away.
> > > Numbers were produced by ring_stress_*autotest (first patch in these
> series).
> > >
> > > X86_64 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> > > DEQ+ENQ average cycles/obj
> > >
> > >                                                 MP/MC      HTS     RTS
> > > 1thread@1core(--lcores=6-7)                     8.00       8.15    8.99
> > > 2thread@2core(--lcores=6-8)                     19.14      19.61   20.35
> > > 4thread@4core(--lcores=6-10)                    29.43      29.79   31.82
> > > 8thread@8core(--lcores=6-14)                    110.59     192.81  119.50
> > > 16thread@16core(--lcores=6-22)                  461.03     813.12  495.59
> > > 32thread/@32core(--lcores='6-22,55-70')         982.90     1972.38 1160.51
> > >
> > > 2thread@1core(--lcores='6,(10-11)@7'            20140.50   23.58   25.14
> > > 4thread@2core(--lcores='6,(10-11)@7,(20-21)@8'  153680.60  76.88
> 80.05
> > > 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  280314.32  294.72
> > > 318.79 16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 643176.59
> > > 1144.02
> > > 1175.14 32thread@2core(--lcores='6,(10-25)@7,(30-45)@8' 4264238.80
> > > 4627.48 4892.68
> > >
> > > 8thread@2core(--lcores='6,(10-17)@(7,8))'       321085.98  298.59  307.47
> > > 16thread@4core(--lcores='6,(20-35)@(7-10))'     1900705.61 575.35
> 678.29
> > > 32thread@4core(--lcores='6,(20-51)@(7-10))'     5510445.85 2164.36
> 2714.12
> > >
> > > i686 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> > > DEQ+ENQ average cycles/obj
> > >
> > >                                                 MP/MC      HTS     RTS
> > > 1thread@1core(--lcores=6-7)                     7.85       12.13   11.31
> > > 2thread@2core(--lcores=6-8)                     17.89      24.52   21.86
> > > 8thread@8core(--lcores=6-14)                    32.58      354.20  54.58
> > > 32thread/@32core(--lcores='6-22,55-70')         813.77     6072.41 2169.91
> > >
> > > 2thread@1core(--lcores='6,(10-11)@7'            16095.00   36.06   34.74
> > > 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  1140354.54 346.61
> > > 361.57 16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 1920417.86
> > > 1314.90
> > > 1416.65
> > >
> > > 8thread@2core(--lcores='6,(10-17)@(7,8))'       594358.61  332.70  357.74
> > > 32thread@4core(--lcores='6,(20-51)@(7-10))'     5319896.86 2836.44
> 3028.87
> > >
> > > Konstantin Ananyev (6):
> > >   test/ring: add contention stress test
> > >   ring: rework ring layout to allow new sync schemes
> > >   ring: introduce RTS ring mode
> > >   test/ring: add contention stress test for RTS ring
> > >   ring: introduce HTS ring mode
> > >   test/ring: add contention stress test for HTS ring
> > >
> > >  app/test/Makefile                      |   3 +
> > >  app/test/meson.build                   |   3 +
> > >  app/test/test_pdump.c                  |   6 +-
> > >  app/test/test_ring_hts_stress.c        |  28 ++
> > >  app/test/test_ring_rts_stress.c        |  28 ++
> > >  app/test/test_ring_stress.c            |  27 ++
> > >  app/test/test_ring_stress.h            | 477 +++++++++++++++++++
> > >  lib/librte_pdump/rte_pdump.c           |   2 +-
> > >  lib/librte_port/rte_port_ring.c        |  12 +-
> > >  lib/librte_ring/Makefile               |   4 +-
> > >  lib/librte_ring/meson.build            |   4 +-
> > >  lib/librte_ring/rte_ring.c             |  84 +++-
> > >  lib/librte_ring/rte_ring.h             | 619 +++++++++++++++++++++++--
> > >  lib/librte_ring/rte_ring_elem.h        |   8 +-
> > >  lib/librte_ring/rte_ring_hts_generic.h | 228 +++++++++
> > > lib/librte_ring/rte_ring_rts_generic.h | 240 ++++++++++
> > >  16 files changed, 1721 insertions(+), 52 deletions(-)  create mode
> > > 100644 app/test/test_ring_hts_stress.c  create mode 100644
> > > app/test/test_ring_rts_stress.c  create mode 100644
> > > app/test/test_ring_stress.c  create mode 100644
> > > app/test/test_ring_stress.h create mode 100644
> > > lib/librte_ring/rte_ring_hts_generic.h
> > >  create mode 100644 lib/librte_ring/rte_ring_rts_generic.h
> > >
> > > --
> > > 2.17.1


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 0/4] Introduce IF proxy library
  2020-03-26 12:41  3%     ` Andrzej Ostruszka
@ 2020-03-30 19:23  3%       ` Andrzej Ostruszka
  0 siblings, 0 replies; 200+ results
From: Andrzej Ostruszka @ 2020-03-30 19:23 UTC (permalink / raw)
  To: David Marchand, Andrzej Ostruszka; +Cc: dev

On 3/26/20 1:41 PM, Andrzej Ostruszka wrote:
> Thank you David for taking time to look at this.
> 
> On 3/25/20 9:08 AM, David Marchand wrote:
>> Hello Andrzej,
>>
>> On Tue, Mar 10, 2020 at 12:11 PM Andrzej Ostruszka
> [...]
>> I can see we end up exposing structures for registering callbacks.
> 
> Right.  I was thinking more in terms of user convenience so it seemed
> like a good choice to gather them in one struct and call 'register'
> once.  The fact that the same structure is used to keep them is an
> implementation choice and this can be decoupled.
> 
>> Did you consider some ways to avoid exposure of those? (thinking of
>> ABI maintenance for when this library will elect to non-experimental).
> 
> I will.  So far I used the union for the input since I like when things
> are well typed :) and there is no need for casting.  However I will
> spend some time on this and will get back to you soon (if you have
> already something in your head please share).  Right now I'm thinking
> about taking array of callbacks with each entry being ("event type",
> callback) pair, however need to figure out how to have minimum amount of
> type casting.

David, I thought about this a bit and here is my proposal.

Define "typeful" callback pointer (public):

union rte_ifpx_cb_ptr {
    int (*mac_change)(const struct mac_change *ev);
    int (*mtu_change)(const struct mtu_change *ev);
    ...
    int (*cfg_done)(void);
};

In implementation make sure its size is as expected:

_Static_assert(sizeof(union rte_ifpx_cb_ptr) == sizeof (int(*)(void*)),
               "Size of callback pointer has to be"
               "equal to size of function pointer");

Accept as input tagged callbacks (also public type):

struct rte_ifpx_callback {
    enum rte_ifpx_event_type type;
    union rte_ifpx_cb_ptr callback;
};

The user would be defining array of callbacks:

struct rte_ifpx_callback callbacks[] = {
    {RTE_IFPX_MAC_CHANGE, {.mac_change = mac_change}},
    {RTE_IFPX_MTU_CHANGE, {.mtu_change = mtu_change}},
    ...
    {RTE_IFPX_CFG_DONE,   {.cfg_done   = finished}},
};

and passing it to registration together with its length like:

int rte_ifpx_callbacks_register(int len,
                                const struct rte_ifpx_callback *cbs)
{
    for (int i = 0; i < len; ++i) {
        switch (cbs[i].type) {
            case RTE_IFPX_MAC_CHANGE:
                priv_cbs.mac_change = cbs[i].callback.mac_change;
                break;
    ...
}

This way we should be protected from ABI breakage when adding new event
types and how the callbacks are stored would not be visible to the user.

Let me know what do you think about it.

With regards
Andrzej Ostruszka

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [RFC PATCH 7/9] eal/windows: fix rte_page_sizes with Clang on Windows
  @ 2020-03-30  4:10  3% ` Dmitry Kozlyuk
  0 siblings, 0 replies; 200+ results
From: Dmitry Kozlyuk @ 2020-03-30  4:10 UTC (permalink / raw)
  To: dev; +Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk, Anatoly Burakov

Clang on Windows follows MS ABI where enum values are signed 32-bit,
Enum rte_page_size has members valued beyond 2^32.  EAL cannot use
-fno-ms-compatibility because its code is OS-dependent.  The only option
is to define these values outside enum, but this prohibits using
-fstrict-enums.  Another consequence is that enum rte_page_size cannot
be used to hold page size, because on Windows it won't be able to hold
all possible values.

Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
 lib/librte_eal/common/include/rte_memory.h | 6 ++++++
 lib/librte_eal/meson.build                 | 1 +
 2 files changed, 7 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h
index 1742fde9a..5b0e2d8b5 100644
--- a/lib/librte_eal/common/include/rte_memory.h
+++ b/lib/librte_eal/common/include/rte_memory.h
@@ -34,8 +34,14 @@ enum rte_page_sizes {
 	RTE_PGSIZE_256M  = 1ULL << 28,
 	RTE_PGSIZE_512M  = 1ULL << 29,
 	RTE_PGSIZE_1G    = 1ULL << 30,
+/* Work around Clang on Windows being limited to 32-bit underlying type. */
+#if !defined(RTE_TOOLCHAIN_CLANG) || !defined(RTE_EXEC_ENV_WINDOWS)
 	RTE_PGSIZE_4G    = 1ULL << 32,
 	RTE_PGSIZE_16G   = 1ULL << 34,
+#else
+#define RTE_PGSIZE_4G  (1ULL << 32)
+#define RTE_PGSIZE_16G (1ULL << 34)
+#endif
 };
 
 #define SOCKET_ID_ANY -1                    /**< Any NUMA socket. */
diff --git a/lib/librte_eal/meson.build b/lib/librte_eal/meson.build
index 1730d603f..ec80bd6be 100644
--- a/lib/librte_eal/meson.build
+++ b/lib/librte_eal/meson.build
@@ -23,6 +23,7 @@ endif
 if cc.has_header('getopt.h')
 	cflags += ['-DHAVE_GETOPT_H', '-DHAVE_GETOPT', '-DHAVE_GETOPT_LONG']
 endif
+cflags += '-fno-strict-enums'
 sources = common_sources + env_sources
 objs = common_objs + env_objs
 headers = common_headers + env_headers
-- 
2.25.1


^ permalink raw reply	[relevance 3%]

* [dpdk-dev]  [PATCH v3 00/33] DPDK Trace support
  2020-03-25 21:15  1% ` [dpdk-dev] [PATCH v2 " jerinj
@ 2020-03-29 14:43  1%   ` jerinj
  2020-04-01  8:18  3%     ` David Marchand
  2020-04-03 15:36  1%     ` [dpdk-dev] [PATCH v4 " jerinj
  0 siblings, 2 replies; 200+ results
From: jerinj @ 2020-03-29 14:43 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson, david.marchand, mattias.ronnblom,
	skori, Jerin Jacob

From: Jerin Jacob <jerinj@marvell.com>


v3:
~~

1) Fix the following build issues reported by CI
http://mails.dpdk.org/archives/test-report/2020-March/122060.html

a) clang + i686 meson build issue(Fixed in the the patch meson: add libatomic as a global dependency for i686 clang)
b) fixed build issue with FreeBSD with top of tree change.
c) fixed missing experimental API for iavf and ice with meson build in avx512 files.

v2:
~~
Addressed the following review comments from Mattias Rönnblom:

1) Changed 

from:
typedef uint64_t* rte_trace_t;
to
typedef uint64_t rte_trace_t;

Initially thought to make the handle as
struct rte_trace {
    uint64_t val;
}

but changed to uint64_t for the following reasons
a) It is opaque to the application and it will fix the compile-time type
check as well.
b) The handle has an index that will point to an internal slow-path
structure so no ABI change required in the future.
c) RTE_TRACE_POINT_DEFINE need to expose trace object. So it is better
to keep as uint64_t and avoid one more indirection for no use.

2)
Changed:
from:
enum rte_trace_mode_e {
to:
enum rte_trace_mode {


3) removed [out] "found" param from rte_trace_pattern() and
rte_trace_regexp()


4) Changed rte_trace_from_name to rte_trace_by_name

5) rte_trace_is_dp_enabled() return bool now


6) in __rte_trace_point_register() the argument fn change to register_fn

7) removed !! from rte_trace_is_enabled()

8) Remove uninitialized "rc warning" from rte_trace_pattern() and
rte_trace_regexp()

9) fixup bool return type for trace_entry_compare()

10) fixup calloc casting in trace_mkdir()

11) check fclose() return in trace_meta_save() and trace_mem_save()

12) rte_trace_ctf_* macro cleanup

13) added release notes

14) fix build issues reported by CI
http://mails.dpdk.org/archives/test-report/2020-March/121235.html


This patch set contains 
~~~~~~~~~~~~~~~~~~~~~~~~

# The native implementation of common trace format(CTF)[1] based tracer
# Public API to create the trace points.
# Add tracepoints to eal, ethdev, mempool, eventdev and cryptodev 
library for tracing support
# A unit test case
# Performance test case to measure the trace overhead. (See eal/trace:
# add trace performance test cases, patch)
# Programmers guide for Trace support(See doc: add trace library guide,
# patch)

# Tested OS:
~~~~~~~~~~~
- Linux
- FreeBSD

# Tested open source CTF trace viewers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Babeltrace
- Tracecompass

# Trace overhead comparison with LTTng
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

trace overhead data on x86:[2]
# 236 cycles with LTTng(>100ns)
# 18 cycles(7ns) with Native DPDK CTF emitter.(See eal/trace: add trace
# performance test cases patch)

trace overhead data on arm64:
#  312  cycles to  1100 cycles with LTTng based on the class of arm64
#  CPU.
#  11 cycles to 13 cycles with Native DPDK CTF emitter based on the
class of arm64 CPU.

18 cycles(on x86) vs 11 cycles(on arm64) is due to rdtsc() overhead in
x86. It seems  rdtsc takes around 15cycles in x86.


Items that needs to be sort it out 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Makefile and meson.build are updated to allow experimental APIs.

As multiple EXPERIMENTAL symbols, exported by trace library, are
used in various drivers, lib, app and examples. So to fix compilation
warning/error, Makefile and meson.build are updated for all required
components to support EXPERIMENTAL APIs.
It results same code changes at multiple components as well as
increases source code line changes in patchset too.
Suggestions are welcome to resolve this issue with lesser code changes.
	
More details:
~~~~~~~~~~~~~

# The Native DPDK CTF trace support does not have any dependency on
third-party library.
The generated output file is compatible with LTTng as both are using
CTF trace format.

The performance gain comes from:
1) exploit dpdk worker thread usage model to avoid atomics and use per
core variables
2) use hugepage,
3) avoid a lot function pointers in fast-path etc
4) avoid unaligned store for arm64 etc

Features:
~~~~~~~~~
- APIs and Features are similar to rte_log dynamic framework
API(expect log prints on stdout vs it dumps on trace file)
- No specific limit on the events. A string-based event like rte_log
for pattern matching
- Dynamic enable/disable support.
- Instructmention overhead is ~1 cycle. i.e cost of adding the code
wth out using trace feature.
- Timestamp support for all the events using DPDK rte_rtdsc
- No dependency on another library. Clean room native implementation of
  CTF.

Functional test case:
a) echo "trace_autotest" | sudo ./build/app/test/dpdk-test  -c 0x3
--trace-level=8

The above command emits the following trace events
<code>
        uint8_t i;

        rte_trace_lib_eal_generic_void();
        rte_trace_lib_eal_generic_u64(0x10000000000000);
        rte_trace_lib_eal_generic_u32(0x10000000);
        rte_trace_lib_eal_generic_u16(0xffee);
        rte_trace_lib_eal_generic_u8(0xc);
        rte_trace_lib_eal_generic_i64(-1234);
        rte_trace_lib_eal_generic_i32(-1234567);
        rte_trace_lib_eal_generic_i16(12);
        rte_trace_lib_eal_generic_i8(-3);
        rte_trace_lib_eal_generic_string("my string");
        rte_trace_lib_eal_generic_function(__func__);

        for (i = 0; i < 128; i++)
                rte_trace_lib_eal_generic_u8(i);
</code>

Install babeltrace package in Linux and point the generated trace file
to babel trace. By default trace file created under
<user>/dpdk-traces/time_stamp/

example:
# babeltrace /root/dpdk-traces/rte-2020-02-15-PM-02-56-51 | more

[13:27:36.138468807] (+?.?????????) lib.eal.generic.void: { cpu_id =
0, name = "dpdk-test" }, { }
[13:27:36.138468851] (+0.000000044) lib.eal.generic.u64: { cpu_id = 0,
name = "dpdk-test" }, { in = 4503599627370496 }
[13:27:36.138468860] (+0.000000009) lib.eal.generic.u32: { cpu_id = 0,
name = "dpdk-test" }, { in = 268435456 }
[13:27:36.138468934] (+0.000000074) lib.eal.generic.u16: { cpu_id = 0,
name = "dpdk-test" }, { in = 65518 }
[13:27:36.138468949] (+0.000000015) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 12 }
[13:27:36.138468956] (+0.000000007) lib.eal.generic.i64: { cpu_id = 0,
name = "dpdk-test" }, { in = -1234 }
[13:27:36.138468963] (+0.000000007) lib.eal.generic.i32: { cpu_id = 0,
name = "dpdk-test" }, { in = -1234567 }
[13:27:36.138469024] (+0.000000061) lib.eal.generic.i16: { cpu_id = 0,
name = "dpdk-test" }, { in = 12 }
[13:27:36.138469044] (+0.000000020) lib.eal.generic.i8: { cpu_id = 0,
name = "dpdk-test" }, { in = -3 }
[13:27:36.138469051] (+0.000000007) lib.eal.generic.string: { cpu_id =
0, name = "dpdk-test" }, { str = "my string" }
[13:27:36.138469203] (+0.000000152) lib.eal.generic.func: { cpu_id =
0, name = "dpdk-test" }, { func = "test_trace_points" }
[13:27:36.138469239] (+0.000000036) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 0 }
[13:27:36.138469246] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 1 }
[13:27:36.138469252] (+0.000000006) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 2 }
[13:27:36.138469262] (+0.000000010) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 3 }
[13:27:36.138469269] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 4 }
[13:27:36.138469276] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 5 }

# There is a  GUI based trace viewer available in Windows, Linux and
# Mac.
It is called as tracecompass.(https://www.eclipse.org/tracecompass/)

The example screenshot and Histogram of above DPDK trace using
Tracecompass.

https://github.com/jerinjacobk/share/blob/master/dpdk_trace.JPG



File walk through:
~~~~~~~~~~~~~~~~~~

lib/librte_eal/common/include/rte_trace.h - Public API for Trace
provider and Trace control
lib/librte_eal/common/eal_common_trace.c - main trace implementation
lib/librte_eal/common/eal_common_trace_ctf.c - CTF metadata spec
implementation
lib/librte_eal/common/eal_common_trace_utils.c - command line utils
and filesystem operations.
lib/librte_eal/common/eal_common_trace_points.c -  trace points for EAL
library
lib/librte_eal/common/include/rte_trace_eal.h - EAL tracepoint public
API.
lib/librte_eal/common/eal_trace.h - Private trace header file.


[1] https://diamon.org/ctf/

[2] The above test is ported to LTTng for finding the LTTng trace
overhead. It available at
https://github.com/jerinjacobk/lttng-overhead
https://github.com/jerinjacobk/lttng-overhead/blob/master/README

Jerin Jacob (21):
  eal: introduce API for getting thread name
  eal: define the public API for trace support
  eal/trace: implement trace register API
  eal/trace: implement trace operation APIs
  eal/trace: add internal trace init and fini interface
  eal/trace: get bootup timestamp for trace
  eal/trace: create CTF TDSL metadata in memory
  eal/trace: implement trace memory allocation
  eal/trace: implement debug dump function
  eal/trace: implement trace save
  eal/trace: implement registration payload
  eal/trace: implement provider payload
  eal/trace: hook internal trace APIs to Linux
  eal/trace: hook internal trace APIs to FreeBSD
  eal/trace: add generic tracepoints
  eal/trace: add alarm tracepoints
  eal/trace: add memory tracepoints
  eal/trace: add memzone tracepoints
  eal/trace: add thread tracepoints
  eal/trace: add interrupt tracepoints
  eal/trace: add trace performance test cases

Pavan Nikhilesh (1):
  meson: add libatomic as a global dependency for i686 clang

Sunil Kumar Kori (11):
  eal/trace: handle CTF keyword collision
  eal/trace: add trace level configuration parameter
  eal/trace: add trace dir configuration parameter
  eal/trace: add trace bufsize configuration parameter
  eal/trace: add trace mode configuration parameter
  eal/trace: add unit test cases
  ethdev: add tracepoints
  eventdev: add tracepoints
  cryptodev: add tracepoints
  mempool: add tracepoints
  doc: add trace library guide

 MAINTAINERS                                   |  15 +
 app/pdump/Makefile                            |   1 +
 app/pdump/meson.build                         |   1 +
 app/proc-info/Makefile                        |   1 +
 app/proc-info/meson.build                     |   1 +
 app/test-acl/Makefile                         |   1 +
 app/test-acl/meson.build                      |   1 +
 app/test-cmdline/Makefile                     |   1 +
 app/test-cmdline/meson.build                  |   1 +
 app/test-eventdev/Makefile                    |   1 +
 app/test-eventdev/meson.build                 |   1 +
 app/test-pipeline/Makefile                    |   1 +
 app/test-pipeline/meson.build                 |   1 +
 app/test/Makefile                             |   4 +-
 app/test/meson.build                          |   3 +
 app/test/test_trace.c                         | 618 ++++++++++++++++++
 app/test/test_trace.h                         |  52 ++
 app/test/test_trace_perf.c                    | 179 +++++
 app/test/test_trace_register.c                |  46 ++
 config/common_base                            |   1 +
 config/meson.build                            |  10 +
 config/rte_config.h                           |   1 +
 doc/api/doxy-api-index.md                     |   3 +-
 doc/guides/linux_gsg/eal_args.include.rst     |  55 ++
 doc/guides/prog_guide/index.rst               |   1 +
 doc/guides/prog_guide/trace_lib.rst           | 265 ++++++++
 doc/guides/rel_notes/release_20_05.rst        |   9 +
 drivers/common/cpt/Makefile                   |   1 +
 drivers/crypto/ccp/Makefile                   |   1 +
 drivers/crypto/ccp/meson.build                |   2 +
 drivers/crypto/mvsam/Makefile                 |   1 +
 drivers/crypto/mvsam/meson.build              |   1 +
 drivers/crypto/null/Makefile                  |   1 +
 drivers/crypto/null/meson.build               |   1 +
 drivers/crypto/scheduler/Makefile             |   1 +
 drivers/crypto/scheduler/meson.build          |   1 +
 drivers/crypto/virtio/Makefile                |   1 +
 drivers/crypto/virtio/meson.build             |   1 +
 drivers/event/octeontx/Makefile               |   1 +
 drivers/event/octeontx/meson.build            |   6 +-
 drivers/event/octeontx2/meson.build           |   5 -
 drivers/event/opdl/meson.build                |   5 -
 drivers/event/skeleton/Makefile               |   1 +
 drivers/event/skeleton/meson.build            |   1 +
 drivers/event/sw/Makefile                     |   1 +
 drivers/event/sw/meson.build                  |   1 +
 drivers/mempool/ring/Makefile                 |   1 +
 drivers/mempool/ring/meson.build              |   1 +
 drivers/net/af_packet/Makefile                |   1 +
 drivers/net/af_packet/meson.build             |   1 +
 drivers/net/af_xdp/Makefile                   |   1 +
 drivers/net/af_xdp/meson.build                |   1 +
 drivers/net/ark/Makefile                      |   1 +
 drivers/net/ark/meson.build                   |   1 +
 drivers/net/bnxt/Makefile                     |   1 +
 drivers/net/bnxt/meson.build                  |   1 +
 drivers/net/cxgbe/Makefile                    |   1 +
 drivers/net/cxgbe/meson.build                 |   1 +
 drivers/net/enetc/Makefile                    |   1 +
 drivers/net/enetc/meson.build                 |   1 +
 drivers/net/hinic/Makefile                    |   1 +
 drivers/net/hinic/base/meson.build            |   3 +-
 drivers/net/hinic/meson.build                 |   1 +
 drivers/net/iavf/meson.build                  |   3 +
 drivers/net/ice/meson.build                   |   3 +
 drivers/net/ionic/ionic_dev.c                 |   1 +
 drivers/net/ionic/ionic_mac_api.c             |   1 +
 drivers/net/ionic/ionic_main.c                |   1 +
 drivers/net/kni/Makefile                      |   1 +
 drivers/net/kni/meson.build                   |   1 +
 drivers/net/liquidio/Makefile                 |   1 +
 drivers/net/liquidio/meson.build              |   1 +
 drivers/net/mvneta/Makefile                   |   1 +
 drivers/net/mvneta/meson.build                |   1 +
 drivers/net/mvpp2/Makefile                    |   1 +
 drivers/net/mvpp2/meson.build                 |   1 +
 drivers/net/nfb/Makefile                      |   1 +
 drivers/net/nfb/meson.build                   |   1 +
 drivers/net/null/Makefile                     |   1 +
 drivers/net/null/meson.build                  |   1 +
 drivers/net/octeontx/Makefile                 |   1 +
 drivers/net/octeontx2/Makefile                |   1 +
 drivers/net/octeontx2/meson.build             |   1 +
 drivers/net/pcap/Makefile                     |   1 +
 drivers/net/pcap/meson.build                  |   1 +
 drivers/net/ring/Makefile                     |   1 +
 drivers/net/ring/meson.build                  |   1 +
 drivers/net/szedata2/Makefile                 |   1 +
 drivers/net/szedata2/meson.build              |   1 +
 drivers/net/thunderx/base/meson.build         |   1 +
 drivers/net/vhost/Makefile                    |   1 +
 drivers/net/vhost/meson.build                 |   1 +
 drivers/raw/ioat/Makefile                     |   1 +
 drivers/raw/ioat/meson.build                  |   1 +
 drivers/raw/octeontx2_dma/Makefile            |   1 +
 drivers/raw/octeontx2_dma/meson.build         |   1 +
 drivers/raw/octeontx2_ep/Makefile             |   1 +
 drivers/raw/octeontx2_ep/meson.build          |   1 +
 drivers/raw/skeleton/Makefile                 |   1 +
 drivers/raw/skeleton/meson.build              |   1 +
 examples/cmdline/Makefile                     |   1 +
 examples/cmdline/meson.build                  |   1 +
 examples/distributor/Makefile                 |   1 +
 examples/distributor/meson.build              |   1 +
 examples/ethtool/ethtool-app/Makefile         |   1 +
 examples/eventdev_pipeline/meson.build        |   1 +
 examples/flow_filtering/Makefile              |   1 +
 examples/flow_filtering/meson.build           |   1 +
 examples/helloworld/Makefile                  |   1 +
 examples/helloworld/meson.build               |   1 +
 examples/ioat/Makefile                        |   1 +
 examples/ioat/meson.build                     |   1 +
 examples/ip_fragmentation/Makefile            |   2 +
 examples/ip_fragmentation/meson.build         |   1 +
 examples/ip_reassembly/Makefile               |   1 +
 examples/ip_reassembly/meson.build            |   1 +
 examples/ipv4_multicast/Makefile              |   1 +
 examples/ipv4_multicast/meson.build           |   1 +
 examples/l2fwd-cat/Makefile                   |   1 +
 examples/l2fwd-cat/meson.build                |   1 +
 examples/l2fwd-event/Makefile                 |   1 +
 examples/l2fwd-event/meson.build              |   6 +-
 examples/l2fwd-jobstats/Makefile              |   1 +
 examples/l2fwd-jobstats/meson.build           |   1 +
 examples/l2fwd-keepalive/Makefile             |   1 +
 examples/l2fwd-keepalive/ka-agent/Makefile    |   1 +
 examples/l2fwd-keepalive/meson.build          |   1 +
 examples/l3fwd-acl/Makefile                   |   1 +
 examples/l3fwd-acl/meson.build                |   1 +
 examples/l3fwd/Makefile                       |   1 +
 examples/l3fwd/meson.build                    |   1 +
 examples/link_status_interrupt/Makefile       |   1 +
 examples/link_status_interrupt/meson.build    |   1 +
 .../client_server_mp/mp_client/Makefile       |   1 +
 .../client_server_mp/mp_client/meson.build    |   1 +
 .../client_server_mp/mp_server/meson.build    |   1 +
 examples/multi_process/hotplug_mp/Makefile    |   1 +
 examples/multi_process/hotplug_mp/meson.build |   1 +
 examples/multi_process/simple_mp/Makefile     |   1 +
 examples/multi_process/simple_mp/meson.build  |   1 +
 examples/multi_process/symmetric_mp/Makefile  |   1 +
 .../multi_process/symmetric_mp/meson.build    |   1 +
 examples/ntb/Makefile                         |   1 +
 examples/ntb/meson.build                      |   1 +
 examples/packet_ordering/Makefile             |   1 +
 examples/packet_ordering/meson.build          |   1 +
 .../performance-thread/l3fwd-thread/Makefile  |   1 +
 .../l3fwd-thread/meson.build                  |   1 +
 .../performance-thread/pthread_shim/Makefile  |   1 +
 .../pthread_shim/meson.build                  |   1 +
 examples/ptpclient/Makefile                   |   1 +
 examples/ptpclient/meson.build                |   1 +
 examples/qos_meter/Makefile                   |   1 +
 examples/qos_meter/meson.build                |   1 +
 examples/qos_sched/Makefile                   |   1 +
 examples/qos_sched/meson.build                |   1 +
 examples/server_node_efd/node/Makefile        |   1 +
 examples/server_node_efd/node/meson.build     |   1 +
 examples/server_node_efd/server/Makefile      |   1 +
 examples/server_node_efd/server/meson.build   |   1 +
 examples/service_cores/Makefile               |   1 +
 examples/service_cores/meson.build            |   1 +
 examples/skeleton/Makefile                    |   1 +
 examples/skeleton/meson.build                 |   1 +
 examples/timer/Makefile                       |   1 +
 examples/timer/meson.build                    |   1 +
 examples/vm_power_manager/Makefile            |   1 +
 examples/vm_power_manager/meson.build         |   1 +
 examples/vmdq/Makefile                        |   1 +
 examples/vmdq/meson.build                     |   1 +
 examples/vmdq_dcb/Makefile                    |   1 +
 examples/vmdq_dcb/meson.build                 |   1 +
 lib/librte_bitratestats/Makefile              |   1 +
 lib/librte_bitratestats/meson.build           |   1 +
 lib/librte_cryptodev/Makefile                 |   4 +-
 lib/librte_cryptodev/cryptodev_trace_points.c |  70 ++
 lib/librte_cryptodev/meson.build              |   7 +-
 lib/librte_cryptodev/rte_cryptodev.c          |  18 +
 lib/librte_cryptodev/rte_cryptodev.h          |   6 +
 .../rte_cryptodev_version.map                 |  18 +
 lib/librte_cryptodev/rte_trace_cryptodev.h    | 133 ++++
 lib/librte_cryptodev/rte_trace_cryptodev_fp.h |  34 +
 lib/librte_distributor/Makefile               |   1 +
 lib/librte_distributor/meson.build            |   6 +-
 lib/librte_eal/common/Makefile                |   1 +
 lib/librte_eal/common/eal_common_log.c        |   9 +-
 lib/librte_eal/common/eal_common_memzone.c    |   9 +
 lib/librte_eal/common/eal_common_options.c    |  68 +-
 lib/librte_eal/common/eal_common_thread.c     |   3 +-
 lib/librte_eal/common/eal_common_trace.c      | 610 +++++++++++++++++
 lib/librte_eal/common/eal_common_trace_ctf.c  | 488 ++++++++++++++
 .../common/eal_common_trace_points.c          | 115 ++++
 .../common/eal_common_trace_utils.c           | 523 +++++++++++++++
 lib/librte_eal/common/eal_options.h           |   8 +
 lib/librte_eal/common/eal_private.h           |  11 +
 lib/librte_eal/common/eal_trace.h             | 122 ++++
 lib/librte_eal/common/include/rte_lcore.h     |  17 +
 lib/librte_eal/common/include/rte_trace.h     | 584 +++++++++++++++++
 lib/librte_eal/common/include/rte_trace_eal.h | 247 +++++++
 .../common/include/rte_trace_provider.h       | 137 ++++
 .../common/include/rte_trace_register.h       |  53 ++
 lib/librte_eal/common/meson.build             |   8 +
 lib/librte_eal/common/rte_malloc.c            |  60 +-
 lib/librte_eal/freebsd/eal/Makefile           |   4 +
 lib/librte_eal/freebsd/eal/eal.c              |  10 +
 lib/librte_eal/freebsd/eal/eal_alarm.c        |   3 +
 lib/librte_eal/freebsd/eal/eal_interrupts.c   |  54 +-
 lib/librte_eal/freebsd/eal/eal_thread.c       |  21 +-
 lib/librte_eal/linux/eal/Makefile             |   4 +
 lib/librte_eal/linux/eal/eal.c                |   9 +
 lib/librte_eal/linux/eal/eal_alarm.c          |   4 +
 lib/librte_eal/linux/eal/eal_interrupts.c     |  84 ++-
 lib/librte_eal/linux/eal/eal_thread.c         |  27 +-
 lib/librte_eal/rte_eal_version.map            |  59 ++
 lib/librte_ethdev/Makefile                    |   3 +
 lib/librte_ethdev/ethdev_trace_points.c       |  43 ++
 lib/librte_ethdev/meson.build                 |   5 +-
 lib/librte_ethdev/rte_ethdev.c                |  12 +
 lib/librte_ethdev/rte_ethdev.h                |   5 +
 lib/librte_ethdev/rte_ethdev_version.map      |  10 +
 lib/librte_ethdev/rte_trace_ethdev.h          |  90 +++
 lib/librte_ethdev/rte_trace_ethdev_fp.h       |  40 ++
 lib/librte_eventdev/Makefile                  |   3 +
 lib/librte_eventdev/eventdev_trace_points.c   | 173 +++++
 lib/librte_eventdev/meson.build               |   3 +
 .../rte_event_crypto_adapter.c                |  10 +
 .../rte_event_eth_rx_adapter.c                |  11 +
 .../rte_event_eth_tx_adapter.c                |  13 +-
 .../rte_event_eth_tx_adapter.h                |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c |   8 +-
 lib/librte_eventdev/rte_event_timer_adapter.h |   8 +
 lib/librte_eventdev/rte_eventdev.c            |   9 +
 lib/librte_eventdev/rte_eventdev.h            |   5 +-
 lib/librte_eventdev/rte_eventdev_version.map  |  42 ++
 lib/librte_eventdev/rte_trace_eventdev.h      | 278 ++++++++
 lib/librte_eventdev/rte_trace_eventdev_fp.h   |  75 +++
 lib/librte_gro/Makefile                       |   1 +
 lib/librte_gro/meson.build                    |   1 +
 lib/librte_gso/Makefile                       |   1 +
 lib/librte_gso/meson.build                    |   1 +
 lib/librte_ip_frag/Makefile                   |   1 +
 lib/librte_ip_frag/meson.build                |   1 +
 lib/librte_kni/Makefile                       |   1 +
 lib/librte_kni/meson.build                    |   1 +
 lib/librte_latencystats/Makefile              |   1 +
 lib/librte_latencystats/meson.build           |   1 +
 lib/librte_mempool/Makefile                   |   3 +
 lib/librte_mempool/mempool_trace_points.c     | 108 +++
 lib/librte_mempool/meson.build                |   7 +-
 lib/librte_mempool/rte_mempool.c              |  16 +
 lib/librte_mempool/rte_mempool.h              |  13 +
 lib/librte_mempool/rte_mempool_ops.c          |   7 +
 lib/librte_mempool/rte_mempool_version.map    |  26 +
 lib/librte_mempool/rte_trace_mempool.h        | 148 +++++
 lib/librte_mempool/rte_trace_mempool_fp.h     | 102 +++
 lib/librte_port/Makefile                      |   1 +
 lib/librte_port/meson.build                   |   1 +
 lib/librte_rcu/meson.build                    |   5 -
 lib/librte_reorder/Makefile                   |   1 +
 lib/librte_reorder/meson.build                |   1 +
 lib/librte_sched/Makefile                     |   1 +
 lib/librte_sched/meson.build                  |   1 +
 lib/librte_security/Makefile                  |   1 +
 lib/librte_security/meson.build               |   1 +
 lib/librte_table/Makefile                     |   1 +
 lib/librte_table/meson.build                  |   1 +
 266 files changed, 6286 insertions(+), 113 deletions(-)
 create mode 100644 app/test/test_trace.c
 create mode 100644 app/test/test_trace.h
 create mode 100644 app/test/test_trace_perf.c
 create mode 100644 app/test/test_trace_register.c
 create mode 100644 doc/guides/prog_guide/trace_lib.rst
 create mode 100644 lib/librte_cryptodev/cryptodev_trace_points.c
 create mode 100644 lib/librte_cryptodev/rte_trace_cryptodev.h
 create mode 100644 lib/librte_cryptodev/rte_trace_cryptodev_fp.h
 create mode 100644 lib/librte_eal/common/eal_common_trace.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_ctf.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_points.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_utils.c
 create mode 100644 lib/librte_eal/common/eal_trace.h
 create mode 100644 lib/librte_eal/common/include/rte_trace.h
 create mode 100644 lib/librte_eal/common/include/rte_trace_eal.h
 create mode 100644 lib/librte_eal/common/include/rte_trace_provider.h
 create mode 100644 lib/librte_eal/common/include/rte_trace_register.h
 create mode 100644 lib/librte_ethdev/ethdev_trace_points.c
 create mode 100644 lib/librte_ethdev/rte_trace_ethdev.h
 create mode 100644 lib/librte_ethdev/rte_trace_ethdev_fp.h
 create mode 100644 lib/librte_eventdev/eventdev_trace_points.c
 create mode 100644 lib/librte_eventdev/rte_trace_eventdev.h
 create mode 100644 lib/librte_eventdev/rte_trace_eventdev_fp.h
 create mode 100644 lib/librte_mempool/mempool_trace_points.c
 create mode 100644 lib/librte_mempool/rte_trace_mempool.h
 create mode 100644 lib/librte_mempool/rte_trace_mempool_fp.h

-- 
2.25.1


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  2020-03-27 14:36  3%           ` Ray Kinsella
@ 2020-03-27 15:19  3%             ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-03-27 15:19 UTC (permalink / raw)
  To: Van Haaren, Harry, Neil Horman, Ray Kinsella, David Marchand,
	Laatz, Kevin
  Cc: Dodji Seketeli, dev, Richardson, Bruce, Honnappa Nagarahalli

27/03/2020 15:36, Ray Kinsella:
> On 27/03/2020 14:32, Van Haaren, Harry wrote:
> > From: Thomas Monjalon <thomas@monjalon.net>
> >> 27/03/2020 14:44, Neil Horman:
> >>> On Fri, Mar 27, 2020 at 01:24:12PM +0100, David Marchand wrote:
> >>>> On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com>
> >> wrote:
> >>>>> --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> >>>>> +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> >>>>> @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
> >>>>>         /* (EAX 80000007h) EDX features */
> >>>>>         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
> >>>>>
> >>>>> +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and
> >> Quadword */
> >>>>> +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused
> >> Multiply-Add */
> >>>>> +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict
> >> Detection*/
> >>>>> +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
> >>>>> +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
> >>>>> +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit
> >> Manipulation */
> >>>>> +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit
> >> Manipulation 2 */
> >>>>> +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New
> >> Instructions */
> >>>>> +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
> >>>>> +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less
> >> Multiply */
> >>>>> +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural
> >> Network Instructions */
> >>>>> +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms
> >> */
> >>>>> +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount
> >> */
> >>>>> +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
> >>>>> +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store
> >> Instructions */
> >>>>> +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store
> >> Instructions 64B */
> >>>>> +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register
> >> Intersection */
> >>>>> +
> >>>>>         /* The last item */
> >>>>>         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be
> >> the last! */
> >>>>
> >>>> This is seen as an ABI break because of the change on _NUMFLAGS:
> >>>> https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351
> >>>>
> >>> It shouldn't be, as the only API calls we expose that use rte_cpu_flag_t
> >> accept
> >>> it as an integer parameter to see if the flag is enabled.  Theres no use of
> >> the
> >>> enum in a public array or any struct that is sized based on the number of
> >> flags,
> >>> so you should be good to go
> >>
> >> Indeed I cannot imagine an ABI incompatibility in this case.
> >> The only behaviour change is to accept new (higher) RTE_CPUFLAG values
> >> in functions rte_cpu_get_flag_enabled() and rte_cpu_get_flag_name().
> >> Is changing the range of valid values an ABI break?
> >> Why is it flagged by libabigail?
> > 
> > If this enum _MAX value was used by the application to allocate an array, that later our DPDK code would write to it could cause out-of-bounds array accesses of the application supplied array. Abigail doesn't know what applications could use the value for, so it flags it.
> > 
> > IMO Abigail is right to flag it to us - a manual review to understand what that _MAX enum value is used for, and then decide on a case by case basis seems the best way forward to me.
> > 
> > Thanks Neil/Thomas for reviewing, as reply in this thread, I also believe this is not going to break ABI.
> > 
>  
> +1 to Harrry's comments. 
> I can't immediately see how this might break the ABI either. 


So we all agree that increasing the range of valid rte_cpu_flag_t values
is OK for ABI compatibility.
This conclusion must be written as a libabigail exception in this patch.



^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  2020-03-27 13:18  5%     ` Van Haaren, Harry
@ 2020-03-27 15:04  0%       ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-03-27 15:04 UTC (permalink / raw)
  To: Van Haaren, Harry, Laatz, Kevin
  Cc: dev, Richardson, Bruce, Neil Horman, Thomas Monjalon,
	Honnappa Nagarahalli, Dodji Seketeli

On Fri, Mar 27, 2020 at 2:18 PM Van Haaren, Harry
<harry.van.haaren@intel.com> wrote:
>
> > -----Original Message-----
> > From: David Marchand <david.marchand@redhat.com>
> > Sent: Friday, March 27, 2020 12:24 PM
> > To: Laatz, Kevin <kevin.laatz@intel.com>
> > Cc: dev <dev@dpdk.org>; Richardson, Bruce <bruce.richardson@intel.com>; Van
> > Haaren, Harry <harry.van.haaren@intel.com>; Neil Horman
> > <nhorman@tuxdriver.com>; Thomas Monjalon <thomas@monjalon.net>; Honnappa
> > Nagarahalli <Honnappa.Nagarahalli@arm.com>; Dodji Seketeli <dodji@redhat.com>
> > Subject: Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
> >
> > On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com> wrote:
> > >
> > > This patch adds CPU flags which will enable the detection of ISA
> > > features available on more recent x86 based CPUs.
> > >
> > > The CPUID leaf information can be found in Section 1.7 of this
> > > document:
> > > https://software.intel.com/sites/default/files/managed/c5/15/architecture-
> > instruction-set-extensions-programming-reference.pdf
> > >
> > > The following CPU flags are added in this patch:
> > >     - AVX-512 doubleword and quadword instructions.
> > >     - AVX-512 integer fused multiply-add instructions.
> > >     - AVX-512 conflict detection instructions.
> > >     - AVX-512 byte and word instructions.
> > >     - AVX-512 vector length instructions.
> > >     - AVX-512 vector bit manipulation instructions.
> > >     - AVX-512 vector bit manipulation 2 instructions.
> > >     - Galois field new instructions.
> > >     - Vector AES instructions.
> > >     - Vector carry-less multiply instructions.
> > >     - AVX-512 vector neural network instructions.
> > >     - AVX-512 for bit algorithm instructions.
> > >     - AVX-512 vector popcount instructions.
> > >     - Cache line demote instructions.
> > >     - Direct store instructions.
> > >     - Direct store 64B instructions.
> > >     - AVX-512 two register intersection instructions.
> > >
> > > Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> > > ---
> > >  lib/librte_eal/common/arch/x86/rte_cpuflags.c  | 18 ++++++++++++++++++
> > >  .../common/include/arch/x86/rte_cpuflags.h     | 18 ++++++++++++++++++
> > >  2 files changed, 36 insertions(+)
> > >
> > > diff --git a/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > > index 6492df556..30439e795 100644
> > > --- a/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > > +++ b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > > @@ -120,6 +120,24 @@ const struct feature_entry rte_cpu_feature_table[] = {
> > >         FEAT_DEF(EM64T, 0x80000001, 0, RTE_REG_EDX, 29)
> > >
> > >         FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)
> > > +
> > > +       FEAT_DEF(AVX512DQ, 0x00000007, 0, RTE_REG_EBX, 17)
> > > +       FEAT_DEF(AVX512IFMA, 0x00000007, 0, RTE_REG_EBX, 21)
> > > +       FEAT_DEF(AVX512CD, 0x00000007, 0, RTE_REG_EBX, 28)
> > > +       FEAT_DEF(AVX512BW, 0x00000007, 0, RTE_REG_EBX, 30)
> > > +       FEAT_DEF(AVX512VL, 0x00000007, 0, RTE_REG_EBX, 31)
> > > +       FEAT_DEF(AVX512VBMI, 0x00000007, 0, RTE_REG_ECX, 1)
> > > +       FEAT_DEF(AVX512VBMI2, 0x00000007, 0, RTE_REG_ECX, 6)
> > > +       FEAT_DEF(GFNI, 0x00000007, 0, RTE_REG_ECX, 8)
> > > +       FEAT_DEF(VAES, 0x00000007, 0, RTE_REG_ECX, 9)
> > > +       FEAT_DEF(VPCLMULQDQ, 0x00000007, 0, RTE_REG_ECX, 10)
> > > +       FEAT_DEF(AVX512VNNI, 0x00000007, 0, RTE_REG_ECX, 11)
> > > +       FEAT_DEF(AVX512BITALG, 0x00000007, 0, RTE_REG_ECX, 12)
> > > +       FEAT_DEF(AVX512VPOPCNTDQ, 0x00000007, 0, RTE_REG_ECX,  14)
> > > +       FEAT_DEF(CLDEMOTE, 0x00000007, 0, RTE_REG_ECX, 25)
> > > +       FEAT_DEF(MOVDIRI, 0x00000007, 0, RTE_REG_ECX, 27)
> > > +       FEAT_DEF(MOVDIR64B, 0x00000007, 0, RTE_REG_ECX, 28)
> > > +       FEAT_DEF(AVX512VP2INTERSECT, 0x00000007, 0, RTE_REG_EDX, 8)
> > >  };
> > >
> > >  int
> > > diff --git a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > > index 25ba47b96..f8f73b19f 100644
> > > --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > > +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > > @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
> > >         /* (EAX 80000007h) EDX features */
> > >         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
> > >
> > > +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and
> > Quadword */
> > > +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused
> > Multiply-Add */
> > > +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict Detection*/
> > > +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
> > > +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
> > > +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit
> > Manipulation */
> > > +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit
> > Manipulation 2 */
> > > +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New
> > Instructions */
> > > +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
> > > +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less Multiply
> > */
> > > +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural
> > Network Instructions */
> > > +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms */
> > > +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount */
> > > +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
> > > +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store Instructions
> > */
> > > +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions
> > 64B */
> > > +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register
> > Intersection */
> > > +
> > >         /* The last item */
> > >         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the
> > last! */
> >
> > This is seen as an ABI break because of the change on _NUMFLAGS:
> > https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351
>
> Correct a publicly exposed enum max value has changed - I don't believe this is an ABI break, but a backward compatible ABI change was expected with this patchset.

A change is that if an application was passing incorrect values to the
functions taking this enum as input, then now it would succeed.
I don't really see the point in doing this :-).

>
> Code compiled against eg 19.11 or 20.02 is expected to continue operating correctly.
> The new flags were only added at the end of the enum, ensuring to not change the meaning of any existing flags which would be compiled-in constants to the application binary.
>
> The actual size of the CPU flags array is a DPDK internal structure (in a .c file), and is hidden from the application, and never allocated by an application - so no possible mismatch in ABI there? Applications compiled against the older ABI will just not know about the newer flags - but suffer no breakage.
>
> @ABI compatibility folks, please review too - but to the best of my understanding this is not an ABI break, but a backwards compatible update of CPU flag lists?
>
> Thanks for flagging the CI results David!

I'd like people to look at this by themselves, not wait for Thomas,
Aaron or me to check.

When a failure is caught by the robot, a mail is sent to the submitter
afaiu (I suppose with Travis instability wrt ARM jobs, the mail might
not have been sent this time).
It is then the responsibility of the submitter to either discuss the
report on the mailing or/and waive it in devtools/libabigail.abignore.

Thanks.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  2020-03-27 14:32  3%         ` Van Haaren, Harry
@ 2020-03-27 14:36  3%           ` Ray Kinsella
  2020-03-27 15:19  3%             ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Ray Kinsella @ 2020-03-27 14:36 UTC (permalink / raw)
  To: Van Haaren, Harry, Thomas Monjalon, Neil Horman, Dodji Seketeli
  Cc: David Marchand, Laatz, Kevin, dev, Richardson, Bruce,
	Honnappa Nagarahalli



On 27/03/2020 14:32, Van Haaren, Harry wrote:
>> -----Original Message-----
>> From: Thomas Monjalon <thomas@monjalon.net>
>> Sent: Friday, March 27, 2020 2:16 PM
>> To: Neil Horman <nhorman@tuxdriver.com>; Dodji Seketeli <dodji@redhat.com>;
>> mdr@ashroe.eu
>> Cc: David Marchand <david.marchand@redhat.com>; Laatz, Kevin
>> <kevin.laatz@intel.com>; dev <dev@dpdk.org>; Richardson, Bruce
>> <bruce.richardson@intel.com>; Van Haaren, Harry <harry.van.haaren@intel.com>;
>> Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>
>> Subject: Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
>>
>> 27/03/2020 14:44, Neil Horman:
>>> On Fri, Mar 27, 2020 at 01:24:12PM +0100, David Marchand wrote:
>>>> On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com>
>> wrote:
>>>>> --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
>>>>> +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
>>>>> @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
>>>>>         /* (EAX 80000007h) EDX features */
>>>>>         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
>>>>>
>>>>> +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and
>> Quadword */
>>>>> +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused
>> Multiply-Add */
>>>>> +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict
>> Detection*/
>>>>> +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
>>>>> +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
>>>>> +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit
>> Manipulation */
>>>>> +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit
>> Manipulation 2 */
>>>>> +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New
>> Instructions */
>>>>> +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
>>>>> +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less
>> Multiply */
>>>>> +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural
>> Network Instructions */
>>>>> +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms
>> */
>>>>> +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount
>> */
>>>>> +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
>>>>> +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store
>> Instructions */
>>>>> +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store
>> Instructions 64B */
>>>>> +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register
>> Intersection */
>>>>> +
>>>>>         /* The last item */
>>>>>         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be
>> the last! */
>>>>
>>>> This is seen as an ABI break because of the change on _NUMFLAGS:
>>>> https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351
>>>>
>>> It shouldn't be, as the only API calls we expose that use rte_cpu_flag_t
>> accept
>>> it as an integer parameter to see if the flag is enabled.  Theres no use of
>> the
>>> enum in a public array or any struct that is sized based on the number of
>> flags,
>>> so you should be good to go
>>
>> Indeed I cannot imagine an ABI incompatibility in this case.
>> The only behaviour change is to accept new (higher) RTE_CPUFLAG values
>> in functions rte_cpu_get_flag_enabled() and rte_cpu_get_flag_name().
>> Is changing the range of valid values an ABI break?
>> Why is it flagged by libabigail?
> 
> If this enum _MAX value was used by the application to allocate an array, that later our DPDK code would write to it could cause out-of-bounds array accesses of the application supplied array. Abigail doesn't know what applications could use the value for, so it flags it.
> 
> IMO Abigail is right to flag it to us - a manual review to understand what that _MAX enum value is used for, and then decide on a case by case basis seems the best way forward to me.
> 
> Thanks Neil/Thomas for reviewing, as reply in this thread, I also believe this is not going to break ABI.
> 
 
+1 to Harrry's comments. 
I can't immediately see how this might break the ABI either. 

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  2020-03-27 14:15  4%       ` Thomas Monjalon
@ 2020-03-27 14:32  3%         ` Van Haaren, Harry
  2020-03-27 14:36  3%           ` Ray Kinsella
  0 siblings, 1 reply; 200+ results
From: Van Haaren, Harry @ 2020-03-27 14:32 UTC (permalink / raw)
  To: Thomas Monjalon, Neil Horman, Dodji Seketeli, mdr
  Cc: David Marchand, Laatz, Kevin, dev, Richardson, Bruce,
	Honnappa Nagarahalli

> -----Original Message-----
> From: Thomas Monjalon <thomas@monjalon.net>
> Sent: Friday, March 27, 2020 2:16 PM
> To: Neil Horman <nhorman@tuxdriver.com>; Dodji Seketeli <dodji@redhat.com>;
> mdr@ashroe.eu
> Cc: David Marchand <david.marchand@redhat.com>; Laatz, Kevin
> <kevin.laatz@intel.com>; dev <dev@dpdk.org>; Richardson, Bruce
> <bruce.richardson@intel.com>; Van Haaren, Harry <harry.van.haaren@intel.com>;
> Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>
> Subject: Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
> 
> 27/03/2020 14:44, Neil Horman:
> > On Fri, Mar 27, 2020 at 01:24:12PM +0100, David Marchand wrote:
> > > On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com>
> wrote:
> > > > --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > > > +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > > > @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
> > > >         /* (EAX 80000007h) EDX features */
> > > >         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
> > > >
> > > > +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and
> Quadword */
> > > > +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused
> Multiply-Add */
> > > > +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict
> Detection*/
> > > > +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
> > > > +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
> > > > +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit
> Manipulation */
> > > > +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit
> Manipulation 2 */
> > > > +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New
> Instructions */
> > > > +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
> > > > +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less
> Multiply */
> > > > +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural
> Network Instructions */
> > > > +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms
> */
> > > > +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount
> */
> > > > +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
> > > > +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store
> Instructions */
> > > > +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store
> Instructions 64B */
> > > > +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register
> Intersection */
> > > > +
> > > >         /* The last item */
> > > >         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be
> the last! */
> > >
> > > This is seen as an ABI break because of the change on _NUMFLAGS:
> > > https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351
> > >
> > It shouldn't be, as the only API calls we expose that use rte_cpu_flag_t
> accept
> > it as an integer parameter to see if the flag is enabled.  Theres no use of
> the
> > enum in a public array or any struct that is sized based on the number of
> flags,
> > so you should be good to go
> 
> Indeed I cannot imagine an ABI incompatibility in this case.
> The only behaviour change is to accept new (higher) RTE_CPUFLAG values
> in functions rte_cpu_get_flag_enabled() and rte_cpu_get_flag_name().
> Is changing the range of valid values an ABI break?
> Why is it flagged by libabigail?

If this enum _MAX value was used by the application to allocate an array, that later our DPDK code would write to it could cause out-of-bounds array accesses of the application supplied array. Abigail doesn't know what applications could use the value for, so it flags it.

IMO Abigail is right to flag it to us - a manual review to understand what that _MAX enum value is used for, and then decide on a case by case basis seems the best way forward to me.

Thanks Neil/Thomas for reviewing, as reply in this thread, I also believe this is not going to break ABI.

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  2020-03-27 13:44  0%     ` Neil Horman
@ 2020-03-27 14:15  4%       ` Thomas Monjalon
  2020-03-27 14:32  3%         ` Van Haaren, Harry
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-03-27 14:15 UTC (permalink / raw)
  To: Neil Horman, Dodji Seketeli, mdr
  Cc: David Marchand, Kevin Laatz, dev, Bruce Richardson,
	Van Haaren Harry, Honnappa Nagarahalli

27/03/2020 14:44, Neil Horman:
> On Fri, Mar 27, 2020 at 01:24:12PM +0100, David Marchand wrote:
> > On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com> wrote:
> > > --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > > +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > > @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
> > >         /* (EAX 80000007h) EDX features */
> > >         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
> > >
> > > +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and Quadword */
> > > +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused Multiply-Add */
> > > +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict Detection*/
> > > +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
> > > +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
> > > +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit Manipulation */
> > > +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit Manipulation 2 */
> > > +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New Instructions */
> > > +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
> > > +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less Multiply */
> > > +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural Network Instructions */
> > > +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms */
> > > +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount */
> > > +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
> > > +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store Instructions */
> > > +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
> > > +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
> > > +
> > >         /* The last item */
> > >         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
> > 
> > This is seen as an ABI break because of the change on _NUMFLAGS:
> > https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351
> > 
> It shouldn't be, as the only API calls we expose that use rte_cpu_flag_t accept
> it as an integer parameter to see if the flag is enabled.  Theres no use of the
> enum in a public array or any struct that is sized based on the number of flags,
> so you should be good to go

Indeed I cannot imagine an ABI incompatibility in this case.
The only behaviour change is to accept new (higher) RTE_CPUFLAG values
in functions rte_cpu_get_flag_enabled() and rte_cpu_get_flag_name().
Is changing the range of valid values an ABI break?
Why is it flagged by libabigail?




^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  2020-03-27 12:24  3%   ` David Marchand
  2020-03-27 13:18  5%     ` Van Haaren, Harry
@ 2020-03-27 13:44  0%     ` Neil Horman
  2020-03-27 14:15  4%       ` Thomas Monjalon
  1 sibling, 1 reply; 200+ results
From: Neil Horman @ 2020-03-27 13:44 UTC (permalink / raw)
  To: David Marchand
  Cc: Kevin Laatz, dev, Bruce Richardson, Van Haaren Harry,
	Thomas Monjalon, Honnappa Nagarahalli, Dodji Seketeli

On Fri, Mar 27, 2020 at 01:24:12PM +0100, David Marchand wrote:
> On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com> wrote:
> >
> > This patch adds CPU flags which will enable the detection of ISA
> > features available on more recent x86 based CPUs.
> >
> > The CPUID leaf information can be found in Section 1.7 of this
> > document:
> > https://software.intel.com/sites/default/files/managed/c5/15/architecture-instruction-set-extensions-programming-reference.pdf
> >
> > The following CPU flags are added in this patch:
> >     - AVX-512 doubleword and quadword instructions.
> >     - AVX-512 integer fused multiply-add instructions.
> >     - AVX-512 conflict detection instructions.
> >     - AVX-512 byte and word instructions.
> >     - AVX-512 vector length instructions.
> >     - AVX-512 vector bit manipulation instructions.
> >     - AVX-512 vector bit manipulation 2 instructions.
> >     - Galois field new instructions.
> >     - Vector AES instructions.
> >     - Vector carry-less multiply instructions.
> >     - AVX-512 vector neural network instructions.
> >     - AVX-512 for bit algorithm instructions.
> >     - AVX-512 vector popcount instructions.
> >     - Cache line demote instructions.
> >     - Direct store instructions.
> >     - Direct store 64B instructions.
> >     - AVX-512 two register intersection instructions.
> >
> > Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> > ---
> >  lib/librte_eal/common/arch/x86/rte_cpuflags.c  | 18 ++++++++++++++++++
> >  .../common/include/arch/x86/rte_cpuflags.h     | 18 ++++++++++++++++++
> >  2 files changed, 36 insertions(+)
> >
> > diff --git a/lib/librte_eal/common/arch/x86/rte_cpuflags.c b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > index 6492df556..30439e795 100644
> > --- a/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > +++ b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > @@ -120,6 +120,24 @@ const struct feature_entry rte_cpu_feature_table[] = {
> >         FEAT_DEF(EM64T, 0x80000001, 0, RTE_REG_EDX, 29)
> >
> >         FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)
> > +
> > +       FEAT_DEF(AVX512DQ, 0x00000007, 0, RTE_REG_EBX, 17)
> > +       FEAT_DEF(AVX512IFMA, 0x00000007, 0, RTE_REG_EBX, 21)
> > +       FEAT_DEF(AVX512CD, 0x00000007, 0, RTE_REG_EBX, 28)
> > +       FEAT_DEF(AVX512BW, 0x00000007, 0, RTE_REG_EBX, 30)
> > +       FEAT_DEF(AVX512VL, 0x00000007, 0, RTE_REG_EBX, 31)
> > +       FEAT_DEF(AVX512VBMI, 0x00000007, 0, RTE_REG_ECX, 1)
> > +       FEAT_DEF(AVX512VBMI2, 0x00000007, 0, RTE_REG_ECX, 6)
> > +       FEAT_DEF(GFNI, 0x00000007, 0, RTE_REG_ECX, 8)
> > +       FEAT_DEF(VAES, 0x00000007, 0, RTE_REG_ECX, 9)
> > +       FEAT_DEF(VPCLMULQDQ, 0x00000007, 0, RTE_REG_ECX, 10)
> > +       FEAT_DEF(AVX512VNNI, 0x00000007, 0, RTE_REG_ECX, 11)
> > +       FEAT_DEF(AVX512BITALG, 0x00000007, 0, RTE_REG_ECX, 12)
> > +       FEAT_DEF(AVX512VPOPCNTDQ, 0x00000007, 0, RTE_REG_ECX,  14)
> > +       FEAT_DEF(CLDEMOTE, 0x00000007, 0, RTE_REG_ECX, 25)
> > +       FEAT_DEF(MOVDIRI, 0x00000007, 0, RTE_REG_ECX, 27)
> > +       FEAT_DEF(MOVDIR64B, 0x00000007, 0, RTE_REG_ECX, 28)
> > +       FEAT_DEF(AVX512VP2INTERSECT, 0x00000007, 0, RTE_REG_EDX, 8)
> >  };
> >
> >  int
> > diff --git a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > index 25ba47b96..f8f73b19f 100644
> > --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
> >         /* (EAX 80000007h) EDX features */
> >         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
> >
> > +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and Quadword */
> > +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused Multiply-Add */
> > +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict Detection*/
> > +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
> > +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
> > +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit Manipulation */
> > +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit Manipulation 2 */
> > +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New Instructions */
> > +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
> > +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less Multiply */
> > +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural Network Instructions */
> > +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms */
> > +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount */
> > +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
> > +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store Instructions */
> > +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
> > +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
> > +
> >         /* The last item */
> >         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
> 
> This is seen as an ABI break because of the change on _NUMFLAGS:
> https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351
> 
It shouldn't be, as the only API calls we expose that use rte_cpu_flag_t accept
it as an integer parameter to see if the flag is enabled.  Theres no use of the
enum in a public array or any struct that is sized based on the number of flags,
so you should be good to go
Neil

> 
> -- 
> David Marchand
> 
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  2020-03-27 12:24  3%   ` David Marchand
@ 2020-03-27 13:18  5%     ` Van Haaren, Harry
  2020-03-27 15:04  0%       ` David Marchand
  2020-03-27 13:44  0%     ` Neil Horman
  1 sibling, 1 reply; 200+ results
From: Van Haaren, Harry @ 2020-03-27 13:18 UTC (permalink / raw)
  To: David Marchand, Laatz, Kevin
  Cc: dev, Richardson, Bruce, Neil Horman, Thomas Monjalon,
	Honnappa Nagarahalli, Dodji Seketeli

> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Friday, March 27, 2020 12:24 PM
> To: Laatz, Kevin <kevin.laatz@intel.com>
> Cc: dev <dev@dpdk.org>; Richardson, Bruce <bruce.richardson@intel.com>; Van
> Haaren, Harry <harry.van.haaren@intel.com>; Neil Horman
> <nhorman@tuxdriver.com>; Thomas Monjalon <thomas@monjalon.net>; Honnappa
> Nagarahalli <Honnappa.Nagarahalli@arm.com>; Dodji Seketeli <dodji@redhat.com>
> Subject: Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
> 
> On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com> wrote:
> >
> > This patch adds CPU flags which will enable the detection of ISA
> > features available on more recent x86 based CPUs.
> >
> > The CPUID leaf information can be found in Section 1.7 of this
> > document:
> > https://software.intel.com/sites/default/files/managed/c5/15/architecture-
> instruction-set-extensions-programming-reference.pdf
> >
> > The following CPU flags are added in this patch:
> >     - AVX-512 doubleword and quadword instructions.
> >     - AVX-512 integer fused multiply-add instructions.
> >     - AVX-512 conflict detection instructions.
> >     - AVX-512 byte and word instructions.
> >     - AVX-512 vector length instructions.
> >     - AVX-512 vector bit manipulation instructions.
> >     - AVX-512 vector bit manipulation 2 instructions.
> >     - Galois field new instructions.
> >     - Vector AES instructions.
> >     - Vector carry-less multiply instructions.
> >     - AVX-512 vector neural network instructions.
> >     - AVX-512 for bit algorithm instructions.
> >     - AVX-512 vector popcount instructions.
> >     - Cache line demote instructions.
> >     - Direct store instructions.
> >     - Direct store 64B instructions.
> >     - AVX-512 two register intersection instructions.
> >
> > Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> > ---
> >  lib/librte_eal/common/arch/x86/rte_cpuflags.c  | 18 ++++++++++++++++++
> >  .../common/include/arch/x86/rte_cpuflags.h     | 18 ++++++++++++++++++
> >  2 files changed, 36 insertions(+)
> >
> > diff --git a/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > index 6492df556..30439e795 100644
> > --- a/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > +++ b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> > @@ -120,6 +120,24 @@ const struct feature_entry rte_cpu_feature_table[] = {
> >         FEAT_DEF(EM64T, 0x80000001, 0, RTE_REG_EDX, 29)
> >
> >         FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)
> > +
> > +       FEAT_DEF(AVX512DQ, 0x00000007, 0, RTE_REG_EBX, 17)
> > +       FEAT_DEF(AVX512IFMA, 0x00000007, 0, RTE_REG_EBX, 21)
> > +       FEAT_DEF(AVX512CD, 0x00000007, 0, RTE_REG_EBX, 28)
> > +       FEAT_DEF(AVX512BW, 0x00000007, 0, RTE_REG_EBX, 30)
> > +       FEAT_DEF(AVX512VL, 0x00000007, 0, RTE_REG_EBX, 31)
> > +       FEAT_DEF(AVX512VBMI, 0x00000007, 0, RTE_REG_ECX, 1)
> > +       FEAT_DEF(AVX512VBMI2, 0x00000007, 0, RTE_REG_ECX, 6)
> > +       FEAT_DEF(GFNI, 0x00000007, 0, RTE_REG_ECX, 8)
> > +       FEAT_DEF(VAES, 0x00000007, 0, RTE_REG_ECX, 9)
> > +       FEAT_DEF(VPCLMULQDQ, 0x00000007, 0, RTE_REG_ECX, 10)
> > +       FEAT_DEF(AVX512VNNI, 0x00000007, 0, RTE_REG_ECX, 11)
> > +       FEAT_DEF(AVX512BITALG, 0x00000007, 0, RTE_REG_ECX, 12)
> > +       FEAT_DEF(AVX512VPOPCNTDQ, 0x00000007, 0, RTE_REG_ECX,  14)
> > +       FEAT_DEF(CLDEMOTE, 0x00000007, 0, RTE_REG_ECX, 25)
> > +       FEAT_DEF(MOVDIRI, 0x00000007, 0, RTE_REG_ECX, 27)
> > +       FEAT_DEF(MOVDIR64B, 0x00000007, 0, RTE_REG_ECX, 28)
> > +       FEAT_DEF(AVX512VP2INTERSECT, 0x00000007, 0, RTE_REG_EDX, 8)
> >  };
> >
> >  int
> > diff --git a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > index 25ba47b96..f8f73b19f 100644
> > --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> > @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
> >         /* (EAX 80000007h) EDX features */
> >         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
> >
> > +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and
> Quadword */
> > +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused
> Multiply-Add */
> > +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict Detection*/
> > +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
> > +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
> > +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit
> Manipulation */
> > +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit
> Manipulation 2 */
> > +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New
> Instructions */
> > +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
> > +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less Multiply
> */
> > +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural
> Network Instructions */
> > +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms */
> > +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount */
> > +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
> > +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store Instructions
> */
> > +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions
> 64B */
> > +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register
> Intersection */
> > +
> >         /* The last item */
> >         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the
> last! */
> 
> This is seen as an ABI break because of the change on _NUMFLAGS:
> https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351

Correct a publicly exposed enum max value has changed - I don't believe this is an ABI break, but a backward compatible ABI change was expected with this patchset.

Code compiled against eg 19.11 or 20.02 is expected to continue operating correctly.
The new flags were only added at the end of the enum, ensuring to not change the meaning of any existing flags which would be compiled-in constants to the application binary.

The actual size of the CPU flags array is a DPDK internal structure (in a .c file), and is hidden from the application, and never allocated by an application - so no possible mismatch in ABI there? Applications compiled against the older ABI will just not know about the newer flags - but suffer no breakage.

@ABI compatibility folks, please review too - but to the best of my understanding this is not an ABI break, but a backwards compatible update of CPU flag lists?

Thanks for flagging the CI results David!

Regards, -Harry

^ permalink raw reply	[relevance 5%]

* Re: [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags
  @ 2020-03-27 12:24  3%   ` David Marchand
  2020-03-27 13:18  5%     ` Van Haaren, Harry
  2020-03-27 13:44  0%     ` Neil Horman
  0 siblings, 2 replies; 200+ results
From: David Marchand @ 2020-03-27 12:24 UTC (permalink / raw)
  To: Kevin Laatz
  Cc: dev, Bruce Richardson, Van Haaren Harry, Neil Horman,
	Thomas Monjalon, Honnappa Nagarahalli, Dodji Seketeli

On Wed, Mar 25, 2020 at 12:11 PM Kevin Laatz <kevin.laatz@intel.com> wrote:
>
> This patch adds CPU flags which will enable the detection of ISA
> features available on more recent x86 based CPUs.
>
> The CPUID leaf information can be found in Section 1.7 of this
> document:
> https://software.intel.com/sites/default/files/managed/c5/15/architecture-instruction-set-extensions-programming-reference.pdf
>
> The following CPU flags are added in this patch:
>     - AVX-512 doubleword and quadword instructions.
>     - AVX-512 integer fused multiply-add instructions.
>     - AVX-512 conflict detection instructions.
>     - AVX-512 byte and word instructions.
>     - AVX-512 vector length instructions.
>     - AVX-512 vector bit manipulation instructions.
>     - AVX-512 vector bit manipulation 2 instructions.
>     - Galois field new instructions.
>     - Vector AES instructions.
>     - Vector carry-less multiply instructions.
>     - AVX-512 vector neural network instructions.
>     - AVX-512 for bit algorithm instructions.
>     - AVX-512 vector popcount instructions.
>     - Cache line demote instructions.
>     - Direct store instructions.
>     - Direct store 64B instructions.
>     - AVX-512 two register intersection instructions.
>
> Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
> ---
>  lib/librte_eal/common/arch/x86/rte_cpuflags.c  | 18 ++++++++++++++++++
>  .../common/include/arch/x86/rte_cpuflags.h     | 18 ++++++++++++++++++
>  2 files changed, 36 insertions(+)
>
> diff --git a/lib/librte_eal/common/arch/x86/rte_cpuflags.c b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> index 6492df556..30439e795 100644
> --- a/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> +++ b/lib/librte_eal/common/arch/x86/rte_cpuflags.c
> @@ -120,6 +120,24 @@ const struct feature_entry rte_cpu_feature_table[] = {
>         FEAT_DEF(EM64T, 0x80000001, 0, RTE_REG_EDX, 29)
>
>         FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)
> +
> +       FEAT_DEF(AVX512DQ, 0x00000007, 0, RTE_REG_EBX, 17)
> +       FEAT_DEF(AVX512IFMA, 0x00000007, 0, RTE_REG_EBX, 21)
> +       FEAT_DEF(AVX512CD, 0x00000007, 0, RTE_REG_EBX, 28)
> +       FEAT_DEF(AVX512BW, 0x00000007, 0, RTE_REG_EBX, 30)
> +       FEAT_DEF(AVX512VL, 0x00000007, 0, RTE_REG_EBX, 31)
> +       FEAT_DEF(AVX512VBMI, 0x00000007, 0, RTE_REG_ECX, 1)
> +       FEAT_DEF(AVX512VBMI2, 0x00000007, 0, RTE_REG_ECX, 6)
> +       FEAT_DEF(GFNI, 0x00000007, 0, RTE_REG_ECX, 8)
> +       FEAT_DEF(VAES, 0x00000007, 0, RTE_REG_ECX, 9)
> +       FEAT_DEF(VPCLMULQDQ, 0x00000007, 0, RTE_REG_ECX, 10)
> +       FEAT_DEF(AVX512VNNI, 0x00000007, 0, RTE_REG_ECX, 11)
> +       FEAT_DEF(AVX512BITALG, 0x00000007, 0, RTE_REG_ECX, 12)
> +       FEAT_DEF(AVX512VPOPCNTDQ, 0x00000007, 0, RTE_REG_ECX,  14)
> +       FEAT_DEF(CLDEMOTE, 0x00000007, 0, RTE_REG_ECX, 25)
> +       FEAT_DEF(MOVDIRI, 0x00000007, 0, RTE_REG_ECX, 27)
> +       FEAT_DEF(MOVDIR64B, 0x00000007, 0, RTE_REG_ECX, 28)
> +       FEAT_DEF(AVX512VP2INTERSECT, 0x00000007, 0, RTE_REG_EDX, 8)
>  };
>
>  int
> diff --git a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> index 25ba47b96..f8f73b19f 100644
> --- a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> +++ b/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
> @@ -113,6 +113,24 @@ enum rte_cpu_flag_t {
>         /* (EAX 80000007h) EDX features */
>         RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
>
> +       RTE_CPUFLAG_AVX512DQ,               /**< AVX512 Doubleword and Quadword */
> +       RTE_CPUFLAG_AVX512IFMA,             /**< AVX512 Integer Fused Multiply-Add */
> +       RTE_CPUFLAG_AVX512CD,               /**< AVX512 Conflict Detection*/
> +       RTE_CPUFLAG_AVX512BW,               /**< AVX512 Byte and Word */
> +       RTE_CPUFLAG_AVX512VL,               /**< AVX512 Vector Length */
> +       RTE_CPUFLAG_AVX512VBMI,             /**< AVX512 Vector Bit Manipulation */
> +       RTE_CPUFLAG_AVX512VBMI2,            /**< AVX512 Vector Bit Manipulation 2 */
> +       RTE_CPUFLAG_GFNI,                   /**< Galois Field New Instructions */
> +       RTE_CPUFLAG_VAES,                   /**< Vector AES */
> +       RTE_CPUFLAG_VPCLMULQDQ,             /**< Vector Carry-less Multiply */
> +       RTE_CPUFLAG_AVX512VNNI,             /**< AVX512 Vector Neural Network Instructions */
> +       RTE_CPUFLAG_AVX512BITALG,           /**< AVX512 Bit Algorithms */
> +       RTE_CPUFLAG_AVX512VPOPCNTDQ,        /**< AVX512 Vector Popcount */
> +       RTE_CPUFLAG_CLDEMOTE,               /**< Cache Line Demote */
> +       RTE_CPUFLAG_MOVDIRI,                /**< Direct Store Instructions */
> +       RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
> +       RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
> +
>         /* The last item */
>         RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */

This is seen as an ABI break because of the change on _NUMFLAGS:
https://travis-ci.com/github/ovsrobot/dpdk/jobs/302524264#L2351


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization
  @ 2020-03-27  2:56  1%   ` Haiyue Wang
  0 siblings, 0 replies; 200+ results
From: Haiyue Wang @ 2020-03-27  2:56 UTC (permalink / raw)
  To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
  Cc: wei.zhao1, Haiyue Wang

Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.

Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
 doc/guides/nics/ice.rst                |  47 +++
 doc/guides/nics/img/ice_dcf.png        | Bin 0 -> 39168 bytes
 doc/guides/rel_notes/release_20_05.rst |   5 +
 drivers/common/Makefile                |   1 +
 drivers/net/ice/Makefile               |   5 +
 drivers/net/ice/ice_dcf.c              | 474 +++++++++++++++++++++++++
 drivers/net/ice/ice_dcf.h              |  52 +++
 drivers/net/ice/ice_dcf_ethdev.c       | 317 +++++++++++++++++
 drivers/net/ice/ice_dcf_ethdev.h       |  24 ++
 drivers/net/ice/meson.build            |   7 +-
 mk/rte.app.mk                          |   1 +
 11 files changed, 931 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 drivers/net/ice/ice_dcf.c
 create mode 100644 drivers/net/ice/ice_dcf.h
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.h

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
 
 The APPs based on DPDK should avoid providing such packets.
 
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+   DCF Communication flow.
+
+#. Create the VFs::
+
+      echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+      ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0,  and run testpmd with 'cap=dcf' devarg::
+
+      testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+      tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+      flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+      dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+      sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+      192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+      iface="enp24s0f0", count=10)
+
 Sample Application Notes
 ------------------------
 
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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

literal 0
HcmV?d00001

diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
 
   * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
 
+* **Updated the Intel ice driver.**
+
+  Updated the Intel ice driver with new features and improvements, including:
+
+  * Added support for DCF (Device Config Function) feature.
 
 Removed Items
 -------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
 endif
 
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifneq (,$(findstring y,$(IAVF-y)))
 DIRS-y += iavf
 endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
 LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
 
 EXPORT_MAP := rte_pmd_ice_version.map
 
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
 
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
 
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN     32
+#define ICE_DCF_AQ_BUF_SZ  4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME  2   /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ	\
+	(sizeof(struct virtchnl_vf_resource) +	\
+		IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *req_msg, uint16_t req_msglen)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+				      req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+			    uint16_t *rsp_msglen)
+{
+	struct iavf_arq_event_info event;
+	enum virtchnl_ops v_op;
+	int i = 0;
+	int err;
+
+	event.buf_len = rsp_buflen;
+	event.msg_buf = rsp_msgbuf;
+
+	do {
+		err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+		if (err != IAVF_SUCCESS)
+			goto again;
+
+		v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+		if (v_op != op)
+			goto again;
+
+		if (rsp_msglen != NULL)
+			*rsp_msglen = event.msg_len;
+		return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	cmd->v_ret = IAVF_ERR_NOT_READY;
+	cmd->rsp_msglen = 0;
+	cmd->pending = 1;
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf,
+				      cmd->v_op, IAVF_SUCCESS,
+				      cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+	struct dcf_virtchnl_cmd *cmd;
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+	uint16_t aq_op;
+
+	aq_op = rte_le_to_cpu_16(info->desc.opcode);
+	if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+		PMD_DRV_LOG(ERR,
+			    "Request %u is not supported yet", aq_op);
+		return;
+	}
+
+	v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+	if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+		return;
+
+	v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+		if (cmd->v_op == v_op && cmd->pending) {
+			cmd->v_ret = v_ret;
+			cmd->rsp_msglen = RTE_MIN(info->msg_len,
+						  cmd->rsp_buflen);
+			if (likely(cmd->rsp_msglen != 0))
+				rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+					   cmd->rsp_msglen);
+
+			/* prevent compiler reordering */
+			rte_compiler_barrier();
+			cmd->pending = 0;
+			break;
+		}
+	}
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+	struct iavf_arq_event_info info;
+	uint16_t pending = 1;
+	int ret;
+
+	info.buf_len = ICE_DCF_AQ_BUF_SZ;
+	info.msg_buf = hw->arq_buf;
+
+	while (pending) {
+		ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+		if (ret != IAVF_SUCCESS)
+			break;
+
+		ice_dcf_aq_cmd_handle(hw, &info);
+	}
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START	1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START	1
+	struct virtchnl_version_info version, *pver;
+	int err;
+
+	version.major = VIRTCHNL_VERSION_MAJOR;
+	version.minor = VIRTCHNL_VERSION_MINOR;
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)&version, sizeof(version));
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+		return err;
+	}
+
+	pver = &hw->virtchnl_version;
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)pver, sizeof(*pver), NULL);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG,
+		     "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+	if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+	    (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+	     pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+		PMD_INIT_LOG(ERR,
+			     "VIRTCHNL API version should not be lower than (%u.%u)",
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+		return -1;
+	} else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+		   (pver->major == VIRTCHNL_VERSION_MAJOR &&
+		    pver->minor > VIRTCHNL_VERSION_MINOR)) {
+		PMD_INIT_LOG(ERR,
+			     "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+			     pver->major, pver->minor,
+			     VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+	return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+	uint32_t caps;
+	int err, i;
+
+	caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+	       VF_BASE_MODE_OFFLOADS;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)&caps, sizeof(caps));
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)hw->vf_res,
+					  ICE_DCF_VF_RES_BUF_SZ, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+		return -1;
+	}
+
+	iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+	hw->vsi_res = NULL;
+	for (i = 0; i < hw->vf_res->num_vsis; i++) {
+		if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+			hw->vsi_res = &hw->vf_res->vsi_res[i];
+	}
+
+	if (!hw->vsi_res) {
+		PMD_DRV_LOG(ERR, "no LAN VSI found");
+		return -1;
+	}
+
+	hw->vsi_id = hw->vsi_res->vsi_id;
+	PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+	return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT       50
+	struct iavf_hw *avf = &hw->avf;
+	int i, reset;
+
+	for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+		reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+					IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+		reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+		if (reset == VIRTCHNL_VFR_VFACTIVE ||
+		    reset == VIRTCHNL_VFR_COMPLETED)
+			break;
+
+		rte_delay_ms(20);
+	}
+
+	if (i >= ICE_DCF_RESET_WAIT_CNT)
+		return -1;
+
+	return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+	struct ice_dcf_hw *hw = param;
+
+	ice_dcf_disable_irq0(hw);
+
+	ice_dcf_handle_virtchnl_msg(hw);
+
+	ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+			     struct dcf_virtchnl_cmd *cmd)
+{
+	int i = 0;
+	int err;
+
+	if ((cmd->req_msg && !cmd->req_msglen) ||
+	    (!cmd->req_msg && cmd->req_msglen) ||
+	    (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+	    (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+		return -EINVAL;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_vc_cmd_set(hw, cmd);
+
+	err = ice_dcf_vc_cmd_send(hw, cmd);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+		goto ret;
+	}
+
+	do {
+		if (!cmd->pending)
+			break;
+
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	if (cmd->v_ret != IAVF_SUCCESS) {
+		err = -1;
+		PMD_DRV_LOG(ERR,
+			    "No response (%d times) or return failure (%d) for cmd %d",
+			    i, cmd->v_ret, cmd->v_op);
+	}
+
+ret:
+	ice_dcf_aq_cmd_clear(hw, cmd);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+	return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	int ret;
+
+	hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+	hw->avf.back = hw;
+
+	hw->avf.bus.bus_id = pci_dev->addr.bus;
+	hw->avf.bus.device = pci_dev->addr.devid;
+	hw->avf.bus.func = pci_dev->addr.function;
+
+	hw->avf.device_id = pci_dev->id.device_id;
+	hw->avf.vendor_id = pci_dev->id.vendor_id;
+	hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+	hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+	hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+	rte_spinlock_init(&hw->vc_cmd_send_lock);
+	rte_spinlock_init(&hw->vc_cmd_queue_lock);
+	TAILQ_INIT(&hw->vc_cmd_queue);
+
+	hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+	if (hw->arq_buf == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+		goto err;
+	}
+
+	ret = iavf_set_mac_type(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+		goto err;
+	}
+
+	ret = ice_dcf_check_reset_done(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "VF is still resetting");
+		goto err;
+	}
+
+	ret = iavf_init_adminq(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+		goto err;
+	}
+
+	if (ice_dcf_init_check_api_version(hw)) {
+		PMD_INIT_LOG(ERR, "check_api version failed");
+		goto err_api;
+	}
+
+	hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+	if (hw->vf_res == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+		goto err_api;
+	}
+
+	if (ice_dcf_get_vf_resource(hw)) {
+		PMD_INIT_LOG(ERR, "Failed to get VF resource");
+		goto err_alloc;
+	}
+
+	rte_intr_callback_register(&pci_dev->intr_handle,
+				   ice_dcf_dev_interrupt_handler, hw);
+	rte_intr_enable(&pci_dev->intr_handle);
+	ice_dcf_enable_irq0(hw);
+
+	return 0;
+
+err_alloc:
+	rte_free(hw->vf_res);
+err_api:
+	iavf_shutdown_adminq(&hw->avf);
+err:
+	rte_free(hw->arq_buf);
+
+	return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+	ice_dcf_disable_irq0(hw);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     ice_dcf_dev_interrupt_handler, hw);
+
+	iavf_shutdown_adminq(&hw->avf);
+
+	rte_free(hw->arq_buf);
+	rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+	TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+
+	uint16_t req_msglen;
+	uint8_t *req_msg;
+
+	uint16_t rsp_msglen;
+	uint16_t rsp_buflen;
+	uint8_t *rsp_msgbuf;
+
+	volatile int pending;
+};
+
+struct ice_dcf_hw {
+	struct iavf_hw avf;
+
+	rte_spinlock_t vc_cmd_send_lock;
+	rte_spinlock_t vc_cmd_queue_lock;
+	TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+	uint8_t *arq_buf;
+
+	struct virtchnl_version_info virtchnl_version;
+	struct virtchnl_vf_resource *vf_res; /* VF resource */
+	struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+				 struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+		     struct rte_eth_dev_info *dev_info)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+	dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+	return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+		  __rte_unused struct rte_eth_stats *igb_stats)
+{
+	return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+			enum rte_filter_type filter_type,
+			__rte_unused enum rte_filter_op filter_op,
+			__rte_unused void *arg)
+{
+	int ret = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	switch (filter_type) {
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+			    filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return;
+
+	dev->dev_ops = NULL;
+	dev->rx_pkt_burst = NULL;
+	dev->tx_pkt_burst = NULL;
+	dev->data->mac_addrs = NULL;
+
+	ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+		    __rte_unused int wait_to_complete)
+{
+	return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t rx_queue_id,
+		       __rte_unused uint16_t nb_rx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_rxconf *rx_conf,
+		       __rte_unused struct rte_mempool *mb_pool)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+	return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t tx_queue_id,
+		       __rte_unused uint16_t nb_tx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+	return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+	.dev_start               = ice_dcf_dev_start,
+	.dev_stop                = ice_dcf_dev_stop,
+	.dev_close               = ice_dcf_dev_close,
+	.dev_configure           = ice_dcf_dev_configure,
+	.dev_infos_get           = ice_dcf_dev_info_get,
+	.rx_queue_setup          = ice_dcf_rx_queue_setup,
+	.tx_queue_setup          = ice_dcf_tx_queue_setup,
+	.rx_queue_release        = ice_dcf_queue_release,
+	.tx_queue_release        = ice_dcf_queue_release,
+	.link_update             = ice_dcf_link_update,
+	.stats_get               = ice_dcf_stats_get,
+	.stats_reset             = ice_dcf_stats_reset,
+	.promiscuous_enable      = ice_dcf_dev_promiscuous_enable,
+	.promiscuous_disable     = ice_dcf_dev_promiscuous_disable,
+	.allmulticast_enable     = ice_dcf_dev_allmulticast_enable,
+	.allmulticast_disable    = ice_dcf_dev_allmulticast_disable,
+	.filter_ctrl             = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+	eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+	eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+	eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+	if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+		PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+		return -1;
+	}
+
+	rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+	eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+	return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+	ice_dcf_dev_close(eth_dev);
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+			  const char *value, __rte_unused void *opaque)
+{
+	if (strcmp(value, "dcf"))
+		return -1;
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	const char *key = "cap";
+	int ret = 0;
+
+	if (devargs == NULL)
+		return 0;
+
+	kvlist = rte_kvargs_parse(devargs->args, NULL);
+	if (kvlist == NULL)
+		return 0;
+
+	if (!rte_kvargs_count(kvlist, key))
+		goto exit;
+
+	/* dcf capability selected when there's a key-value pair: cap=dcf */
+	if (rte_kvargs_process(kvlist, key,
+			       ice_dcf_cap_check_handler, NULL) < 0)
+		goto exit;
+
+	ret = 1;
+
+exit:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+			     struct rte_pci_device *pci_dev)
+{
+	if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+		return 1;
+
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+					     sizeof(struct ice_dcf_adapter),
+					     ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+	{ RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+	.id_table = pci_id_ice_dcf_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+	.probe = eth_ice_dcf_pci_probe,
+	.remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS  1
+
+struct ice_dcf_queue {
+	uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+	struct ice_dcf_hw real_hw;
+	struct rte_ether_addr mac_addr;
+	struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+	struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
 	'ice_hash.c'
 	)
 
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
 
 if arch_subdir == 'x86'
 	sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
 	endif
 endif
 
+sources += files('ice_dcf.c',
+		 'ice_dcf_ethdev.c')
+
 install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD)       += -lrte_pmd_iavf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD)        += -lrte_pmd_ice
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifeq ($(findstring y,$(IAVF-y)),y)
 _LDLIBS-y += -lrte_common_iavf
 endif
-- 
2.26.0


^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v2 6/8] eal: move common header files
  @ 2020-03-27  1:15  3%   ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-03-27  1:15 UTC (permalink / raw)
  To: dev
  Cc: david.marchand, Neil Horman, John McNamara, Marko Kovacevic,
	Hemant Agrawal, Sachin Saxena, Matan Azrad, Shahaf Shuler,
	Viacheslav Ovsiienko, Gagandeep Singh, Akhil Goyal, Nipun Gupta,
	Ferruh Yigit, Cristian Dumitrescu, Harry van Haaren,
	Bruce Richardson, Phil Yang, Joyce Kong, Anatoly Burakov,
	Mattias Rönnblom, Olivier Matz

The EAL API (with doxygen documentation) is moved from
common/include/ to include/, which makes more clear that
it is the global API for all environments and architectures.

Note that the arch-specific and OS-specific include files are not
in this global include directory, but include/generic/ should
cover the doxygen documentation for them.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 MAINTAINERS                                   | 26 ++++----
 buildtools/pmdinfogen/meson.build             |  2 +-
 doc/api/doxy-api.conf.in                      |  4 +-
 doc/guides/rel_notes/known_issues.rst         |  2 +-
 drivers/bus/dpaa/Makefile                     |  2 +-
 drivers/common/mlx5/meson.build               |  2 +-
 drivers/crypto/caam_jr/Makefile               |  2 +-
 drivers/crypto/dpaa_sec/Makefile              |  2 +-
 drivers/event/dpaa/Makefile                   |  2 +-
 drivers/net/dpaa/Makefile                     |  2 +-
 kernel/linux/igb_uio/meson.build              |  2 +-
 kernel/linux/kni/meson.build                  |  2 +-
 lib/librte_cfgfile/Makefile                   |  2 +-
 lib/librte_eal/Makefile                       |  6 +-
 lib/librte_eal/common/Makefile                | 38 -----------
 lib/librte_eal/common/meson.build             | 65 ++-----------------
 lib/librte_eal/common/rte_service.c           |  2 +-
 lib/librte_eal/freebsd/eal/Makefile           |  2 +-
 lib/librte_eal/include/Makefile               | 19 ++++++
 .../{common => }/include/generic/rte_atomic.h |  0
 .../include/generic/rte_byteorder.h           |  0
 .../include/generic/rte_cpuflags.h            |  0
 .../{common => }/include/generic/rte_cycles.h |  0
 .../{common => }/include/generic/rte_io.h     |  0
 .../include/generic/rte_mcslock.h             |  0
 .../{common => }/include/generic/rte_memcpy.h |  0
 .../{common => }/include/generic/rte_pause.h  |  0
 .../include/generic/rte_prefetch.h            |  0
 .../{common => }/include/generic/rte_rwlock.h |  0
 .../include/generic/rte_spinlock.h            |  0
 .../include/generic/rte_ticketlock.h          |  0
 .../{common => }/include/generic/rte_vect.h   |  0
 lib/librte_eal/include/meson.build            | 64 ++++++++++++++++++
 .../{common => }/include/rte_alarm.h          |  0
 .../{common => }/include/rte_bitmap.h         |  0
 .../include/rte_branch_prediction.h           |  0
 lib/librte_eal/{common => }/include/rte_bus.h |  0
 .../{common => }/include/rte_class.h          |  0
 .../{common => }/include/rte_common.h         |  0
 .../{common => }/include/rte_compat.h         |  0
 .../{common => }/include/rte_debug.h          |  0
 lib/librte_eal/{common => }/include/rte_dev.h |  0
 .../{common => }/include/rte_devargs.h        |  0
 lib/librte_eal/{common => }/include/rte_eal.h |  0
 .../{common => }/include/rte_eal_interrupts.h |  0
 .../{common => }/include/rte_eal_memconfig.h  |  0
 .../{common => }/include/rte_errno.h          |  0
 .../{common => }/include/rte_fbarray.h        |  0
 .../include/rte_function_versioning.h         |  0
 .../{common => }/include/rte_hexdump.h        |  0
 .../{common => }/include/rte_hypervisor.h     |  0
 .../{common => }/include/rte_interrupts.h     |  0
 .../{common => }/include/rte_keepalive.h      |  0
 .../{common => }/include/rte_launch.h         |  0
 .../{common => }/include/rte_lcore.h          |  0
 lib/librte_eal/{common => }/include/rte_log.h |  0
 .../{common => }/include/rte_malloc.h         |  0
 .../{common => }/include/rte_memory.h         |  0
 .../{common => }/include/rte_memzone.h        |  0
 .../{common => }/include/rte_option.h         |  0
 .../include/rte_pci_dev_feature_defs.h        |  0
 .../include/rte_pci_dev_features.h            |  0
 .../{common => }/include/rte_per_lcore.h      |  0
 .../{common => }/include/rte_random.h         |  0
 .../{common => }/include/rte_reciprocal.h     |  0
 .../{common => }/include/rte_service.h        |  0
 .../include/rte_service_component.h           |  0
 .../{common => }/include/rte_string_fns.h     |  0
 .../{common => }/include/rte_tailq.h          |  0
 .../{common => }/include/rte_test.h           |  0
 .../{common => }/include/rte_time.h           |  0
 .../{common => }/include/rte_uuid.h           |  0
 .../{common => }/include/rte_version.h        |  0
 .../{common => }/include/rte_vfio.h           |  0
 lib/librte_eal/linux/eal/Makefile             |  2 +-
 lib/librte_eal/meson.build                    |  4 +-
 lib/librte_kvargs/Makefile                    |  2 +-
 meson.build                                   |  2 +-
 78 files changed, 124 insertions(+), 134 deletions(-)
 delete mode 100644 lib/librte_eal/common/Makefile
 create mode 100644 lib/librte_eal/include/Makefile
 rename lib/librte_eal/{common => }/include/generic/rte_atomic.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_byteorder.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_cpuflags.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_cycles.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_io.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_mcslock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_memcpy.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_pause.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_prefetch.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_rwlock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_spinlock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_ticketlock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_vect.h (100%)
 create mode 100644 lib/librte_eal/include/meson.build
 rename lib/librte_eal/{common => }/include/rte_alarm.h (100%)
 rename lib/librte_eal/{common => }/include/rte_bitmap.h (100%)
 rename lib/librte_eal/{common => }/include/rte_branch_prediction.h (100%)
 rename lib/librte_eal/{common => }/include/rte_bus.h (100%)
 rename lib/librte_eal/{common => }/include/rte_class.h (100%)
 rename lib/librte_eal/{common => }/include/rte_common.h (100%)
 rename lib/librte_eal/{common => }/include/rte_compat.h (100%)
 rename lib/librte_eal/{common => }/include/rte_debug.h (100%)
 rename lib/librte_eal/{common => }/include/rte_dev.h (100%)
 rename lib/librte_eal/{common => }/include/rte_devargs.h (100%)
 rename lib/librte_eal/{common => }/include/rte_eal.h (100%)
 rename lib/librte_eal/{common => }/include/rte_eal_interrupts.h (100%)
 rename lib/librte_eal/{common => }/include/rte_eal_memconfig.h (100%)
 rename lib/librte_eal/{common => }/include/rte_errno.h (100%)
 rename lib/librte_eal/{common => }/include/rte_fbarray.h (100%)
 rename lib/librte_eal/{common => }/include/rte_function_versioning.h (100%)
 rename lib/librte_eal/{common => }/include/rte_hexdump.h (100%)
 rename lib/librte_eal/{common => }/include/rte_hypervisor.h (100%)
 rename lib/librte_eal/{common => }/include/rte_interrupts.h (100%)
 rename lib/librte_eal/{common => }/include/rte_keepalive.h (100%)
 rename lib/librte_eal/{common => }/include/rte_launch.h (100%)
 rename lib/librte_eal/{common => }/include/rte_lcore.h (100%)
 rename lib/librte_eal/{common => }/include/rte_log.h (100%)
 rename lib/librte_eal/{common => }/include/rte_malloc.h (100%)
 rename lib/librte_eal/{common => }/include/rte_memory.h (100%)
 rename lib/librte_eal/{common => }/include/rte_memzone.h (100%)
 rename lib/librte_eal/{common => }/include/rte_option.h (100%)
 rename lib/librte_eal/{common => }/include/rte_pci_dev_feature_defs.h (100%)
 rename lib/librte_eal/{common => }/include/rte_pci_dev_features.h (100%)
 rename lib/librte_eal/{common => }/include/rte_per_lcore.h (100%)
 rename lib/librte_eal/{common => }/include/rte_random.h (100%)
 rename lib/librte_eal/{common => }/include/rte_reciprocal.h (100%)
 rename lib/librte_eal/{common => }/include/rte_service.h (100%)
 rename lib/librte_eal/{common => }/include/rte_service_component.h (100%)
 rename lib/librte_eal/{common => }/include/rte_string_fns.h (100%)
 rename lib/librte_eal/{common => }/include/rte_tailq.h (100%)
 rename lib/librte_eal/{common => }/include/rte_test.h (100%)
 rename lib/librte_eal/{common => }/include/rte_time.h (100%)
 rename lib/librte_eal/{common => }/include/rte_uuid.h (100%)
 rename lib/librte_eal/{common => }/include/rte_version.h (100%)
 rename lib/librte_eal/{common => }/include/rte_vfio.h (100%)

diff --git a/MAINTAINERS b/MAINTAINERS
index 89aff59ccf..3e842625f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -142,8 +142,8 @@ F: .ci/
 
 ABI versioning
 M: Neil Horman <nhorman@tuxdriver.com>
-F: lib/librte_eal/common/include/rte_compat.h
-F: lib/librte_eal/common/include/rte_function_versioning.h
+F: lib/librte_eal/include/rte_compat.h
+F: lib/librte_eal/include/rte_function_versioning.h
 F: doc/guides/rel_notes/deprecation.rst
 F: devtools/check-abi.sh
 F: devtools/check-abi-version.sh
@@ -169,7 +169,7 @@ T: git://dpdk.org/dpdk
 
 EAL API and common code
 F: lib/librte_eal/common/
-F: lib/librte_eal/common/include/
+F: lib/librte_eal/include/
 F: lib/librte_eal/rte_eal_version.map
 F: doc/guides/prog_guide/env_abstraction_layer.rst
 F: app/test/test_alarm.c
@@ -196,9 +196,9 @@ F: app/test/test_version.c
 
 Memory Allocation
 M: Anatoly Burakov <anatoly.burakov@intel.com>
-F: lib/librte_eal/common/include/rte_fbarray.h
-F: lib/librte_eal/common/include/rte_mem*
-F: lib/librte_eal/common/include/rte_malloc.h
+F: lib/librte_eal/include/rte_fbarray.h
+F: lib/librte_eal/include/rte_mem*
+F: lib/librte_eal/include/rte_malloc.h
 F: lib/librte_eal/common/*malloc*
 F: lib/librte_eal/common/eal_common_fbarray.c
 F: lib/librte_eal/common/eal_common_mem*
@@ -214,7 +214,7 @@ F: app/test/test_memory.c
 F: app/test/test_memzone.c
 
 Keep alive
-F: lib/librte_eal/common/include/rte_keepalive.h
+F: lib/librte_eal/include/rte_keepalive.h
 F: lib/librte_eal/common/rte_keepalive.c
 F: examples/l2fwd-keepalive/
 F: doc/guides/sample_app_ug/keep_alive.rst
@@ -230,30 +230,30 @@ F: doc/guides/sample_app_ug/multi_process.rst
 
 Service Cores
 M: Harry van Haaren <harry.van.haaren@intel.com>
-F: lib/librte_eal/common/include/rte_service.h
-F: lib/librte_eal/common/include/rte_service_component.h
+F: lib/librte_eal/include/rte_service.h
+F: lib/librte_eal/include/rte_service_component.h
 F: lib/librte_eal/common/rte_service.c
 F: doc/guides/prog_guide/service_cores.rst
 F: app/test/test_service_cores.c
 
 Bitmap
 M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
-F: lib/librte_eal/common/include/rte_bitmap.h
+F: lib/librte_eal/include/rte_bitmap.h
 F: app/test/test_bitmap.c
 
 MCSlock - EXPERIMENTAL
 M: Phil Yang <phil.yang@arm.com>
-F: lib/librte_eal/common/include/generic/rte_mcslock.h
+F: lib/librte_eal/include/generic/rte_mcslock.h
 F: app/test/test_mcslock.c
 
 Ticketlock
 M: Joyce Kong <joyce.kong@arm.com>
-F: lib/librte_eal/common/include/generic/rte_ticketlock.h
+F: lib/librte_eal/include/generic/rte_ticketlock.h
 F: app/test/test_ticketlock.c
 
 Pseudo-random Number Generation
 M: Mattias Rönnblom <mattias.ronnblom@ericsson.com>
-F: lib/librte_eal/common/include/rte_random.h
+F: lib/librte_eal/include/rte_random.h
 F: lib/librte_eal/common/rte_random.c
 F: app/test/test_rand_perf.c
 
diff --git a/buildtools/pmdinfogen/meson.build b/buildtools/pmdinfogen/meson.build
index 899ba112cd..7da415b3b7 100644
--- a/buildtools/pmdinfogen/meson.build
+++ b/buildtools/pmdinfogen/meson.build
@@ -6,7 +6,7 @@ if host_machine.system() == 'windows'
 endif
 
 pmdinfogen_inc = [global_inc]
-pmdinfogen_inc += include_directories('../../lib/librte_eal/common/include')
+pmdinfogen_inc += include_directories('../../lib/librte_eal/include')
 pmdinfogen_inc += include_directories('../../lib/librte_pci')
 pmdinfogen = executable('pmdinfogen',
 	'pmdinfogen.c',
diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in
index 1c4392eecc..65e8146bef 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -17,8 +17,8 @@ INPUT                   = @TOPDIR@/doc/api/doxy-api-index.md \
                           @TOPDIR@/drivers/net/softnic \
                           @TOPDIR@/drivers/raw/dpaa2_cmdif \
                           @TOPDIR@/drivers/raw/dpaa2_qdma \
-                          @TOPDIR@/lib/librte_eal/common/include \
-                          @TOPDIR@/lib/librte_eal/common/include/generic \
+                          @TOPDIR@/lib/librte_eal/include \
+                          @TOPDIR@/lib/librte_eal/include/generic \
                           @TOPDIR@/lib/librte_acl \
                           @TOPDIR@/lib/librte_bbdev \
                           @TOPDIR@/lib/librte_bitratestats \
diff --git a/doc/guides/rel_notes/known_issues.rst b/doc/guides/rel_notes/known_issues.rst
index 68c3d22bea..de0782136d 100644
--- a/doc/guides/rel_notes/known_issues.rst
+++ b/doc/guides/rel_notes/known_issues.rst
@@ -127,7 +127,7 @@ HPET timers do not work on the Osage customer reference platform
    work correctly, provided the BIOS supports HPET.
 
 **Driver/Module**:
-   ``lib/librte_eal/common/include/rte_cycles.h``
+   ``lib/librte_eal/include/rte_cycles.h``
 
 
 Not all variants of supported NIC types have been used in testing
diff --git a/drivers/bus/dpaa/Makefile b/drivers/bus/dpaa/Makefile
index cd1093f744..9e1a31bb75 100644
--- a/drivers/bus/dpaa/Makefile
+++ b/drivers/bus/dpaa/Makefile
@@ -18,7 +18,7 @@ CFLAGS += -I$(RTE_BUS_DPAA)/
 CFLAGS += -I$(RTE_BUS_DPAA)/include
 CFLAGS += -I$(RTE_BUS_DPAA)/base/qbman
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 # versioning export map
 EXPORT_MAP := rte_bus_dpaa_version.map
diff --git a/drivers/common/mlx5/meson.build b/drivers/common/mlx5/meson.build
index 141739fd6f..f671710714 100644
--- a/drivers/common/mlx5/meson.build
+++ b/drivers/common/mlx5/meson.build
@@ -203,7 +203,7 @@ if dlopen_ibverbs
 	dlopen_install_dir = [ eal_pmd_path + '-glue' ]
 	dlopen_includes = [global_inc]
 	dlopen_includes += include_directories(
-		'../../../lib/librte_eal/common/include/generic',
+		'../../../lib/librte_eal/include/generic',
 	)
 	shared_lib = shared_library(
 		dlopen_lib_name,
diff --git a/drivers/crypto/caam_jr/Makefile b/drivers/crypto/caam_jr/Makefile
index 1b1f25a2a2..db17294395 100644
--- a/drivers/crypto/caam_jr/Makefile
+++ b/drivers/crypto/caam_jr/Makefile
@@ -20,7 +20,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/include
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax/caamflib/
 CFLAGS += -I$(RTE_SDK)/drivers/crypto/caam_jr
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 # versioning export map
 EXPORT_MAP := rte_pmd_caam_jr_version.map
diff --git a/drivers/crypto/dpaa_sec/Makefile b/drivers/crypto/dpaa_sec/Makefile
index fbfd775855..13a5ff20cf 100644
--- a/drivers/crypto/dpaa_sec/Makefile
+++ b/drivers/crypto/dpaa_sec/Makefile
@@ -20,7 +20,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/base/qbman
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
 CFLAGS += -I$(RTE_SDK)/drivers/crypto/dpaa_sec/
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax/caamflib/
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_cryptodev
 
diff --git a/drivers/event/dpaa/Makefile b/drivers/event/dpaa/Makefile
index 2f53efdf9e..15ffc157f8 100644
--- a/drivers/event/dpaa/Makefile
+++ b/drivers/event/dpaa/Makefile
@@ -20,7 +20,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa
 CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/include/
 CFLAGS += -I$(RTE_SDK)/drivers/mempool/dpaa
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 LDLIBS += -lrte_pmd_dpaa_sec
 CFLAGS += -I$(RTE_SDK)/drivers/crypto/dpaa_sec
diff --git a/drivers/net/dpaa/Makefile b/drivers/net/dpaa/Makefile
index 8e049b2a0b..f63c9bf540 100644
--- a/drivers/net/dpaa/Makefile
+++ b/drivers/net/dpaa/Makefile
@@ -21,7 +21,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/base/qbman
 CFLAGS += -I$(RTE_SDK)/drivers/mempool/dpaa
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
 CFLAGS += -I$(RTE_SDK)/drivers/event/dpaa
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 EXPORT_MAP := rte_pmd_dpaa_version.map
 
diff --git a/kernel/linux/igb_uio/meson.build b/kernel/linux/igb_uio/meson.build
index fac404f078..80540aecee 100644
--- a/kernel/linux/igb_uio/meson.build
+++ b/kernel/linux/igb_uio/meson.build
@@ -12,7 +12,7 @@ custom_target('igb_uio',
 		'M=' + meson.current_build_dir(),
 		'src=' + meson.current_source_dir(),
 		'EXTRA_CFLAGS=-I' + meson.current_source_dir() +
-			'/../../../lib/librte_eal/common/include',
+			'/../../../lib/librte_eal/include',
 		'modules'],
 	depends: mkfile,
 	install: true,
diff --git a/kernel/linux/kni/meson.build b/kernel/linux/kni/meson.build
index f93e97fa09..706bea5b7f 100644
--- a/kernel/linux/kni/meson.build
+++ b/kernel/linux/kni/meson.build
@@ -17,7 +17,7 @@ custom_target('rte_kni',
 		'M=' + meson.current_build_dir(),
 		'src=' + meson.current_source_dir(),
 		'MODULE_CFLAGS=-include ' + meson.source_root() + '/config/rte_config.h' +
-		' -I' + meson.source_root() + '/lib/librte_eal/common/include' +
+		' -I' + meson.source_root() + '/lib/librte_eal/include' +
 		' -I' + meson.source_root() + '/lib/librte_eal/linux/eal/include' +
 		' -I' + meson.build_root() +
 		' -I' + meson.current_source_dir(),
diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile
index d3b08420ff..7c10a4e56c 100644
--- a/lib/librte_cfgfile/Makefile
+++ b/lib/librte_cfgfile/Makefile
@@ -10,7 +10,7 @@ LIB = librte_cfgfile.a
 
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-CFLAGS += -I$(SRCDIR)/../librte_eal/common/include
+CFLAGS += -I$(SRCDIR)/../librte_eal/include
 LDLIBS += -lrte_eal
 
 EXPORT_MAP := rte_cfgfile_version.map
diff --git a/lib/librte_eal/Makefile b/lib/librte_eal/Makefile
index 9c383d42bd..ff74935932 100644
--- a/lib/librte_eal/Makefile
+++ b/lib/librte_eal/Makefile
@@ -3,10 +3,10 @@
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-DIRS-y += common
+DIRS-y += include
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += linux/eal
-DEPDIRS-linux := common
+DEPDIRS-linux := include
 DIRS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += freebsd/eal
-DEPDIRS-freebsd := common
+DEPDIRS-freebsd := include
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
deleted file mode 100644
index 6c52f50106..0000000000
--- a/lib/librte_eal/common/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-INC := rte_branch_prediction.h rte_common.h rte_compat.h
-INC += rte_function_versioning.h
-INC += rte_debug.h rte_eal.h rte_eal_interrupts.h
-INC += rte_errno.h rte_launch.h rte_lcore.h
-INC += rte_log.h rte_memory.h rte_memzone.h
-INC += rte_per_lcore.h rte_random.h
-INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
-INC += rte_eal_memconfig.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
-INC += rte_option.h
-INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
-INC += rte_malloc.h rte_keepalive.h rte_time.h
-INC += rte_service.h rte_service_component.h
-INC += rte_bitmap.h rte_vfio.h rte_hypervisor.h rte_test.h
-INC += rte_reciprocal.h rte_fbarray.h rte_uuid.h
-
-GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h
-GENERIC_INC += rte_memcpy.h rte_cpuflags.h
-GENERIC_INC += rte_mcslock.h rte_spinlock.h rte_rwlock.h rte_ticketlock.h
-GENERIC_INC += rte_vect.h rte_pause.h rte_io.h
-
-# defined in mk/arch/$(RTE_ARCH)/rte.vars.mk
-ARCH_DIR ?= $(RTE_ARCH)
-ARCH_INC := $(sort $(notdir $(wildcard $(RTE_SDK)/lib/librte_eal/$(ARCH_DIR)/include/*.h)))
-
-SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include := $(addprefix include/,$(INC))
-SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include += \
-	$(addprefix ../$(ARCH_DIR)/include/,$(ARCH_INC))
-SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include/generic := \
-	$(addprefix include/generic/,$(GENERIC_INC))
-
-include $(RTE_SDK)/mk/rte.install.mk
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 5885441b48..02d9280cc3 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-eal_inc += include_directories('.', 'include')
+includes += include_directories('.')
 
 if is_windows
 	sources += files(
@@ -16,7 +16,9 @@ if is_windows
 		'eal_common_thread.c',
 		'rte_option.c',
 	)
-else # temporary bad indent
+	subdir_done()
+endif
+
 sources += files(
 	'eal_common_bus.c',
 	'eal_common_cpuflags.c',
@@ -52,62 +54,3 @@ sources += files(
 	'rte_reciprocal.c',
 	'rte_service.c',
 )
-endif
-
-common_headers = files(
-	'include/rte_alarm.h',
-	'include/rte_branch_prediction.h',
-	'include/rte_bus.h',
-	'include/rte_bitmap.h',
-	'include/rte_class.h',
-	'include/rte_common.h',
-	'include/rte_compat.h',
-	'include/rte_debug.h',
-	'include/rte_devargs.h',
-	'include/rte_dev.h',
-	'include/rte_eal.h',
-	'include/rte_eal_memconfig.h',
-	'include/rte_eal_interrupts.h',
-	'include/rte_errno.h',
-	'include/rte_fbarray.h',
-	'include/rte_hexdump.h',
-	'include/rte_hypervisor.h',
-	'include/rte_interrupts.h',
-	'include/rte_keepalive.h',
-	'include/rte_launch.h',
-	'include/rte_lcore.h',
-	'include/rte_log.h',
-	'include/rte_malloc.h',
-	'include/rte_memory.h',
-	'include/rte_memzone.h',
-	'include/rte_option.h',
-	'include/rte_pci_dev_feature_defs.h',
-	'include/rte_pci_dev_features.h',
-	'include/rte_per_lcore.h',
-	'include/rte_random.h',
-	'include/rte_reciprocal.h',
-	'include/rte_service.h',
-	'include/rte_service_component.h',
-	'include/rte_string_fns.h',
-	'include/rte_tailq.h',
-	'include/rte_time.h',
-	'include/rte_uuid.h',
-	'include/rte_version.h',
-	'include/rte_vfio.h')
-
-# special case install the generic headers, since they go in a subdir
-generic_headers = files(
-	'include/generic/rte_atomic.h',
-	'include/generic/rte_byteorder.h',
-	'include/generic/rte_cpuflags.h',
-	'include/generic/rte_cycles.h',
-	'include/generic/rte_io.h',
-	'include/generic/rte_mcslock.h',
-	'include/generic/rte_memcpy.h',
-	'include/generic/rte_pause.h',
-	'include/generic/rte_prefetch.h',
-	'include/generic/rte_rwlock.h',
-	'include/generic/rte_spinlock.h',
-	'include/generic/rte_ticketlock.h',
-	'include/generic/rte_vect.h')
-install_headers(generic_headers, subdir: 'generic')
diff --git a/lib/librte_eal/common/rte_service.c b/lib/librte_eal/common/rte_service.c
index b0b78baabd..70d17a5d79 100644
--- a/lib/librte_eal/common/rte_service.c
+++ b/lib/librte_eal/common/rte_service.c
@@ -10,7 +10,7 @@
 
 #include <rte_compat.h>
 #include <rte_service.h>
-#include "include/rte_service_component.h"
+#include <rte_service_component.h>
 
 #include <rte_eal.h>
 #include <rte_lcore.h>
diff --git a/lib/librte_eal/freebsd/eal/Makefile b/lib/librte_eal/freebsd/eal/Makefile
index e3023f24fa..0c809d9872 100644
--- a/lib/librte_eal/freebsd/eal/Makefile
+++ b/lib/librte_eal/freebsd/eal/Makefile
@@ -12,7 +12,7 @@ VPATH += $(RTE_SDK)/lib/librte_eal/$(ARCH_DIR)
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -I$(SRCDIR)/include
 CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 CFLAGS += $(WERROR_FLAGS) -O3
 
 LDLIBS += -lexecinfo
diff --git a/lib/librte_eal/include/Makefile b/lib/librte_eal/include/Makefile
new file mode 100644
index 0000000000..eb99190d10
--- /dev/null
+++ b/lib/librte_eal/include/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include := \
+	$(sort $(notdir \
+	$(wildcard $(RTE_SDK)/lib/librte_eal/include/*.h)))
+
+SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include/generic := \
+	$(sort $(addprefix generic/, $(notdir \
+	$(wildcard $(RTE_SDK)/lib/librte_eal/include/generic/*.h))))
+
+ARCH_DIR ?= $(RTE_ARCH)
+SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include += \
+	$(sort $(addprefix ../$(ARCH_DIR)/include/, $(notdir \
+	$(wildcard $(RTE_SDK)/lib/librte_eal/$(ARCH_DIR)/include/*.h))))
+
+include $(RTE_SDK)/mk/rte.install.mk
diff --git a/lib/librte_eal/common/include/generic/rte_atomic.h b/lib/librte_eal/include/generic/rte_atomic.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_atomic.h
rename to lib/librte_eal/include/generic/rte_atomic.h
diff --git a/lib/librte_eal/common/include/generic/rte_byteorder.h b/lib/librte_eal/include/generic/rte_byteorder.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_byteorder.h
rename to lib/librte_eal/include/generic/rte_byteorder.h
diff --git a/lib/librte_eal/common/include/generic/rte_cpuflags.h b/lib/librte_eal/include/generic/rte_cpuflags.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_cpuflags.h
rename to lib/librte_eal/include/generic/rte_cpuflags.h
diff --git a/lib/librte_eal/common/include/generic/rte_cycles.h b/lib/librte_eal/include/generic/rte_cycles.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_cycles.h
rename to lib/librte_eal/include/generic/rte_cycles.h
diff --git a/lib/librte_eal/common/include/generic/rte_io.h b/lib/librte_eal/include/generic/rte_io.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_io.h
rename to lib/librte_eal/include/generic/rte_io.h
diff --git a/lib/librte_eal/common/include/generic/rte_mcslock.h b/lib/librte_eal/include/generic/rte_mcslock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_mcslock.h
rename to lib/librte_eal/include/generic/rte_mcslock.h
diff --git a/lib/librte_eal/common/include/generic/rte_memcpy.h b/lib/librte_eal/include/generic/rte_memcpy.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_memcpy.h
rename to lib/librte_eal/include/generic/rte_memcpy.h
diff --git a/lib/librte_eal/common/include/generic/rte_pause.h b/lib/librte_eal/include/generic/rte_pause.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_pause.h
rename to lib/librte_eal/include/generic/rte_pause.h
diff --git a/lib/librte_eal/common/include/generic/rte_prefetch.h b/lib/librte_eal/include/generic/rte_prefetch.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_prefetch.h
rename to lib/librte_eal/include/generic/rte_prefetch.h
diff --git a/lib/librte_eal/common/include/generic/rte_rwlock.h b/lib/librte_eal/include/generic/rte_rwlock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_rwlock.h
rename to lib/librte_eal/include/generic/rte_rwlock.h
diff --git a/lib/librte_eal/common/include/generic/rte_spinlock.h b/lib/librte_eal/include/generic/rte_spinlock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_spinlock.h
rename to lib/librte_eal/include/generic/rte_spinlock.h
diff --git a/lib/librte_eal/common/include/generic/rte_ticketlock.h b/lib/librte_eal/include/generic/rte_ticketlock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_ticketlock.h
rename to lib/librte_eal/include/generic/rte_ticketlock.h
diff --git a/lib/librte_eal/common/include/generic/rte_vect.h b/lib/librte_eal/include/generic/rte_vect.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_vect.h
rename to lib/librte_eal/include/generic/rte_vect.h
diff --git a/lib/librte_eal/include/meson.build b/lib/librte_eal/include/meson.build
new file mode 100644
index 0000000000..6fd4274941
--- /dev/null
+++ b/lib/librte_eal/include/meson.build
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+includes += include_directories('.')
+
+headers += files(
+	'rte_alarm.h',
+	'rte_bitmap.h',
+	'rte_branch_prediction.h',
+	'rte_bus.h',
+	'rte_class.h',
+	'rte_common.h',
+	'rte_compat.h',
+	'rte_debug.h',
+	'rte_dev.h',
+	'rte_devargs.h',
+	'rte_eal.h',
+	'rte_eal_interrupts.h',
+	'rte_eal_memconfig.h',
+	'rte_errno.h',
+	'rte_fbarray.h',
+	'rte_hexdump.h',
+	'rte_hypervisor.h',
+	'rte_interrupts.h',
+	'rte_keepalive.h',
+	'rte_launch.h',
+	'rte_lcore.h',
+	'rte_log.h',
+	'rte_malloc.h',
+	'rte_memory.h',
+	'rte_memzone.h',
+	'rte_option.h',
+	'rte_pci_dev_feature_defs.h',
+	'rte_pci_dev_features.h',
+	'rte_per_lcore.h',
+	'rte_random.h',
+	'rte_reciprocal.h',
+	'rte_service.h',
+	'rte_service_component.h',
+	'rte_string_fns.h',
+	'rte_tailq.h',
+	'rte_time.h',
+	'rte_uuid.h',
+	'rte_version.h',
+	'rte_vfio.h',
+)
+
+# special case install the generic headers, since they go in a subdir
+generic_headers = files(
+	'generic/rte_atomic.h',
+	'generic/rte_byteorder.h',
+	'generic/rte_cpuflags.h',
+	'generic/rte_cycles.h',
+	'generic/rte_io.h',
+	'generic/rte_mcslock.h',
+	'generic/rte_memcpy.h',
+	'generic/rte_pause.h',
+	'generic/rte_prefetch.h',
+	'generic/rte_rwlock.h',
+	'generic/rte_spinlock.h',
+	'generic/rte_ticketlock.h',
+	'generic/rte_vect.h',
+)
+install_headers(generic_headers, subdir: 'generic')
diff --git a/lib/librte_eal/common/include/rte_alarm.h b/lib/librte_eal/include/rte_alarm.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_alarm.h
rename to lib/librte_eal/include/rte_alarm.h
diff --git a/lib/librte_eal/common/include/rte_bitmap.h b/lib/librte_eal/include/rte_bitmap.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_bitmap.h
rename to lib/librte_eal/include/rte_bitmap.h
diff --git a/lib/librte_eal/common/include/rte_branch_prediction.h b/lib/librte_eal/include/rte_branch_prediction.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_branch_prediction.h
rename to lib/librte_eal/include/rte_branch_prediction.h
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/include/rte_bus.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_bus.h
rename to lib/librte_eal/include/rte_bus.h
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/include/rte_class.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_class.h
rename to lib/librte_eal/include/rte_class.h
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/include/rte_common.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_common.h
rename to lib/librte_eal/include/rte_common.h
diff --git a/lib/librte_eal/common/include/rte_compat.h b/lib/librte_eal/include/rte_compat.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_compat.h
rename to lib/librte_eal/include/rte_compat.h
diff --git a/lib/librte_eal/common/include/rte_debug.h b/lib/librte_eal/include/rte_debug.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_debug.h
rename to lib/librte_eal/include/rte_debug.h
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/include/rte_dev.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_dev.h
rename to lib/librte_eal/include/rte_dev.h
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/include/rte_devargs.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_devargs.h
rename to lib/librte_eal/include/rte_devargs.h
diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/include/rte_eal.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_eal.h
rename to lib/librte_eal/include/rte_eal.h
diff --git a/lib/librte_eal/common/include/rte_eal_interrupts.h b/lib/librte_eal/include/rte_eal_interrupts.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_eal_interrupts.h
rename to lib/librte_eal/include/rte_eal_interrupts.h
diff --git a/lib/librte_eal/common/include/rte_eal_memconfig.h b/lib/librte_eal/include/rte_eal_memconfig.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_eal_memconfig.h
rename to lib/librte_eal/include/rte_eal_memconfig.h
diff --git a/lib/librte_eal/common/include/rte_errno.h b/lib/librte_eal/include/rte_errno.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_errno.h
rename to lib/librte_eal/include/rte_errno.h
diff --git a/lib/librte_eal/common/include/rte_fbarray.h b/lib/librte_eal/include/rte_fbarray.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_fbarray.h
rename to lib/librte_eal/include/rte_fbarray.h
diff --git a/lib/librte_eal/common/include/rte_function_versioning.h b/lib/librte_eal/include/rte_function_versioning.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_function_versioning.h
rename to lib/librte_eal/include/rte_function_versioning.h
diff --git a/lib/librte_eal/common/include/rte_hexdump.h b/lib/librte_eal/include/rte_hexdump.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_hexdump.h
rename to lib/librte_eal/include/rte_hexdump.h
diff --git a/lib/librte_eal/common/include/rte_hypervisor.h b/lib/librte_eal/include/rte_hypervisor.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_hypervisor.h
rename to lib/librte_eal/include/rte_hypervisor.h
diff --git a/lib/librte_eal/common/include/rte_interrupts.h b/lib/librte_eal/include/rte_interrupts.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_interrupts.h
rename to lib/librte_eal/include/rte_interrupts.h
diff --git a/lib/librte_eal/common/include/rte_keepalive.h b/lib/librte_eal/include/rte_keepalive.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_keepalive.h
rename to lib/librte_eal/include/rte_keepalive.h
diff --git a/lib/librte_eal/common/include/rte_launch.h b/lib/librte_eal/include/rte_launch.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_launch.h
rename to lib/librte_eal/include/rte_launch.h
diff --git a/lib/librte_eal/common/include/rte_lcore.h b/lib/librte_eal/include/rte_lcore.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_lcore.h
rename to lib/librte_eal/include/rte_lcore.h
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/include/rte_log.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_log.h
rename to lib/librte_eal/include/rte_log.h
diff --git a/lib/librte_eal/common/include/rte_malloc.h b/lib/librte_eal/include/rte_malloc.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_malloc.h
rename to lib/librte_eal/include/rte_malloc.h
diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/include/rte_memory.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_memory.h
rename to lib/librte_eal/include/rte_memory.h
diff --git a/lib/librte_eal/common/include/rte_memzone.h b/lib/librte_eal/include/rte_memzone.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_memzone.h
rename to lib/librte_eal/include/rte_memzone.h
diff --git a/lib/librte_eal/common/include/rte_option.h b/lib/librte_eal/include/rte_option.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_option.h
rename to lib/librte_eal/include/rte_option.h
diff --git a/lib/librte_eal/common/include/rte_pci_dev_feature_defs.h b/lib/librte_eal/include/rte_pci_dev_feature_defs.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_pci_dev_feature_defs.h
rename to lib/librte_eal/include/rte_pci_dev_feature_defs.h
diff --git a/lib/librte_eal/common/include/rte_pci_dev_features.h b/lib/librte_eal/include/rte_pci_dev_features.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_pci_dev_features.h
rename to lib/librte_eal/include/rte_pci_dev_features.h
diff --git a/lib/librte_eal/common/include/rte_per_lcore.h b/lib/librte_eal/include/rte_per_lcore.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_per_lcore.h
rename to lib/librte_eal/include/rte_per_lcore.h
diff --git a/lib/librte_eal/common/include/rte_random.h b/lib/librte_eal/include/rte_random.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_random.h
rename to lib/librte_eal/include/rte_random.h
diff --git a/lib/librte_eal/common/include/rte_reciprocal.h b/lib/librte_eal/include/rte_reciprocal.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_reciprocal.h
rename to lib/librte_eal/include/rte_reciprocal.h
diff --git a/lib/librte_eal/common/include/rte_service.h b/lib/librte_eal/include/rte_service.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_service.h
rename to lib/librte_eal/include/rte_service.h
diff --git a/lib/librte_eal/common/include/rte_service_component.h b/lib/librte_eal/include/rte_service_component.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_service_component.h
rename to lib/librte_eal/include/rte_service_component.h
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_eal/include/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_eal/include/rte_string_fns.h
diff --git a/lib/librte_eal/common/include/rte_tailq.h b/lib/librte_eal/include/rte_tailq.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_tailq.h
rename to lib/librte_eal/include/rte_tailq.h
diff --git a/lib/librte_eal/common/include/rte_test.h b/lib/librte_eal/include/rte_test.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_test.h
rename to lib/librte_eal/include/rte_test.h
diff --git a/lib/librte_eal/common/include/rte_time.h b/lib/librte_eal/include/rte_time.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_time.h
rename to lib/librte_eal/include/rte_time.h
diff --git a/lib/librte_eal/common/include/rte_uuid.h b/lib/librte_eal/include/rte_uuid.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_uuid.h
rename to lib/librte_eal/include/rte_uuid.h
diff --git a/lib/librte_eal/common/include/rte_version.h b/lib/librte_eal/include/rte_version.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_version.h
rename to lib/librte_eal/include/rte_version.h
diff --git a/lib/librte_eal/common/include/rte_vfio.h b/lib/librte_eal/include/rte_vfio.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_vfio.h
rename to lib/librte_eal/include/rte_vfio.h
diff --git a/lib/librte_eal/linux/eal/Makefile b/lib/librte_eal/linux/eal/Makefile
index 177b7c45da..692fec2695 100644
--- a/lib/librte_eal/linux/eal/Makefile
+++ b/lib/librte_eal/linux/eal/Makefile
@@ -15,7 +15,7 @@ VPATH += $(RTE_SDK)/lib/librte_eal/common
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -I$(SRCDIR)/include
 CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 CFLAGS += $(WERROR_FLAGS) -O3
 
 LDLIBS += -ldl
diff --git a/lib/librte_eal/meson.build b/lib/librte_eal/meson.build
index 1fc532139b..a433f46ade 100644
--- a/lib/librte_eal/meson.build
+++ b/lib/librte_eal/meson.build
@@ -5,6 +5,8 @@
 # have a straight list of headers and source files.
 # Initially pull in common settings
 eal_inc = [global_inc]
+subdir('include')
+
 subdir('common')
 
 # Now do OS/exec-env specific settings, including building kernel modules
@@ -27,5 +29,5 @@ if cc.has_header('getopt.h')
 endif
 sources += env_sources
 objs = env_objs
-headers = common_headers + env_headers
+headers = env_headers
 includes += eal_inc
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 419be8bd7c..24b1c3c5b9 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -7,7 +7,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
diff --git a/meson.build b/meson.build
index b7ae9c8d9a..ace4a0b8bf 100644
--- a/meson.build
+++ b/meson.build
@@ -28,7 +28,7 @@ abi_version_file = files('ABI_VERSION')
 # able to be included in any file. We also store a global array of include dirs
 # for passing to pmdinfogen scripts
 global_inc = include_directories('.', 'config',
-	'lib/librte_eal/common/include',
+	'lib/librte_eal/include',
 	'lib/librte_eal/@0@/eal/include'.format(host_machine.system()),
 )
 subdir('config')
-- 
2.25.1


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2 0/4] Introduce IF proxy library
  2020-03-25 11:11  4%     ` Morten Brørup
@ 2020-03-26 17:42  3%       ` Andrzej Ostruszka
  0 siblings, 0 replies; 200+ results
From: Andrzej Ostruszka @ 2020-03-26 17:42 UTC (permalink / raw)
  To: Morten Brørup, Andrzej Ostruszka, David Marchand; +Cc: dev

On 3/25/20 12:11 PM, Morten Brørup wrote:
[...]
>>> - Notification scheme has been changed - instead of having just
>>>   callbacks now event queueing is also available (or a mix of those
>>>   two).
> 
> Thank you for adding event queueing!

That was actually a good input from you - thank you.

> David mentions ABI forward compatibility below.
> Consider using a dynamically sized generic TLV (type, length, value)
> message format instead of a big union structure for the events. This
> would make it easier to extend the list of event types without breaking
> the ABI.

My understanding is that David was talking about registering of
callbacks and you want to extend this to event definition.

So let's focus on one example:
...
	RTE_IFPX_NEIGH_ADD,
	RTE_IFPX_NEIGH_DEL,
...
struct rte_ifpx_neigh_change {
	uint16_t port_id;
	struct rte_ether_addr mac;
	uint32_t ip;
};

Right now the event is defined as:

struct rte_ifpx_event {
	enum rte_ifpx_event_type type;
	union {
	...
		struct rte_ifpx_neigh_change neigh_change;
	...
	};
};

So what the user does is a switch on event->type:

	switch (ev->type) {
		case RTE_IFPX_NEIGH_ADD:
			handle_neigh_add(lconf, &ev->neigh_change);
			break;
		case RTE_IFPX_NEIGH_DEL:
			handle_neigh_del(lconf, &ev->neigh_change);
			break;

How does adding more event types to this union would break ABI?  User
gets event from the queue (allocated by the lib) checks the type and
casts the pointer past the 'type' to proper event definition.  And when
done with the event simply free()s it (BTW right now it is malloc() not
rte_malloc() - should I change that?).  If app links against newer
version of lib then it might get type which it does not
understand/handle so it should skip (possibly with a warning).  I'm not
sure how changing rte_ifpx_event to:

struct rte_ifpx_event {
	enut rte_ifpx_event_type type;
	int length;
	uint8_t data[];
};

would help here.  The user would need to cast data based on event type
whereas now it takes address of a proper union member - and the union is
there only to avoid casting.  In both cases what is important is that
RTE_IFPX_NEIGH_ADD/DEL and "struct rte_ifpx_neigh_change" don't change
between versions (new values can be added - or new versions of the
previously existing events when trying to make a change).

And for the callbacks it is more or less the same - library will prepare
data and call callback with a pointer to this data.  Handling of new
event types should be automatic when I implement what David wanted -
simply lib callback for the new event will be NULL nothing will be
called and application will work without problems.

> And I am still strongly opposed to the callback method:

Noted - however for now I would like to keep them.  I don't have much
experience with this library so if they prove to be inadequate then we
will remove them.  Right now they seem to add some flexibility that I like:
- if something should be changed globally and once (and it is safe to do
  so!) then it can be done from the callback
- if something can be prepared once and consumed later by lcores then it
  can be done in callback and the callback returns 0 so that event is
  still queued and lcores (under assumption that queues are per lcore)
  pick up what has been prepared.

> The callbacks are handled as DPDK interrupts, which are running in a non-DPDK
> thread, i.e. a running callback may be preempted by some other Linux process.
> This makes it difficult to implement callbacks correctly.
> The risk of someone calling a non-thread safe function from a callback is high,
> e.g. DPDK hash table manipulation (except lookup) is not thread safe.
> 
> Your documentation is far too vague about this:
> Please note however that the context in which these callbacks are 
> called is most probably different from the one in which packets are 
> handled and it is application writer responsibility to use proper 
> synchronization mechanisms - if they are needed.
> 
> You need a big fat WARNING about how difficult the DPDK interrupt thread is to
> work with. As I described above, it is not "most probably" it is "certainly" a
> very different kind of context.

OK.  Will update in next version.

> Did you check that the functions you use in your example callbacks are all
> thread safe and non-blocking, so they can safely be called from a non-DPDK thread
> that may be preempted by a another Linux process?

I believe so.  However there is a big question whether my assumption
about LPM is correct.  I've looked at the code and it looks like it so
but I'm not in power to authoritatively declare it.  So again, to me LPM
looks like safe to be changed by a single writer while being used by
multiple readers (with an obvious transient period when rule is being
expanded and some IPs might go with an old and some with a new destination).

With regards
Andrzej Ostruszka

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2 0/4] Introduce IF proxy library
  2020-03-25  8:08  3%   ` David Marchand
  2020-03-25 11:11  4%     ` Morten Brørup
@ 2020-03-26 12:41  3%     ` Andrzej Ostruszka
  2020-03-30 19:23  3%       ` Andrzej Ostruszka
  1 sibling, 1 reply; 200+ results
From: Andrzej Ostruszka @ 2020-03-26 12:41 UTC (permalink / raw)
  To: David Marchand, Andrzej Ostruszka; +Cc: dev

Thank you David for taking time to look at this.

On 3/25/20 9:08 AM, David Marchand wrote:
> Hello Andrzej,
> 
> On Tue, Mar 10, 2020 at 12:11 PM Andrzej Ostruszka
[...]
> I can see we end up exposing structures for registering callbacks.

Right.  I was thinking more in terms of user convenience so it seemed
like a good choice to gather them in one struct and call 'register'
once.  The fact that the same structure is used to keep them is an
implementation choice and this can be decoupled.

> Did you consider some ways to avoid exposure of those? (thinking of
> ABI maintenance for when this library will elect to non-experimental).

I will.  So far I used the union for the input since I like when things
are well typed :) and there is no need for casting.  However I will
spend some time on this and will get back to you soon (if you have
already something in your head please share).  Right now I'm thinking
about taking array of callbacks with each entry being ("event type",
callback) pair, however need to figure out how to have minimum amount of
type casting.

> I can see some canary at the end of an enum, can we do without it?

I followed discussion on the list about that and have thought about it
but deemed that to be not a problem.  This enum value is never returned
from the library and the event type enum is never taken as an input
(only used for event notification).  So this is really implementation
thing and you are right it would be better to hide it.  This might be
resolved by itself when I come up with something for the above ABI
stability issue.

> Is there a pb with merging ifpx support into the existing l3fwd
> application rather than introduce a new example?

I don't see a problem with merging per se.  That might be my
misunderstanding of what the examples are.  I thought that each library
can have its own example to show how it is supposed to be used.  So
decided to have simplified version of l3fwd  - and initially I thought
about updating l3fwd but it has some non-trivial optimizations and two
modes of operations (hash/lpm) so I wanted something simple to just show
how to use the library.  Don't know what is the reason for this
bi-modality of l3fwd:
- if this is just a need to show LPM/Hash in use then I can replace that
  with single mode of l3fwd-ifpx where LPM is used for routing and Hash
  is used to keep neighbouring info
- if this is to show that both LPM and Hash can be used for routing then
  it would complicate things as these two have different update
  properties.

I assume (but don't have a solid proof for that) that LPM can be updated
by a single writer while being used by multiple readers and use this
assumption to show how such structures can be updated (Morten please
cover your eyes ;-)) from a callback while other can be updated via
event queuing.

So if the community decides that it would be OK to morph l3fwd to:
- strip the bi-modality
- use LPM and Hash for different things (not both for routing)
then I'm OK with that and will happily do that.  Otherwise adding IFPX
to l3fwd will end up with two modes with different routing
implementation and different update strategies - a bit like two
different apps bundled into one and chosen by the command arg.

There is also a question of not having FreeBSD and Windows support yet -
so things might get complicated.

With regards
Andrzej Ostruszka

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [RFC] ring: make ring implementation non-inlined
  2020-03-25 21:09  4% ` Jerin Jacob
  2020-03-26  0:28  0%   ` Ananyev, Konstantin
@ 2020-03-26  8:04  4%   ` Morten Brørup
  2020-03-31 23:25  5%     ` Thomas Monjalon
  1 sibling, 1 reply; 200+ results
From: Morten Brørup @ 2020-03-26  8:04 UTC (permalink / raw)
  To: Jerin Jacob, Konstantin Ananyev
  Cc: dpdk-dev, Olivier Matz, Honnappa Nagarahalli, Jerin Jacob,
	David Christensen, Stephen Hemminger

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jerin Jacob
> Sent: Wednesday, March 25, 2020 10:09 PM
> 
> On Fri, Mar 20, 2020 at 10:11 PM Konstantin Ananyev
> <konstantin.ananyev@intel.com> wrote:
> >
> > As was discussed here:
> > http://mails.dpdk.org/archives/dev/2020-February/158586.html
> > this RFC aimed to hide ring internals into .c and make all
> > ring functions non-inlined. In theory that might help to
> > maintain ABI stability in future.
> > This is just a POC to measure the impact of proposed idea,
> > proper implementation would definetly need some extra effort.
> > On IA box (SKX) ring_perf_autotest shows ~20-30 cycles extra for
> > enqueue+dequeue pair. On some more realistic code, I suspect
> > the impact it might be a bit higher.
> > For MP/MC bulk transfers degradation seems quite small,
> > though for SP/SC and/or small transfers it is more then noticable
> > (see exact numbers below).
> > From my perspective we'd probably keep it inlined for now
> > to avoid any non-anticipated perfomance degradations.
> > Though intersted to see perf results and opinions from
> > other interested parties.
> 
> +1
> 
> My reasoning is a bit different, DPDK is using in embedded boxes too
> where performance has
> more weight than ABI stuff.

As a network appliance vendor I can confirm that we certainly care more about performance than ABI stability. ABI stability is irrelevant for us; and API instability is a non-recurring engineering cost each time we choose to switch to a new DPDK version, which we only do if we cannot avoid it, e.g. due to new drivers, security fixes or new features that we want to use.

For us, the trend pointed in the wrong direction when DPDK switched the preference towards runtime configurability and deprecated compile time configurability. I do understand the reasoning behind it, and the impact is minimal, so we accept it.

However, if DPDK starts sacrificing performance of the core libraries for the benefits of the GNU/Linux distributors, network appliance vendors may put more effort into sticking with old DPDK versions instead of updating.

> I think we need to focus first on slow
> path APIs ABI stuff.
> 
> I spend a few cycles to apply this patch +
> http://mails.dpdk.org/archives/dev/2020-February/158586.html
> on top of the tree, there are a lot of conflicts. If I get a mergeable
> patch then I will test it on an arm64 box.
> 
> 
> 
> 
> 
> >
> > Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> > ring_perf_autotest (without patch/with patch)


^ permalink raw reply	[relevance 4%]

* [dpdk-dev] [PATCH v5 2/7] net/ice: add the DCF hardware initialization
  @ 2020-03-26  7:15  1%   ` Haiyue Wang
  0 siblings, 0 replies; 200+ results
From: Haiyue Wang @ 2020-03-26  7:15 UTC (permalink / raw)
  To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
  Cc: wei.zhao1, Haiyue Wang

Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.

Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
 doc/guides/nics/ice.rst                |  47 +++
 doc/guides/nics/img/ice_dcf.png        | Bin 0 -> 39168 bytes
 doc/guides/rel_notes/release_20_05.rst |   5 +
 drivers/common/Makefile                |   1 +
 drivers/net/ice/Makefile               |   5 +
 drivers/net/ice/ice_dcf.c              | 474 +++++++++++++++++++++++++
 drivers/net/ice/ice_dcf.h              |  52 +++
 drivers/net/ice/ice_dcf_ethdev.c       | 317 +++++++++++++++++
 drivers/net/ice/ice_dcf_ethdev.h       |  24 ++
 drivers/net/ice/meson.build            |   7 +-
 mk/rte.app.mk                          |   1 +
 11 files changed, 931 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 drivers/net/ice/ice_dcf.c
 create mode 100644 drivers/net/ice/ice_dcf.h
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.h

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
 
 The APPs based on DPDK should avoid providing such packets.
 
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+   DCF Communication flow.
+
+#. Create the VFs::
+
+      echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+      ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0,  and run testpmd with 'cap=dcf' devarg::
+
+      testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+      tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+      flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+      dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+      sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+      192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+      iface="enp24s0f0", count=10)
+
 Sample Application Notes
 ------------------------
 
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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

literal 0
HcmV?d00001

diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
 
   * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
 
+* **Updated the Intel ice driver.**
+
+  Updated the Intel ice driver with new features and improvements, including:
+
+  * Added support for DCF (Device Config Function) feature.
 
 Removed Items
 -------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
 endif
 
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifneq (,$(findstring y,$(IAVF-y)))
 DIRS-y += iavf
 endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
 LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
 
 EXPORT_MAP := rte_pmd_ice_version.map
 
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
 
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
 
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN     32
+#define ICE_DCF_AQ_BUF_SZ  4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME  2   /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ	\
+	(sizeof(struct virtchnl_vf_resource) +	\
+		IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *req_msg, uint16_t req_msglen)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+				      req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+			    uint16_t *rsp_msglen)
+{
+	struct iavf_arq_event_info event;
+	enum virtchnl_ops v_op;
+	int i = 0;
+	int err;
+
+	event.buf_len = rsp_buflen;
+	event.msg_buf = rsp_msgbuf;
+
+	do {
+		err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+		if (err != IAVF_SUCCESS)
+			goto again;
+
+		v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+		if (v_op != op)
+			goto again;
+
+		if (rsp_msglen != NULL)
+			*rsp_msglen = event.msg_len;
+		return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	cmd->v_ret = IAVF_ERR_NOT_READY;
+	cmd->rsp_msglen = 0;
+	cmd->pending = 1;
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf,
+				      cmd->v_op, IAVF_SUCCESS,
+				      cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+	struct dcf_virtchnl_cmd *cmd;
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+	uint16_t aq_op;
+
+	aq_op = rte_le_to_cpu_16(info->desc.opcode);
+	if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+		PMD_DRV_LOG(ERR,
+			    "Request %u is not supported yet", aq_op);
+		return;
+	}
+
+	v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+	if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+		return;
+
+	v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+		if (cmd->v_op == v_op && cmd->pending) {
+			cmd->v_ret = v_ret;
+			cmd->rsp_msglen = RTE_MIN(info->msg_len,
+						  cmd->rsp_buflen);
+			if (likely(cmd->rsp_msglen != 0))
+				rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+					   cmd->rsp_msglen);
+
+			/* prevent compiler reordering */
+			rte_compiler_barrier();
+			cmd->pending = 0;
+			break;
+		}
+	}
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+	struct iavf_arq_event_info info;
+	uint16_t pending = 1;
+	int ret;
+
+	info.buf_len = ICE_DCF_AQ_BUF_SZ;
+	info.msg_buf = hw->arq_buf;
+
+	while (pending) {
+		ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+		if (ret != IAVF_SUCCESS)
+			break;
+
+		ice_dcf_aq_cmd_handle(hw, &info);
+	}
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START	1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START	1
+	struct virtchnl_version_info version, *pver;
+	int err;
+
+	version.major = VIRTCHNL_VERSION_MAJOR;
+	version.minor = VIRTCHNL_VERSION_MINOR;
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)&version, sizeof(version));
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+		return err;
+	}
+
+	pver = &hw->virtchnl_version;
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)pver, sizeof(*pver), NULL);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG,
+		     "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+	if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+	    (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+	     pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+		PMD_INIT_LOG(ERR,
+			     "VIRTCHNL API version should not be lower than (%u.%u)",
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+		return -1;
+	} else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+		   (pver->major == VIRTCHNL_VERSION_MAJOR &&
+		    pver->minor > VIRTCHNL_VERSION_MINOR)) {
+		PMD_INIT_LOG(ERR,
+			     "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+			     pver->major, pver->minor,
+			     VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+	return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+	uint32_t caps;
+	int err, i;
+
+	caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+	       VF_BASE_MODE_OFFLOADS;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)&caps, sizeof(caps));
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)hw->vf_res,
+					  ICE_DCF_VF_RES_BUF_SZ, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+		return -1;
+	}
+
+	iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+	hw->vsi_res = NULL;
+	for (i = 0; i < hw->vf_res->num_vsis; i++) {
+		if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+			hw->vsi_res = &hw->vf_res->vsi_res[i];
+	}
+
+	if (!hw->vsi_res) {
+		PMD_DRV_LOG(ERR, "no LAN VSI found");
+		return -1;
+	}
+
+	hw->vsi_id = hw->vsi_res->vsi_id;
+	PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+	return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT       50
+	struct iavf_hw *avf = &hw->avf;
+	int i, reset;
+
+	for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+		reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+					IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+		reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+		if (reset == VIRTCHNL_VFR_VFACTIVE ||
+		    reset == VIRTCHNL_VFR_COMPLETED)
+			break;
+
+		rte_delay_ms(20);
+	}
+
+	if (i >= ICE_DCF_RESET_WAIT_CNT)
+		return -1;
+
+	return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+	struct ice_dcf_hw *hw = param;
+
+	ice_dcf_disable_irq0(hw);
+
+	ice_dcf_handle_virtchnl_msg(hw);
+
+	ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+			     struct dcf_virtchnl_cmd *cmd)
+{
+	int i = 0;
+	int err;
+
+	if ((cmd->req_msg && !cmd->req_msglen) ||
+	    (!cmd->req_msg && cmd->req_msglen) ||
+	    (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+	    (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+		return -EINVAL;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_vc_cmd_set(hw, cmd);
+
+	err = ice_dcf_vc_cmd_send(hw, cmd);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+		goto ret;
+	}
+
+	do {
+		if (!cmd->pending)
+			break;
+
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	if (cmd->v_ret != IAVF_SUCCESS) {
+		err = -1;
+		PMD_DRV_LOG(ERR,
+			    "No response (%d times) or return failure (%d) for cmd %d",
+			    i, cmd->v_ret, cmd->v_op);
+	}
+
+ret:
+	ice_dcf_aq_cmd_clear(hw, cmd);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+	return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	int ret;
+
+	hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+	hw->avf.back = hw;
+
+	hw->avf.bus.bus_id = pci_dev->addr.bus;
+	hw->avf.bus.device = pci_dev->addr.devid;
+	hw->avf.bus.func = pci_dev->addr.function;
+
+	hw->avf.device_id = pci_dev->id.device_id;
+	hw->avf.vendor_id = pci_dev->id.vendor_id;
+	hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+	hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+	hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+	rte_spinlock_init(&hw->vc_cmd_send_lock);
+	rte_spinlock_init(&hw->vc_cmd_queue_lock);
+	TAILQ_INIT(&hw->vc_cmd_queue);
+
+	hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+	if (hw->arq_buf == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+		goto err;
+	}
+
+	ret = iavf_set_mac_type(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+		goto err;
+	}
+
+	ret = ice_dcf_check_reset_done(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "VF is still resetting");
+		goto err;
+	}
+
+	ret = iavf_init_adminq(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+		goto err;
+	}
+
+	if (ice_dcf_init_check_api_version(hw)) {
+		PMD_INIT_LOG(ERR, "check_api version failed");
+		goto err_api;
+	}
+
+	hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+	if (hw->vf_res == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+		goto err_api;
+	}
+
+	if (ice_dcf_get_vf_resource(hw)) {
+		PMD_INIT_LOG(ERR, "Failed to get VF resource");
+		goto err_alloc;
+	}
+
+	rte_intr_callback_register(&pci_dev->intr_handle,
+				   ice_dcf_dev_interrupt_handler, hw);
+	rte_intr_enable(&pci_dev->intr_handle);
+	ice_dcf_enable_irq0(hw);
+
+	return 0;
+
+err_alloc:
+	rte_free(hw->vf_res);
+err_api:
+	iavf_shutdown_adminq(&hw->avf);
+err:
+	rte_free(hw->arq_buf);
+
+	return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+	ice_dcf_disable_irq0(hw);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     ice_dcf_dev_interrupt_handler, hw);
+
+	iavf_shutdown_adminq(&hw->avf);
+
+	rte_free(hw->arq_buf);
+	rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+	TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+
+	uint16_t req_msglen;
+	uint8_t *req_msg;
+
+	uint16_t rsp_msglen;
+	uint16_t rsp_buflen;
+	uint8_t *rsp_msgbuf;
+
+	volatile int pending;
+};
+
+struct ice_dcf_hw {
+	struct iavf_hw avf;
+
+	rte_spinlock_t vc_cmd_send_lock;
+	rte_spinlock_t vc_cmd_queue_lock;
+	TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+	uint8_t *arq_buf;
+
+	struct virtchnl_version_info virtchnl_version;
+	struct virtchnl_vf_resource *vf_res; /* VF resource */
+	struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+				 struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+		     struct rte_eth_dev_info *dev_info)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+	dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+	return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+		  __rte_unused struct rte_eth_stats *igb_stats)
+{
+	return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+			enum rte_filter_type filter_type,
+			__rte_unused enum rte_filter_op filter_op,
+			__rte_unused void *arg)
+{
+	int ret = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	switch (filter_type) {
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+			    filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return;
+
+	dev->dev_ops = NULL;
+	dev->rx_pkt_burst = NULL;
+	dev->tx_pkt_burst = NULL;
+	dev->data->mac_addrs = NULL;
+
+	ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+		    __rte_unused int wait_to_complete)
+{
+	return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t rx_queue_id,
+		       __rte_unused uint16_t nb_rx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_rxconf *rx_conf,
+		       __rte_unused struct rte_mempool *mb_pool)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+	return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t tx_queue_id,
+		       __rte_unused uint16_t nb_tx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+	return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+	.dev_start               = ice_dcf_dev_start,
+	.dev_stop                = ice_dcf_dev_stop,
+	.dev_close               = ice_dcf_dev_close,
+	.dev_configure           = ice_dcf_dev_configure,
+	.dev_infos_get           = ice_dcf_dev_info_get,
+	.rx_queue_setup          = ice_dcf_rx_queue_setup,
+	.tx_queue_setup          = ice_dcf_tx_queue_setup,
+	.rx_queue_release        = ice_dcf_queue_release,
+	.tx_queue_release        = ice_dcf_queue_release,
+	.link_update             = ice_dcf_link_update,
+	.stats_get               = ice_dcf_stats_get,
+	.stats_reset             = ice_dcf_stats_reset,
+	.promiscuous_enable      = ice_dcf_dev_promiscuous_enable,
+	.promiscuous_disable     = ice_dcf_dev_promiscuous_disable,
+	.allmulticast_enable     = ice_dcf_dev_allmulticast_enable,
+	.allmulticast_disable    = ice_dcf_dev_allmulticast_disable,
+	.filter_ctrl             = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+	eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+	eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+	eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+	if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+		PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+		return -1;
+	}
+
+	rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+	eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+	return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+	ice_dcf_dev_close(eth_dev);
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+			  const char *value, __rte_unused void *opaque)
+{
+	if (strcmp(value, "dcf"))
+		return -1;
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	const char *key = "cap";
+	int ret = 0;
+
+	if (devargs == NULL)
+		return 0;
+
+	kvlist = rte_kvargs_parse(devargs->args, NULL);
+	if (kvlist == NULL)
+		return 0;
+
+	if (!rte_kvargs_count(kvlist, key))
+		goto exit;
+
+	/* dcf capability selected when there's a key-value pair: cap=dcf */
+	if (rte_kvargs_process(kvlist, key,
+			       ice_dcf_cap_check_handler, NULL) < 0)
+		goto exit;
+
+	ret = 1;
+
+exit:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+			     struct rte_pci_device *pci_dev)
+{
+	if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+		return 1;
+
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+					     sizeof(struct ice_dcf_adapter),
+					     ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+	{ RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+	.id_table = pci_id_ice_dcf_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+	.probe = eth_ice_dcf_pci_probe,
+	.remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS  1
+
+struct ice_dcf_queue {
+	uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+	struct ice_dcf_hw real_hw;
+	struct rte_ether_addr mac_addr;
+	struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+	struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
 	'ice_hash.c'
 	)
 
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
 
 if arch_subdir == 'x86'
 	sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
 	endif
 endif
 
+sources += files('ice_dcf.c',
+		 'ice_dcf_ethdev.c')
+
 install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD)       += -lrte_pmd_iavf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD)        += -lrte_pmd_ice
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifeq ($(findstring y,$(IAVF-y)),y)
 _LDLIBS-y += -lrte_common_iavf
 endif
-- 
2.26.0


^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v4 2/7] net/ice: add the DCF hardware initialization
  @ 2020-03-26  3:03  1%   ` Haiyue Wang
  0 siblings, 0 replies; 200+ results
From: Haiyue Wang @ 2020-03-26  3:03 UTC (permalink / raw)
  To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
  Cc: wei.zhao1, Haiyue Wang

Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.

Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
 doc/guides/nics/ice.rst                |  47 +++
 doc/guides/nics/img/ice_dcf.png        | Bin 0 -> 39168 bytes
 doc/guides/rel_notes/release_20_05.rst |   5 +
 drivers/common/Makefile                |   1 +
 drivers/net/ice/Makefile               |   5 +
 drivers/net/ice/ice_dcf.c              | 474 +++++++++++++++++++++++++
 drivers/net/ice/ice_dcf.h              |  52 +++
 drivers/net/ice/ice_dcf_ethdev.c       | 317 +++++++++++++++++
 drivers/net/ice/ice_dcf_ethdev.h       |  24 ++
 drivers/net/ice/meson.build            |   7 +-
 mk/rte.app.mk                          |   1 +
 11 files changed, 931 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 drivers/net/ice/ice_dcf.c
 create mode 100644 drivers/net/ice/ice_dcf.h
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.h

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
 
 The APPs based on DPDK should avoid providing such packets.
 
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+   DCF Communication flow.
+
+#. Create the VFs::
+
+      echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+      ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0,  and run testpmd with 'cap=dcf' devarg::
+
+      testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+      tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+      flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+      dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+      sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+      192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+      iface="enp24s0f0", count=10)
+
 Sample Application Notes
 ------------------------
 
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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

literal 0
HcmV?d00001

diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
 
   * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
 
+* **Updated the Intel ice driver.**
+
+  Updated the Intel ice driver with new features and improvements, including:
+
+  * Added support for DCF (Device Config Function) feature.
 
 Removed Items
 -------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
 endif
 
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifneq (,$(findstring y,$(IAVF-y)))
 DIRS-y += iavf
 endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
 LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
 
 EXPORT_MAP := rte_pmd_ice_version.map
 
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
 
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
 
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN     32
+#define ICE_DCF_AQ_BUF_SZ  4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME  2   /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ	\
+	(sizeof(struct virtchnl_vf_resource) +	\
+		IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *req_msg, uint16_t req_msglen)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+				      req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+			    uint16_t *rsp_msglen)
+{
+	struct iavf_arq_event_info event;
+	enum virtchnl_ops v_op;
+	int i = 0;
+	int err;
+
+	event.buf_len = rsp_buflen;
+	event.msg_buf = rsp_msgbuf;
+
+	do {
+		err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+		if (err != IAVF_SUCCESS)
+			goto again;
+
+		v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+		if (v_op != op)
+			goto again;
+
+		if (rsp_msglen != NULL)
+			*rsp_msglen = event.msg_len;
+		return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	cmd->v_ret = IAVF_ERR_NOT_READY;
+	cmd->rsp_msglen = 0;
+	cmd->pending = 1;
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf,
+				      cmd->v_op, IAVF_SUCCESS,
+				      cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+	struct dcf_virtchnl_cmd *cmd;
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+	uint16_t aq_op;
+
+	aq_op = rte_le_to_cpu_16(info->desc.opcode);
+	if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+		PMD_DRV_LOG(ERR,
+			    "Request %u is not supported yet", aq_op);
+		return;
+	}
+
+	v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+	if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+		return;
+
+	v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+		if (cmd->v_op == v_op && cmd->pending) {
+			cmd->v_ret = v_ret;
+			cmd->rsp_msglen = RTE_MIN(info->msg_len,
+						  cmd->rsp_buflen);
+			if (likely(cmd->rsp_msglen != 0))
+				rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+					   cmd->rsp_msglen);
+
+			/* prevent compiler reordering */
+			rte_compiler_barrier();
+			cmd->pending = 0;
+			break;
+		}
+	}
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+	struct iavf_arq_event_info info;
+	uint16_t pending = 1;
+	int ret;
+
+	info.buf_len = ICE_DCF_AQ_BUF_SZ;
+	info.msg_buf = hw->arq_buf;
+
+	while (pending) {
+		ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+		if (ret != IAVF_SUCCESS)
+			break;
+
+		ice_dcf_aq_cmd_handle(hw, &info);
+	}
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START	1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START	1
+	struct virtchnl_version_info version, *pver;
+	int err;
+
+	version.major = VIRTCHNL_VERSION_MAJOR;
+	version.minor = VIRTCHNL_VERSION_MINOR;
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)&version, sizeof(version));
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+		return err;
+	}
+
+	pver = &hw->virtchnl_version;
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)pver, sizeof(*pver), NULL);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG,
+		     "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+	if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+	    (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+	     pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+		PMD_INIT_LOG(ERR,
+			     "VIRTCHNL API version should not be lower than (%u.%u)",
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+		return -1;
+	} else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+		   (pver->major == VIRTCHNL_VERSION_MAJOR &&
+		    pver->minor > VIRTCHNL_VERSION_MINOR)) {
+		PMD_INIT_LOG(ERR,
+			     "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+			     pver->major, pver->minor,
+			     VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+	return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+	uint32_t caps;
+	int err, i;
+
+	caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+	       VF_BASE_MODE_OFFLOADS;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)&caps, sizeof(caps));
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)hw->vf_res,
+					  ICE_DCF_VF_RES_BUF_SZ, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+		return -1;
+	}
+
+	iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+	hw->vsi_res = NULL;
+	for (i = 0; i < hw->vf_res->num_vsis; i++) {
+		if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+			hw->vsi_res = &hw->vf_res->vsi_res[i];
+	}
+
+	if (!hw->vsi_res) {
+		PMD_DRV_LOG(ERR, "no LAN VSI found");
+		return -1;
+	}
+
+	hw->vsi_id = hw->vsi_res->vsi_id;
+	PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+	return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT       50
+	struct iavf_hw *avf = &hw->avf;
+	int i, reset;
+
+	for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+		reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+					IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+		reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+		if (reset == VIRTCHNL_VFR_VFACTIVE ||
+		    reset == VIRTCHNL_VFR_COMPLETED)
+			break;
+
+		rte_delay_ms(20);
+	}
+
+	if (i >= ICE_DCF_RESET_WAIT_CNT)
+		return -1;
+
+	return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+	struct ice_dcf_hw *hw = param;
+
+	ice_dcf_disable_irq0(hw);
+
+	ice_dcf_handle_virtchnl_msg(hw);
+
+	ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+			     struct dcf_virtchnl_cmd *cmd)
+{
+	int i = 0;
+	int err;
+
+	if ((cmd->req_msg && !cmd->req_msglen) ||
+	    (!cmd->req_msg && cmd->req_msglen) ||
+	    (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+	    (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+		return -EINVAL;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_vc_cmd_set(hw, cmd);
+
+	err = ice_dcf_vc_cmd_send(hw, cmd);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+		goto ret;
+	}
+
+	do {
+		if (!cmd->pending)
+			break;
+
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	if (cmd->v_ret != IAVF_SUCCESS) {
+		err = -1;
+		PMD_DRV_LOG(ERR,
+			    "No response (%d times) or return failure (%d) for cmd %d",
+			    i, cmd->v_ret, cmd->v_op);
+	}
+
+ret:
+	ice_dcf_aq_cmd_clear(hw, cmd);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+	return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	int ret;
+
+	hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+	hw->avf.back = hw;
+
+	hw->avf.bus.bus_id = pci_dev->addr.bus;
+	hw->avf.bus.device = pci_dev->addr.devid;
+	hw->avf.bus.func = pci_dev->addr.function;
+
+	hw->avf.device_id = pci_dev->id.device_id;
+	hw->avf.vendor_id = pci_dev->id.vendor_id;
+	hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+	hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+	hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+	rte_spinlock_init(&hw->vc_cmd_send_lock);
+	rte_spinlock_init(&hw->vc_cmd_queue_lock);
+	TAILQ_INIT(&hw->vc_cmd_queue);
+
+	hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+	if (hw->arq_buf == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+		goto err;
+	}
+
+	ret = iavf_set_mac_type(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+		goto err;
+	}
+
+	ret = ice_dcf_check_reset_done(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "VF is still resetting");
+		goto err;
+	}
+
+	ret = iavf_init_adminq(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+		goto err;
+	}
+
+	if (ice_dcf_init_check_api_version(hw)) {
+		PMD_INIT_LOG(ERR, "check_api version failed");
+		goto err_api;
+	}
+
+	hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+	if (hw->vf_res == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+		goto err_api;
+	}
+
+	if (ice_dcf_get_vf_resource(hw)) {
+		PMD_INIT_LOG(ERR, "Failed to get VF resource");
+		goto err_alloc;
+	}
+
+	rte_intr_callback_register(&pci_dev->intr_handle,
+				   ice_dcf_dev_interrupt_handler, hw);
+	rte_intr_enable(&pci_dev->intr_handle);
+	ice_dcf_enable_irq0(hw);
+
+	return 0;
+
+err_alloc:
+	rte_free(hw->vf_res);
+err_api:
+	iavf_shutdown_adminq(&hw->avf);
+err:
+	rte_free(hw->arq_buf);
+
+	return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+	ice_dcf_disable_irq0(hw);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     ice_dcf_dev_interrupt_handler, hw);
+
+	iavf_shutdown_adminq(&hw->avf);
+
+	rte_free(hw->arq_buf);
+	rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+	TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+
+	uint16_t req_msglen;
+	uint8_t *req_msg;
+
+	uint16_t rsp_msglen;
+	uint16_t rsp_buflen;
+	uint8_t *rsp_msgbuf;
+
+	volatile int pending;
+};
+
+struct ice_dcf_hw {
+	struct iavf_hw avf;
+
+	rte_spinlock_t vc_cmd_send_lock;
+	rte_spinlock_t vc_cmd_queue_lock;
+	TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+	uint8_t *arq_buf;
+
+	struct virtchnl_version_info virtchnl_version;
+	struct virtchnl_vf_resource *vf_res; /* VF resource */
+	struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+				 struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+		     struct rte_eth_dev_info *dev_info)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+	dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+	return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+		  __rte_unused struct rte_eth_stats *igb_stats)
+{
+	return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+			enum rte_filter_type filter_type,
+			__rte_unused enum rte_filter_op filter_op,
+			__rte_unused void *arg)
+{
+	int ret = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	switch (filter_type) {
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+			    filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return;
+
+	dev->dev_ops = NULL;
+	dev->rx_pkt_burst = NULL;
+	dev->tx_pkt_burst = NULL;
+	dev->data->mac_addrs = NULL;
+
+	ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+		    __rte_unused int wait_to_complete)
+{
+	return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t rx_queue_id,
+		       __rte_unused uint16_t nb_rx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_rxconf *rx_conf,
+		       __rte_unused struct rte_mempool *mb_pool)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+	return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t tx_queue_id,
+		       __rte_unused uint16_t nb_tx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+	return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+	.dev_start               = ice_dcf_dev_start,
+	.dev_stop                = ice_dcf_dev_stop,
+	.dev_close               = ice_dcf_dev_close,
+	.dev_configure           = ice_dcf_dev_configure,
+	.dev_infos_get           = ice_dcf_dev_info_get,
+	.rx_queue_setup          = ice_dcf_rx_queue_setup,
+	.tx_queue_setup          = ice_dcf_tx_queue_setup,
+	.rx_queue_release        = ice_dcf_queue_release,
+	.tx_queue_release        = ice_dcf_queue_release,
+	.link_update             = ice_dcf_link_update,
+	.stats_get               = ice_dcf_stats_get,
+	.stats_reset             = ice_dcf_stats_reset,
+	.promiscuous_enable      = ice_dcf_dev_promiscuous_enable,
+	.promiscuous_disable     = ice_dcf_dev_promiscuous_disable,
+	.allmulticast_enable     = ice_dcf_dev_allmulticast_enable,
+	.allmulticast_disable    = ice_dcf_dev_allmulticast_disable,
+	.filter_ctrl             = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+	eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+	eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+	eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+	if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+		PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+		return -1;
+	}
+
+	rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+	eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+	return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+	ice_dcf_dev_close(eth_dev);
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+			  const char *value, __rte_unused void *opaque)
+{
+	if (strcmp(value, "dcf"))
+		return -1;
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	const char *key = "cap";
+	int ret = 0;
+
+	if (devargs == NULL)
+		return 0;
+
+	kvlist = rte_kvargs_parse(devargs->args, NULL);
+	if (kvlist == NULL)
+		return 0;
+
+	if (!rte_kvargs_count(kvlist, key))
+		goto exit;
+
+	/* dcf capability selected when there's a key-value pair: cap=dcf */
+	if (rte_kvargs_process(kvlist, key,
+			       ice_dcf_cap_check_handler, NULL) < 0)
+		goto exit;
+
+	ret = 1;
+
+exit:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+			     struct rte_pci_device *pci_dev)
+{
+	if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+		return 1;
+
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+					     sizeof(struct ice_dcf_adapter),
+					     ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+	{ RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+	.id_table = pci_id_ice_dcf_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+	.probe = eth_ice_dcf_pci_probe,
+	.remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS  1
+
+struct ice_dcf_queue {
+	uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+	struct ice_dcf_hw real_hw;
+	struct rte_ether_addr mac_addr;
+	struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+	struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
 	'ice_hash.c'
 	)
 
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
 
 if arch_subdir == 'x86'
 	sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
 	endif
 endif
 
+sources += files('ice_dcf.c',
+		 'ice_dcf_ethdev.c')
+
 install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD)       += -lrte_pmd_iavf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD)        += -lrte_pmd_ice
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifeq ($(findstring y,$(IAVF-y)),y)
 _LDLIBS-y += -lrte_common_iavf
 endif
-- 
2.26.0


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-03-25 20:43  0% ` Honnappa Nagarahalli
@ 2020-03-26  1:50  3%   ` Ananyev, Konstantin
  2020-03-30 21:29  0%     ` Honnappa Nagarahalli
  0 siblings, 1 reply; 200+ results
From: Ananyev, Konstantin @ 2020-03-26  1:50 UTC (permalink / raw)
  To: Honnappa Nagarahalli, dev; +Cc: olivier.matz, nd, nd

> 
> <snip>
> 
> > Subject: [dpdk-dev] [RFC 0/6] New sync modes for ring
> >
> > Upfront note - that RFC is not a complete patch.
> > It introduces an ABI breakage, plus it doesn't update ring_elem code properly,
> As per the current rules, these changes (in the current form) will be accepted only for 20.11 release. How do we address this for immediate
> requirements like RCU defer APIs?

I think I found a way to introduce these new modes without API/ABI breakage.
Working on v1 right now. Plan to submit it by end of that week/start of next one.

> I suggest that we move forward with my RFC (taking into consideration your feedback) to make progress on RCU APIs.
> 
> > etc.
> > I plan to deal with all these things in later versions.
> > Right now I seek an initial feedback about proposed ideas.
> > Would also ask people to repeat performance tests (see below) on their
> > platforms to confirm the impact.
> >
> > More and more customers use(/try to use) DPDK based apps within
> > overcommitted systems (multiple acttive threads over same pysical cores):
> > VM, container deployments, etc.
> > One quite common problem they hit: Lock-Holder-Preemption with rte_ring.
> > LHP is quite a common problem for spin-based sync primitives (spin-locks, etc.)
> > on overcommitted systems.
> > The situation gets much worse when some sort of fair-locking technique is
> > used (ticket-lock, etc.).
> > As now not only lock-owner but also lock-waiters scheduling order matters a
> > lot.
> > This is a well-known problem for kernel within VMs:
> > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > The problem with rte_ring is that while head accusion is sort of un-fair locking,
> > waiting on tail is very similar to ticket lock schema - tail has to be updated in
> > particular order.
> > That makes current rte_ring implementation to perform really pure on some
> > overcommited scenarios.
> > While it is probably not possible to completely resolve this problem in
> > userspace only (without some kernel communication/intervention), removing
> > fairness in tail update can mitigate it significantly.
> > So this RFC proposes two new optional ring synchronization modes:
> > 1) Head/Tail Sync (HTS) mode
> > In that mode enqueue/dequeue operation is fully serialized:
> >     only one thread at a time is allowed to perform given op.
> >     As another enhancement provide ability to split enqueue/dequeue
> >     operation into two phases:
> >       - enqueue/dequeue start
> >       - enqueue/dequeue finish
> >     That allows user to inspect objects in the ring without removing
> >     them from it (aka MT safe peek).
> IMO, this will not address the problem described above.

It does, please see the results produced by ring_stress_*autotest below.
Let say for test-case: 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8' it shows:
avg number of cycles per object for enqueue /dequeue:
MP/MC: 280314.32
HTS:         294.72
RTS:         318.79

Customer who tried it reported similar level of improvement.
Actually if you have time - would be very interesting to see what numbers will be on ARM boxes.
To reproduce, just:
$cat ring_tests_u4
ring_stress_autotest
ring_stress_hts_autotest
ring_stress_rts_autotest

/app/test/dpdk-test --lcores='6,(10-13)@7,(20-23)@8'  -n 4 < ring_tests_u4 2>&1 | tee res1

Then look at the ' AGGREGATE' stats.
Right now it is a bit too verbose, so probably the easiest thing to extract same numbers quickly:
grep 'cycles/obj'  res1 | grep 'cycles/obj' | cat -n | awk '{if ($(1)%9==0) print $(NF);}'
280314.32
1057833.55
294.72
480.10
318.79
461.52

First 2 numbers will be for MP/MC, next 2 for HTS, last 2 for RTS.

> For ex: when a producer updates the head and gets scheduled out, other producers
> have to spin.

Sure, as I wrote in original cover letter:
" While it is probably not possible to completely resolve this problem in
userspace only (without some kernel communication/intervention),
removing fairness in tail update can mitigate it significantly."
Results from the ring_stress_*_autotest confirm that.

> The problem is probably worse as with non-HTS case moving of the head and copying of the ring elements can happen in
> parallel between the producers (similarly for consumers).

Yes as we serialize the ring, we remove possibility of simultaneous copy.
That's why for 'normal' cases (one thread per core) original MP/MC is usually faster.
Though on overcommitted scenarios current MP/MC performance degrades dramatically.
The main problem with current MP/MC implementation is in that tail update
have to be done in strict order (sort of fair locking scheme).
Which means that we have much-much worse LHP manifestation,
then when we use unfair schemes.
With serialized ring (HTS) we remove that ordering completely
(same idea as switch from fair to unfair locking for PV spin-locks).  

> IMO, HTS should not be a configurable flag. 

Why?

> In RCU requirement, a MP enqueue and HTS dequeue are required.

This is supported, user can specify different modes for consumer and producer:
(0 | RING_F_MC_HTS_DEQ).
Then it is up to the user either to call generic rte_ring_enqueue/rte_ring_dequeue,
or specify mode manually by function name:
rte_ring_mp_enqueue_bulk/ rte_ring_hts_dequeue_bulk.

> 
> > 2) Relaxed Tail Sync (RTS)
> > The main difference from original MP/MC algorithm is that tail value is
> > increased not by every thread that finished enqueue/dequeue, but only by the
> > last one.
> > That allows threads to avoid spinning on ring tail value, leaving actual tail value
> > change to the last thread in the update queue.
> This can be a configurable flag on the ring.
> I am not sure how this solves the problem you have stated above completely. Updating the count from all intermediate threads is still
> required to update the value of the head. But yes, it reduces the severity of the problem by not enforcing the order in which the tail is
> updated.

As I said above, main source of slowdown here -
that we have to  update tail in particular order.
So the main objective (same as for HTS) is to remove
that ordering.  

> I also think it introduces the problem on the other side of the ring because the tail is not updated soon enough (the other side has to wait
> longer for the elements to become available).

Yes, producer/consumer starvation.
That's why we need max allowed Head-Tail-Distance (htd_max) -
to limit how far head can go away from tail.

> It also introduces another configuration parameter (HTD_MAX_DEF) which they have to deal
> with.

If user doesn't provide any value, it will be set by default to ring.capacity / 8.
From my measurements works quite well.
Though there possibility for the user to set another value, if needed.

> Users have to still implement the current hypervisor related solutions.

Didn't get what you trying to say with that phrase.

> IMO, we should run the benchmark for this on an over committed setup to understand the benefits.

That's why I created ring_stress_*autotest test-cases and collected numbers provided below.
I suppose they clearly show the problem on overcommitted scenarios,
and how RTS/HTS improve that situation. 
Would appreciate if you repeat these tests on your machines. 

> 
> >
> > Test results on IA (see below) show significant improvements for average
> > enqueue/dequeue op times on overcommitted systems.
> > For 'classic' DPDK deployments (one thread per core) original MP/MC
> > algorithm still shows best numbers, though for 64-bit target RTS numbers are
> > not that far away.
> > Numbers were produced by ring_stress_*autotest (first patch in these series).
> >
> > X86_64 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> > DEQ+ENQ average cycles/obj
> >
> >                                                 MP/MC      HTS     RTS
> > 1thread@1core(--lcores=6-7)                     8.00       8.15    8.99
> > 2thread@2core(--lcores=6-8)                     19.14      19.61   20.35
> > 4thread@4core(--lcores=6-10)                    29.43      29.79   31.82
> > 8thread@8core(--lcores=6-14)                    110.59     192.81  119.50
> > 16thread@16core(--lcores=6-22)                  461.03     813.12  495.59
> > 32thread/@32core(--lcores='6-22,55-70')         982.90     1972.38 1160.51
> >
> > 2thread@1core(--lcores='6,(10-11)@7'            20140.50   23.58   25.14
> > 4thread@2core(--lcores='6,(10-11)@7,(20-21)@8'  153680.60  76.88   80.05
> > 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  280314.32  294.72  318.79
> > 16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 643176.59  1144.02
> > 1175.14 32thread@2core(--lcores='6,(10-25)@7,(30-45)@8' 4264238.80
> > 4627.48 4892.68
> >
> > 8thread@2core(--lcores='6,(10-17)@(7,8))'       321085.98  298.59  307.47
> > 16thread@4core(--lcores='6,(20-35)@(7-10))'     1900705.61 575.35  678.29
> > 32thread@4core(--lcores='6,(20-51)@(7-10))'     5510445.85 2164.36 2714.12
> >
> > i686 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> > DEQ+ENQ average cycles/obj
> >
> >                                                 MP/MC      HTS     RTS
> > 1thread@1core(--lcores=6-7)                     7.85       12.13   11.31
> > 2thread@2core(--lcores=6-8)                     17.89      24.52   21.86
> > 8thread@8core(--lcores=6-14)                    32.58      354.20  54.58
> > 32thread/@32core(--lcores='6-22,55-70')         813.77     6072.41 2169.91
> >
> > 2thread@1core(--lcores='6,(10-11)@7'            16095.00   36.06   34.74
> > 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  1140354.54 346.61  361.57
> > 16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 1920417.86 1314.90
> > 1416.65
> >
> > 8thread@2core(--lcores='6,(10-17)@(7,8))'       594358.61  332.70  357.74
> > 32thread@4core(--lcores='6,(20-51)@(7-10))'     5319896.86 2836.44 3028.87
> >
> > Konstantin Ananyev (6):
> >   test/ring: add contention stress test
> >   ring: rework ring layout to allow new sync schemes
> >   ring: introduce RTS ring mode
> >   test/ring: add contention stress test for RTS ring
> >   ring: introduce HTS ring mode
> >   test/ring: add contention stress test for HTS ring
> >
> >  app/test/Makefile                      |   3 +
> >  app/test/meson.build                   |   3 +
> >  app/test/test_pdump.c                  |   6 +-
> >  app/test/test_ring_hts_stress.c        |  28 ++
> >  app/test/test_ring_rts_stress.c        |  28 ++
> >  app/test/test_ring_stress.c            |  27 ++
> >  app/test/test_ring_stress.h            | 477 +++++++++++++++++++
> >  lib/librte_pdump/rte_pdump.c           |   2 +-
> >  lib/librte_port/rte_port_ring.c        |  12 +-
> >  lib/librte_ring/Makefile               |   4 +-
> >  lib/librte_ring/meson.build            |   4 +-
> >  lib/librte_ring/rte_ring.c             |  84 +++-
> >  lib/librte_ring/rte_ring.h             | 619 +++++++++++++++++++++++--
> >  lib/librte_ring/rte_ring_elem.h        |   8 +-
> >  lib/librte_ring/rte_ring_hts_generic.h | 228 +++++++++
> > lib/librte_ring/rte_ring_rts_generic.h | 240 ++++++++++
> >  16 files changed, 1721 insertions(+), 52 deletions(-)  create mode 100644
> > app/test/test_ring_hts_stress.c  create mode 100644
> > app/test/test_ring_rts_stress.c  create mode 100644
> > app/test/test_ring_stress.c  create mode 100644 app/test/test_ring_stress.h
> > create mode 100644 lib/librte_ring/rte_ring_hts_generic.h
> >  create mode 100644 lib/librte_ring/rte_ring_rts_generic.h
> >
> > --
> > 2.17.1


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [RFC] ring: make ring implementation non-inlined
  2020-03-25 21:09  4% ` Jerin Jacob
@ 2020-03-26  0:28  0%   ` Ananyev, Konstantin
  2020-03-26  8:04  4%   ` Morten Brørup
  1 sibling, 0 replies; 200+ results
From: Ananyev, Konstantin @ 2020-03-26  0:28 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: dpdk-dev, Olivier Matz, Honnappa Nagarahalli, Jerin Jacob,
	David Christensen, Stephen Hemminger

Hi Jerin,

> 
> On Fri, Mar 20, 2020 at 10:11 PM Konstantin Ananyev
> <konstantin.ananyev@intel.com> wrote:
> >
> > As was discussed here:
> > http://mails.dpdk.org/archives/dev/2020-February/158586.html
> > this RFC aimed to hide ring internals into .c and make all
> > ring functions non-inlined. In theory that might help to
> > maintain ABI stability in future.
> > This is just a POC to measure the impact of proposed idea,
> > proper implementation would definetly need some extra effort.
> > On IA box (SKX) ring_perf_autotest shows ~20-30 cycles extra for
> > enqueue+dequeue pair. On some more realistic code, I suspect
> > the impact it might be a bit higher.
> > For MP/MC bulk transfers degradation seems quite small,
> > though for SP/SC and/or small transfers it is more then noticable
> > (see exact numbers below).
> > From my perspective we'd probably keep it inlined for now
> > to avoid any non-anticipated perfomance degradations.
> > Though intersted to see perf results and opinions from
> > other interested parties.
> 
> +1
> 
> My reasoning is a bit different, DPDK is using in embedded boxes too
> where performance has
> more weight than ABI stuff. I think we need to focus first on slow
> path APIs ABI stuff.
> 
> I spend a few cycles to apply this patch +
> http://mails.dpdk.org/archives/dev/2020-February/158586.html
> on top of the tree, there are a lot of conflicts. If I get a mergeable
> patch then I will test it on an arm64 box.

You don’t need to apply previous patch series.
They are completely unrelated.
Just apply that one (http://patches.dpdk.org/patch/66982/)
on top of dpdk.org master.
It should be applied cleanly (at least it does for me). 
Konstantin


> 
> 
> 
> 
> 
> >
> > Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> > ring_perf_autotest (without patch/with patch)

^ permalink raw reply	[relevance 0%]

* [dpdk-dev]  [PATCH v2 00/32] DPDK Trace support
  @ 2020-03-25 21:15  1% ` jerinj
  2020-03-29 14:43  1%   ` [dpdk-dev] [PATCH v3 00/33] " jerinj
  0 siblings, 1 reply; 200+ results
From: jerinj @ 2020-03-25 21:15 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson, david.marchand, mattias.ronnblom,
	skori, Jerin Jacob

From: Jerin Jacob <jerinj@marvell.com>

v2:

Addressed the following review comments from Mattias Rönnblom:

1) Changed 

from:
typedef uint64_t* rte_trace_t;
to
typedef uint64_t rte_trace_t;

Initially thought to make the handle as
struct rte_trace {
    uint64_t val;
}

but changed to uint64_t for the following reasons
a) It is opaque to the application and it will fix the compile-time type
check as well.
b) The handle has an index that will point to an internal slow-path
structure so no ABI change required in the future.
c) RTE_TRACE_POINT_DEFINE need to expose trace object. So it is better
to keep as uint64_t and avoid one more indirection for no use.

2)
Changed:
from:
enum rte_trace_mode_e {
to:
enum rte_trace_mode {


3) removed [out] "found" param from rte_trace_pattern() and
rte_trace_regexp()


4) Changed rte_trace_from_name to rte_trace_by_name

5) rte_trace_is_dp_enabled() return bool now


6) in __rte_trace_point_register() the argument fn change to register_fn

7) removed !! from rte_trace_is_enabled()

8) Remove uninitialized "rc warning" from rte_trace_pattern() and
rte_trace_regexp()

9) fixup bool return type for trace_entry_compare()

10) fixup calloc casting in trace_mkdir()

11) check fclose() return in trace_meta_save() and trace_mem_save()

12) rte_trace_ctf_* macro cleanup

13) added release notes

14) fix build issues reported by CI
http://mails.dpdk.org/archives/test-report/2020-March/121235.html


This patch set contains 
~~~~~~~~~~~~~~~~~~~~~~~~

# The native implementation of common trace format(CTF)[1] based tracer
# Public API to create the trace points.
# Add tracepoints to eal, ethdev, mempool, eventdev and cryptodev 
library for tracing support
# A unit test case
# Performance test case to measure the trace overhead. (See eal/trace:
# add trace performance test cases, patch)
# Programmers guide for Trace support(See doc: add trace library guide,
# patch)

# Tested OS:
~~~~~~~~~~~
- Linux
- FreeBSD

# Tested open source CTF trace viewers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Babeltrace
- Tracecompass

# Trace overhead comparison with LTTng
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

trace overhead data on x86:[2]
# 236 cycles with LTTng(>100ns)
# 18 cycles(7ns) with Native DPDK CTF emitter.(See eal/trace: add trace
# performance test cases patch)

trace overhead data on arm64:
#  312  cycles to  1100 cycles with LTTng based on the class of arm64
#  CPU.
#  11 cycles to 13 cycles with Native DPDK CTF emitter based on the
class of arm64 CPU.

18 cycles(on x86) vs 11 cycles(on arm64) is due to rdtsc() overhead in
x86. It seems  rdtsc takes around 15cycles in x86.


Items that needs to be sort it out 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Makefile and meson.build are updated to allow experimental APIs.

As multiple EXPERIMENTAL symbols, exported by trace library, are
used in various drivers, lib, app and examples. So to fix compilation
warning/error, Makefile and meson.build are updated for all required
components to support EXPERIMENTAL APIs.
It results same code changes at multiple components as well as
increases source code line changes in patchset too.
Suggestions are welcome to resolve this issue with lesser code changes.
	
More details:
~~~~~~~~~~~~~

# The Native DPDK CTF trace support does not have any dependency on
third-party library.
The generated output file is compatible with LTTng as both are using
CTF trace format.

The performance gain comes from:
1) exploit dpdk worker thread usage model to avoid atomics and use per
core variables
2) use hugepage,
3) avoid a lot function pointers in fast-path etc
4) avoid unaligned store for arm64 etc

Features:
~~~~~~~~~
- APIs and Features are similar to rte_log dynamic framework
API(expect log prints on stdout vs it dumps on trace file)
- No specific limit on the events. A string-based event like rte_log
for pattern matching
- Dynamic enable/disable support.
- Instructmention overhead is ~1 cycle. i.e cost of adding the code
wth out using trace feature.
- Timestamp support for all the events using DPDK rte_rtdsc
- No dependency on another library. Clean room native implementation of
  CTF.

Functional test case:
a) echo "trace_autotest" | sudo ./build/app/test/dpdk-test  -c 0x3
--trace-level=8

The above command emits the following trace events
<code>
        uint8_t i;

        rte_trace_lib_eal_generic_void();
        rte_trace_lib_eal_generic_u64(0x10000000000000);
        rte_trace_lib_eal_generic_u32(0x10000000);
        rte_trace_lib_eal_generic_u16(0xffee);
        rte_trace_lib_eal_generic_u8(0xc);
        rte_trace_lib_eal_generic_i64(-1234);
        rte_trace_lib_eal_generic_i32(-1234567);
        rte_trace_lib_eal_generic_i16(12);
        rte_trace_lib_eal_generic_i8(-3);
        rte_trace_lib_eal_generic_string("my string");
        rte_trace_lib_eal_generic_function(__func__);

        for (i = 0; i < 128; i++)
                rte_trace_lib_eal_generic_u8(i);
</code>

Install babeltrace package in Linux and point the generated trace file
to babel trace. By default trace file created under
<user>/dpdk-traces/time_stamp/

example:
# babeltrace /root/dpdk-traces/rte-2020-02-15-PM-02-56-51 | more

[13:27:36.138468807] (+?.?????????) lib.eal.generic.void: { cpu_id =
0, name = "dpdk-test" }, { }
[13:27:36.138468851] (+0.000000044) lib.eal.generic.u64: { cpu_id = 0,
name = "dpdk-test" }, { in = 4503599627370496 }
[13:27:36.138468860] (+0.000000009) lib.eal.generic.u32: { cpu_id = 0,
name = "dpdk-test" }, { in = 268435456 }
[13:27:36.138468934] (+0.000000074) lib.eal.generic.u16: { cpu_id = 0,
name = "dpdk-test" }, { in = 65518 }
[13:27:36.138468949] (+0.000000015) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 12 }
[13:27:36.138468956] (+0.000000007) lib.eal.generic.i64: { cpu_id = 0,
name = "dpdk-test" }, { in = -1234 }
[13:27:36.138468963] (+0.000000007) lib.eal.generic.i32: { cpu_id = 0,
name = "dpdk-test" }, { in = -1234567 }
[13:27:36.138469024] (+0.000000061) lib.eal.generic.i16: { cpu_id = 0,
name = "dpdk-test" }, { in = 12 }
[13:27:36.138469044] (+0.000000020) lib.eal.generic.i8: { cpu_id = 0,
name = "dpdk-test" }, { in = -3 }
[13:27:36.138469051] (+0.000000007) lib.eal.generic.string: { cpu_id =
0, name = "dpdk-test" }, { str = "my string" }
[13:27:36.138469203] (+0.000000152) lib.eal.generic.func: { cpu_id =
0, name = "dpdk-test" }, { func = "test_trace_points" }
[13:27:36.138469239] (+0.000000036) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 0 }
[13:27:36.138469246] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 1 }
[13:27:36.138469252] (+0.000000006) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 2 }
[13:27:36.138469262] (+0.000000010) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 3 }
[13:27:36.138469269] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 4 }
[13:27:36.138469276] (+0.000000007) lib.eal.generic.u8: { cpu_id = 0,
name = "dpdk-test" }, { in = 5 }

# There is a  GUI based trace viewer available in Windows, Linux and
# Mac.
It is called as tracecompass.(https://www.eclipse.org/tracecompass/)

The example screenshot and Histogram of above DPDK trace using
Tracecompass.

https://github.com/jerinjacobk/share/blob/master/dpdk_trace.JPG



File walk through:
~~~~~~~~~~~~~~~~~~

lib/librte_eal/common/include/rte_trace.h - Public API for Trace
provider and Trace control
lib/librte_eal/common/eal_common_trace.c - main trace implementation
lib/librte_eal/common/eal_common_trace_ctf.c - CTF metadata spec
implementation
lib/librte_eal/common/eal_common_trace_utils.c - command line utils
and filesystem operations.
lib/librte_eal/common/eal_common_trace_points.c -  trace points for EAL
library
lib/librte_eal/common/include/rte_trace_eal.h - EAL tracepoint public
API.
lib/librte_eal/common/eal_trace.h - Private trace header file.


[1] https://diamon.org/ctf/

[2] The above test is ported to LTTng for finding the LTTng trace
overhead. It available at
https://github.com/jerinjacobk/lttng-overhead
https://github.com/jerinjacobk/lttng-overhead/blob/master/README

Jerin Jacob (21):
  eal: introduce API for getting thread name
  eal: define the public API for trace support
  eal/trace: implement trace register API
  eal/trace: implement trace operation APIs
  eal/trace: add internal trace init and fini interface
  eal/trace: get bootup timestamp for trace
  eal/trace: create CTF TDSL metadata in memory
  eal/trace: implement trace memory allocation
  eal/trace: implement debug dump function
  eal/trace: implement trace save
  eal/trace: implement registration payload
  eal/trace: implement provider payload
  eal/trace: hook internal trace APIs to Linux
  eal/trace: hook internal trace APIs to FreeBSD
  eal/trace: add generic tracepoints
  eal/trace: add alarm tracepoints
  eal/trace: add memory tracepoints
  eal/trace: add memzone tracepoints
  eal/trace: add thread tracepoints
  eal/trace: add interrupt tracepoints
  eal/trace: add trace performance test cases

Sunil Kumar Kori (11):
  eal/trace: handle CTF keyword collision
  eal/trace: add trace level configuration parameter
  eal/trace: add trace dir configuration parameter
  eal/trace: add trace bufsize configuration parameter
  eal/trace: add trace mode configuration parameter
  eal/trace: add unit test cases
  ethdev: add tracepoints
  eventdev: add tracepoints
  cryptodev: add tracepoints
  mempool: add tracepoints
  doc: add trace library guide

 MAINTAINERS                                   |  15 +
 app/pdump/Makefile                            |   1 +
 app/pdump/meson.build                         |   1 +
 app/proc-info/Makefile                        |   1 +
 app/proc-info/meson.build                     |   1 +
 app/test-acl/Makefile                         |   1 +
 app/test-acl/meson.build                      |   1 +
 app/test-cmdline/Makefile                     |   1 +
 app/test-cmdline/meson.build                  |   1 +
 app/test-eventdev/Makefile                    |   1 +
 app/test-eventdev/meson.build                 |   1 +
 app/test-pipeline/Makefile                    |   1 +
 app/test-pipeline/meson.build                 |   1 +
 app/test/Makefile                             |   4 +-
 app/test/meson.build                          |   3 +
 app/test/test_trace.c                         | 618 ++++++++++++++++++
 app/test/test_trace.h                         |  52 ++
 app/test/test_trace_perf.c                    | 179 +++++
 app/test/test_trace_register.c                |  46 ++
 config/common_base                            |   1 +
 config/rte_config.h                           |   1 +
 doc/api/doxy-api-index.md                     |   3 +-
 doc/guides/linux_gsg/eal_args.include.rst     |  55 ++
 doc/guides/prog_guide/index.rst               |   1 +
 doc/guides/prog_guide/trace_lib.rst           | 265 ++++++++
 doc/guides/rel_notes/release_20_05.rst        |   9 +
 drivers/common/cpt/Makefile                   |   1 +
 drivers/crypto/ccp/Makefile                   |   1 +
 drivers/crypto/ccp/meson.build                |   2 +
 drivers/crypto/mvsam/Makefile                 |   1 +
 drivers/crypto/mvsam/meson.build              |   1 +
 drivers/crypto/null/Makefile                  |   1 +
 drivers/crypto/null/meson.build               |   1 +
 drivers/crypto/scheduler/Makefile             |   1 +
 drivers/crypto/scheduler/meson.build          |   1 +
 drivers/crypto/virtio/Makefile                |   1 +
 drivers/crypto/virtio/meson.build             |   1 +
 drivers/event/octeontx/Makefile               |   1 +
 drivers/event/octeontx/meson.build            |   1 +
 drivers/event/skeleton/Makefile               |   1 +
 drivers/event/skeleton/meson.build            |   1 +
 drivers/event/sw/Makefile                     |   1 +
 drivers/event/sw/meson.build                  |   1 +
 drivers/mempool/ring/Makefile                 |   1 +
 drivers/mempool/ring/meson.build              |   1 +
 drivers/net/af_packet/Makefile                |   1 +
 drivers/net/af_packet/meson.build             |   1 +
 drivers/net/af_xdp/Makefile                   |   1 +
 drivers/net/af_xdp/meson.build                |   1 +
 drivers/net/ark/Makefile                      |   1 +
 drivers/net/ark/meson.build                   |   1 +
 drivers/net/bnxt/Makefile                     |   1 +
 drivers/net/bnxt/meson.build                  |   1 +
 drivers/net/cxgbe/Makefile                    |   1 +
 drivers/net/cxgbe/meson.build                 |   1 +
 drivers/net/enetc/Makefile                    |   1 +
 drivers/net/enetc/meson.build                 |   1 +
 drivers/net/hinic/Makefile                    |   1 +
 drivers/net/hinic/base/meson.build            |   3 +-
 drivers/net/hinic/meson.build                 |   1 +
 drivers/net/ionic/ionic_dev.c                 |   1 +
 drivers/net/ionic/ionic_mac_api.c             |   1 +
 drivers/net/ionic/ionic_main.c                |   1 +
 drivers/net/kni/Makefile                      |   1 +
 drivers/net/kni/meson.build                   |   1 +
 drivers/net/liquidio/Makefile                 |   1 +
 drivers/net/liquidio/meson.build              |   1 +
 drivers/net/mvneta/Makefile                   |   1 +
 drivers/net/mvneta/meson.build                |   1 +
 drivers/net/mvpp2/Makefile                    |   1 +
 drivers/net/mvpp2/meson.build                 |   1 +
 drivers/net/nfb/Makefile                      |   1 +
 drivers/net/nfb/meson.build                   |   1 +
 drivers/net/null/Makefile                     |   1 +
 drivers/net/null/meson.build                  |   1 +
 drivers/net/octeontx/Makefile                 |   1 +
 drivers/net/octeontx2/Makefile                |   1 +
 drivers/net/octeontx2/meson.build             |   1 +
 drivers/net/pcap/Makefile                     |   1 +
 drivers/net/pcap/meson.build                  |   1 +
 drivers/net/ring/Makefile                     |   1 +
 drivers/net/ring/meson.build                  |   1 +
 drivers/net/szedata2/Makefile                 |   1 +
 drivers/net/szedata2/meson.build              |   1 +
 drivers/net/thunderx/base/meson.build         |   1 +
 drivers/net/vhost/Makefile                    |   1 +
 drivers/net/vhost/meson.build                 |   1 +
 drivers/raw/ioat/Makefile                     |   1 +
 drivers/raw/ioat/meson.build                  |   1 +
 drivers/raw/octeontx2_dma/Makefile            |   1 +
 drivers/raw/octeontx2_dma/meson.build         |   1 +
 drivers/raw/octeontx2_ep/Makefile             |   1 +
 drivers/raw/octeontx2_ep/meson.build          |   1 +
 drivers/raw/skeleton/Makefile                 |   1 +
 drivers/raw/skeleton/meson.build              |   1 +
 examples/cmdline/Makefile                     |   1 +
 examples/cmdline/meson.build                  |   1 +
 examples/distributor/Makefile                 |   1 +
 examples/distributor/meson.build              |   1 +
 examples/ethtool/ethtool-app/Makefile         |   1 +
 examples/eventdev_pipeline/meson.build        |   1 +
 examples/flow_filtering/Makefile              |   1 +
 examples/flow_filtering/meson.build           |   1 +
 examples/helloworld/Makefile                  |   1 +
 examples/helloworld/meson.build               |   1 +
 examples/ioat/Makefile                        |   1 +
 examples/ioat/meson.build                     |   1 +
 examples/ip_fragmentation/Makefile            |   2 +
 examples/ip_fragmentation/meson.build         |   1 +
 examples/ip_reassembly/Makefile               |   1 +
 examples/ip_reassembly/meson.build            |   1 +
 examples/ipv4_multicast/Makefile              |   1 +
 examples/ipv4_multicast/meson.build           |   1 +
 examples/l2fwd-cat/Makefile                   |   1 +
 examples/l2fwd-cat/meson.build                |   1 +
 examples/l2fwd-event/Makefile                 |   1 +
 examples/l2fwd-event/meson.build              |   1 +
 examples/l2fwd-jobstats/Makefile              |   1 +
 examples/l2fwd-jobstats/meson.build           |   1 +
 examples/l2fwd-keepalive/Makefile             |   1 +
 examples/l2fwd-keepalive/ka-agent/Makefile    |   1 +
 examples/l2fwd-keepalive/meson.build          |   1 +
 examples/l3fwd-acl/Makefile                   |   1 +
 examples/l3fwd-acl/meson.build                |   1 +
 examples/l3fwd/Makefile                       |   1 +
 examples/l3fwd/meson.build                    |   1 +
 examples/link_status_interrupt/Makefile       |   1 +
 examples/link_status_interrupt/meson.build    |   1 +
 .../client_server_mp/mp_client/Makefile       |   1 +
 .../client_server_mp/mp_client/meson.build    |   1 +
 .../client_server_mp/mp_server/meson.build    |   1 +
 examples/multi_process/hotplug_mp/Makefile    |   1 +
 examples/multi_process/hotplug_mp/meson.build |   1 +
 examples/multi_process/simple_mp/Makefile     |   1 +
 examples/multi_process/simple_mp/meson.build  |   1 +
 examples/multi_process/symmetric_mp/Makefile  |   1 +
 .../multi_process/symmetric_mp/meson.build    |   1 +
 examples/ntb/Makefile                         |   1 +
 examples/ntb/meson.build                      |   1 +
 examples/packet_ordering/Makefile             |   1 +
 examples/packet_ordering/meson.build          |   1 +
 .../performance-thread/l3fwd-thread/Makefile  |   1 +
 .../l3fwd-thread/meson.build                  |   1 +
 .../performance-thread/pthread_shim/Makefile  |   1 +
 .../pthread_shim/meson.build                  |   1 +
 examples/ptpclient/Makefile                   |   1 +
 examples/ptpclient/meson.build                |   1 +
 examples/qos_meter/Makefile                   |   1 +
 examples/qos_meter/meson.build                |   1 +
 examples/qos_sched/Makefile                   |   1 +
 examples/qos_sched/meson.build                |   1 +
 examples/server_node_efd/node/Makefile        |   1 +
 examples/server_node_efd/node/meson.build     |   1 +
 examples/server_node_efd/server/Makefile      |   1 +
 examples/server_node_efd/server/meson.build   |   1 +
 examples/service_cores/Makefile               |   1 +
 examples/service_cores/meson.build            |   1 +
 examples/skeleton/Makefile                    |   1 +
 examples/skeleton/meson.build                 |   1 +
 examples/timer/Makefile                       |   1 +
 examples/timer/meson.build                    |   1 +
 examples/vm_power_manager/Makefile            |   1 +
 examples/vm_power_manager/meson.build         |   1 +
 examples/vmdq/Makefile                        |   1 +
 examples/vmdq/meson.build                     |   1 +
 examples/vmdq_dcb/Makefile                    |   1 +
 examples/vmdq_dcb/meson.build                 |   1 +
 lib/librte_bitratestats/Makefile              |   1 +
 lib/librte_bitratestats/meson.build           |   1 +
 lib/librte_cryptodev/Makefile                 |   4 +-
 lib/librte_cryptodev/cryptodev_trace_points.c |  70 ++
 lib/librte_cryptodev/meson.build              |   7 +-
 lib/librte_cryptodev/rte_cryptodev.c          |  18 +
 lib/librte_cryptodev/rte_cryptodev.h          |   6 +
 .../rte_cryptodev_version.map                 |  18 +
 lib/librte_cryptodev/rte_trace_cryptodev.h    | 133 ++++
 lib/librte_cryptodev/rte_trace_cryptodev_fp.h |  34 +
 lib/librte_distributor/Makefile               |   1 +
 lib/librte_distributor/meson.build            |   1 +
 lib/librte_eal/common/Makefile                |   1 +
 lib/librte_eal/common/eal_common_log.c        |   9 +-
 lib/librte_eal/common/eal_common_memzone.c    |   9 +
 lib/librte_eal/common/eal_common_options.c    |  68 +-
 lib/librte_eal/common/eal_common_thread.c     |   3 +-
 lib/librte_eal/common/eal_common_trace.c      | 610 +++++++++++++++++
 lib/librte_eal/common/eal_common_trace_ctf.c  | 488 ++++++++++++++
 .../common/eal_common_trace_points.c          | 115 ++++
 .../common/eal_common_trace_utils.c           | 523 +++++++++++++++
 lib/librte_eal/common/eal_options.h           |   8 +
 lib/librte_eal/common/eal_private.h           |  11 +
 lib/librte_eal/common/eal_trace.h             | 122 ++++
 lib/librte_eal/common/include/rte_lcore.h     |  17 +
 lib/librte_eal/common/include/rte_trace.h     | 584 +++++++++++++++++
 lib/librte_eal/common/include/rte_trace_eal.h | 247 +++++++
 .../common/include/rte_trace_provider.h       | 137 ++++
 .../common/include/rte_trace_register.h       |  53 ++
 lib/librte_eal/common/meson.build             |   8 +
 lib/librte_eal/common/rte_malloc.c            |  60 +-
 lib/librte_eal/freebsd/eal/Makefile           |   4 +
 lib/librte_eal/freebsd/eal/eal.c              |  10 +
 lib/librte_eal/freebsd/eal/eal_alarm.c        |   3 +
 lib/librte_eal/freebsd/eal/eal_interrupts.c   |  52 +-
 lib/librte_eal/freebsd/eal/eal_thread.c       |  21 +-
 lib/librte_eal/linux/eal/Makefile             |   4 +
 lib/librte_eal/linux/eal/eal.c                |   9 +
 lib/librte_eal/linux/eal/eal_alarm.c          |   4 +
 lib/librte_eal/linux/eal/eal_interrupts.c     |  84 ++-
 lib/librte_eal/linux/eal/eal_thread.c         |  27 +-
 lib/librte_eal/rte_eal_version.map            |  61 ++
 lib/librte_ethdev/Makefile                    |   3 +
 lib/librte_ethdev/ethdev_trace_points.c       |  43 ++
 lib/librte_ethdev/meson.build                 |   5 +-
 lib/librte_ethdev/rte_ethdev.c                |  12 +
 lib/librte_ethdev/rte_ethdev.h                |   5 +
 lib/librte_ethdev/rte_ethdev_version.map      |  10 +
 lib/librte_ethdev/rte_trace_ethdev.h          |  90 +++
 lib/librte_ethdev/rte_trace_ethdev_fp.h       |  40 ++
 lib/librte_eventdev/Makefile                  |   3 +
 lib/librte_eventdev/eventdev_trace_points.c   | 173 +++++
 lib/librte_eventdev/meson.build               |   3 +
 .../rte_event_crypto_adapter.c                |  10 +
 .../rte_event_eth_rx_adapter.c                |  11 +
 .../rte_event_eth_tx_adapter.c                |  13 +-
 .../rte_event_eth_tx_adapter.h                |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c |   8 +-
 lib/librte_eventdev/rte_event_timer_adapter.h |   8 +
 lib/librte_eventdev/rte_eventdev.c            |   9 +
 lib/librte_eventdev/rte_eventdev.h            |   5 +-
 lib/librte_eventdev/rte_eventdev_version.map  |  42 ++
 lib/librte_eventdev/rte_trace_eventdev.h      | 278 ++++++++
 lib/librte_eventdev/rte_trace_eventdev_fp.h   |  75 +++
 lib/librte_gro/Makefile                       |   1 +
 lib/librte_gro/meson.build                    |   1 +
 lib/librte_gso/Makefile                       |   1 +
 lib/librte_gso/meson.build                    |   1 +
 lib/librte_ip_frag/Makefile                   |   1 +
 lib/librte_ip_frag/meson.build                |   1 +
 lib/librte_kni/Makefile                       |   1 +
 lib/librte_kni/meson.build                    |   1 +
 lib/librte_latencystats/Makefile              |   1 +
 lib/librte_latencystats/meson.build           |   1 +
 lib/librte_mempool/Makefile                   |   3 +
 lib/librte_mempool/mempool_trace_points.c     | 108 +++
 lib/librte_mempool/meson.build                |   7 +-
 lib/librte_mempool/rte_mempool.c              |  16 +
 lib/librte_mempool/rte_mempool.h              |  13 +
 lib/librte_mempool/rte_mempool_ops.c          |   7 +
 lib/librte_mempool/rte_mempool_version.map    |  26 +
 lib/librte_mempool/rte_trace_mempool.h        | 148 +++++
 lib/librte_mempool/rte_trace_mempool_fp.h     | 102 +++
 lib/librte_port/Makefile                      |   1 +
 lib/librte_port/meson.build                   |   1 +
 lib/librte_reorder/Makefile                   |   1 +
 lib/librte_reorder/meson.build                |   1 +
 lib/librte_sched/Makefile                     |   1 +
 lib/librte_sched/meson.build                  |   1 +
 lib/librte_security/Makefile                  |   1 +
 lib/librte_security/meson.build               |   1 +
 lib/librte_table/Makefile                     |   1 +
 lib/librte_table/meson.build                  |   1 +
 260 files changed, 6271 insertions(+), 82 deletions(-)
 create mode 100644 app/test/test_trace.c
 create mode 100644 app/test/test_trace.h
 create mode 100644 app/test/test_trace_perf.c
 create mode 100644 app/test/test_trace_register.c
 create mode 100644 doc/guides/prog_guide/trace_lib.rst
 create mode 100644 lib/librte_cryptodev/cryptodev_trace_points.c
 create mode 100644 lib/librte_cryptodev/rte_trace_cryptodev.h
 create mode 100644 lib/librte_cryptodev/rte_trace_cryptodev_fp.h
 create mode 100644 lib/librte_eal/common/eal_common_trace.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_ctf.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_points.c
 create mode 100644 lib/librte_eal/common/eal_common_trace_utils.c
 create mode 100644 lib/librte_eal/common/eal_trace.h
 create mode 100644 lib/librte_eal/common/include/rte_trace.h
 create mode 100644 lib/librte_eal/common/include/rte_trace_eal.h
 create mode 100644 lib/librte_eal/common/include/rte_trace_provider.h
 create mode 100644 lib/librte_eal/common/include/rte_trace_register.h
 create mode 100644 lib/librte_ethdev/ethdev_trace_points.c
 create mode 100644 lib/librte_ethdev/rte_trace_ethdev.h
 create mode 100644 lib/librte_ethdev/rte_trace_ethdev_fp.h
 create mode 100644 lib/librte_eventdev/eventdev_trace_points.c
 create mode 100644 lib/librte_eventdev/rte_trace_eventdev.h
 create mode 100644 lib/librte_eventdev/rte_trace_eventdev_fp.h
 create mode 100644 lib/librte_mempool/mempool_trace_points.c
 create mode 100644 lib/librte_mempool/rte_trace_mempool.h
 create mode 100644 lib/librte_mempool/rte_trace_mempool_fp.h

-- 
2.25.1


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [RFC] ring: make ring implementation non-inlined
  2020-03-20 16:41  3% [dpdk-dev] [RFC] ring: make ring implementation non-inlined Konstantin Ananyev
  2020-03-20 17:54  0% ` Stephen Hemminger
@ 2020-03-25 21:09  4% ` Jerin Jacob
  2020-03-26  0:28  0%   ` Ananyev, Konstantin
  2020-03-26  8:04  4%   ` Morten Brørup
  1 sibling, 2 replies; 200+ results
From: Jerin Jacob @ 2020-03-25 21:09 UTC (permalink / raw)
  To: Konstantin Ananyev
  Cc: dpdk-dev, Olivier Matz, Honnappa Nagarahalli, Jerin Jacob,
	David Christensen, Stephen Hemminger

On Fri, Mar 20, 2020 at 10:11 PM Konstantin Ananyev
<konstantin.ananyev@intel.com> wrote:
>
> As was discussed here:
> http://mails.dpdk.org/archives/dev/2020-February/158586.html
> this RFC aimed to hide ring internals into .c and make all
> ring functions non-inlined. In theory that might help to
> maintain ABI stability in future.
> This is just a POC to measure the impact of proposed idea,
> proper implementation would definetly need some extra effort.
> On IA box (SKX) ring_perf_autotest shows ~20-30 cycles extra for
> enqueue+dequeue pair. On some more realistic code, I suspect
> the impact it might be a bit higher.
> For MP/MC bulk transfers degradation seems quite small,
> though for SP/SC and/or small transfers it is more then noticable
> (see exact numbers below).
> From my perspective we'd probably keep it inlined for now
> to avoid any non-anticipated perfomance degradations.
> Though intersted to see perf results and opinions from
> other interested parties.

+1

My reasoning is a bit different, DPDK is using in embedded boxes too
where performance has
more weight than ABI stuff. I think we need to focus first on slow
path APIs ABI stuff.

I spend a few cycles to apply this patch +
http://mails.dpdk.org/archives/dev/2020-February/158586.html
on top of the tree, there are a lot of conflicts. If I get a mergeable
patch then I will test it on an arm64 box.





>
> Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> ring_perf_autotest (without patch/with patch)

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 11:35  2% [dpdk-dev] [RFC 0/6] New sync modes for ring Konstantin Ananyev
  2020-02-24 16:59  0% ` Stephen Hemminger
@ 2020-03-25 20:43  0% ` Honnappa Nagarahalli
  2020-03-26  1:50  3%   ` Ananyev, Konstantin
  2020-03-31 16:43  3% ` [dpdk-dev] [PATCH v1 0/8] " Konstantin Ananyev
  2 siblings, 1 reply; 200+ results
From: Honnappa Nagarahalli @ 2020-03-25 20:43 UTC (permalink / raw)
  To: Konstantin Ananyev, dev; +Cc: olivier.matz, nd, Honnappa Nagarahalli, nd

<snip>

> Subject: [dpdk-dev] [RFC 0/6] New sync modes for ring
> 
> Upfront note - that RFC is not a complete patch.
> It introduces an ABI breakage, plus it doesn't update ring_elem code properly,
As per the current rules, these changes (in the current form) will be accepted only for 20.11 release. How do we address this for immediate requirements like RCU defer APIs? 
I suggest that we move forward with my RFC (taking into consideration your feedback) to make progress on RCU APIs.

> etc.
> I plan to deal with all these things in later versions.
> Right now I seek an initial feedback about proposed ideas.
> Would also ask people to repeat performance tests (see below) on their
> platforms to confirm the impact.
> 
> More and more customers use(/try to use) DPDK based apps within
> overcommitted systems (multiple acttive threads over same pysical cores):
> VM, container deployments, etc.
> One quite common problem they hit: Lock-Holder-Preemption with rte_ring.
> LHP is quite a common problem for spin-based sync primitives (spin-locks, etc.)
> on overcommitted systems.
> The situation gets much worse when some sort of fair-locking technique is
> used (ticket-lock, etc.).
> As now not only lock-owner but also lock-waiters scheduling order matters a
> lot.
> This is a well-known problem for kernel within VMs:
> http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> The problem with rte_ring is that while head accusion is sort of un-fair locking,
> waiting on tail is very similar to ticket lock schema - tail has to be updated in
> particular order.
> That makes current rte_ring implementation to perform really pure on some
> overcommited scenarios.
> While it is probably not possible to completely resolve this problem in
> userspace only (without some kernel communication/intervention), removing
> fairness in tail update can mitigate it significantly.
> So this RFC proposes two new optional ring synchronization modes:
> 1) Head/Tail Sync (HTS) mode
> In that mode enqueue/dequeue operation is fully serialized:
>     only one thread at a time is allowed to perform given op.
>     As another enhancement provide ability to split enqueue/dequeue
>     operation into two phases:
>       - enqueue/dequeue start
>       - enqueue/dequeue finish
>     That allows user to inspect objects in the ring without removing
>     them from it (aka MT safe peek).
IMO, this will not address the problem described above. For ex: when a producer updates the head and gets scheduled out, other producers have to spin. The problem is probably worse as with non-HTS case moving of the head and copying of the ring elements can happen in parallel between the producers (similarly for consumers).
IMO, HTS should not be a configurable flag. In RCU requirement, a MP enqueue and HTS dequeue are required.

> 2) Relaxed Tail Sync (RTS)
> The main difference from original MP/MC algorithm is that tail value is
> increased not by every thread that finished enqueue/dequeue, but only by the
> last one.
> That allows threads to avoid spinning on ring tail value, leaving actual tail value
> change to the last thread in the update queue.
This can be a configurable flag on the ring.
I am not sure how this solves the problem you have stated above completely. Updating the count from all intermediate threads is still required to update the value of the head. But yes, it reduces the severity of the problem by not enforcing the order in which the tail is updated.
I also think it introduces the problem on the other side of the ring because the tail is not updated soon enough (the other side has to wait longer for the elements to become available). It also introduces another configuration parameter (HTD_MAX_DEF) which they have to deal with.
Users have to still implement the current hypervisor related solutions.
IMO, we should run the benchmark for this on an over committed setup to understand the benefits.

> 
> Test results on IA (see below) show significant improvements for average
> enqueue/dequeue op times on overcommitted systems.
> For 'classic' DPDK deployments (one thread per core) original MP/MC
> algorithm still shows best numbers, though for 64-bit target RTS numbers are
> not that far away.
> Numbers were produced by ring_stress_*autotest (first patch in these series).
> 
> X86_64 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> DEQ+ENQ average cycles/obj
> 
>                                                 MP/MC      HTS     RTS
> 1thread@1core(--lcores=6-7)                     8.00       8.15    8.99
> 2thread@2core(--lcores=6-8)                     19.14      19.61   20.35
> 4thread@4core(--lcores=6-10)                    29.43      29.79   31.82
> 8thread@8core(--lcores=6-14)                    110.59     192.81  119.50
> 16thread@16core(--lcores=6-22)                  461.03     813.12  495.59
> 32thread/@32core(--lcores='6-22,55-70')         982.90     1972.38 1160.51
> 
> 2thread@1core(--lcores='6,(10-11)@7'            20140.50   23.58   25.14
> 4thread@2core(--lcores='6,(10-11)@7,(20-21)@8'  153680.60  76.88   80.05
> 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  280314.32  294.72  318.79
> 16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 643176.59  1144.02
> 1175.14 32thread@2core(--lcores='6,(10-25)@7,(30-45)@8' 4264238.80
> 4627.48 4892.68
> 
> 8thread@2core(--lcores='6,(10-17)@(7,8))'       321085.98  298.59  307.47
> 16thread@4core(--lcores='6,(20-35)@(7-10))'     1900705.61 575.35  678.29
> 32thread@4core(--lcores='6,(20-51)@(7-10))'     5510445.85 2164.36 2714.12
> 
> i686 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> DEQ+ENQ average cycles/obj
> 
>                                                 MP/MC      HTS     RTS
> 1thread@1core(--lcores=6-7)                     7.85       12.13   11.31
> 2thread@2core(--lcores=6-8)                     17.89      24.52   21.86
> 8thread@8core(--lcores=6-14)                    32.58      354.20  54.58
> 32thread/@32core(--lcores='6-22,55-70')         813.77     6072.41 2169.91
> 
> 2thread@1core(--lcores='6,(10-11)@7'            16095.00   36.06   34.74
> 8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  1140354.54 346.61  361.57
> 16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 1920417.86 1314.90
> 1416.65
> 
> 8thread@2core(--lcores='6,(10-17)@(7,8))'       594358.61  332.70  357.74
> 32thread@4core(--lcores='6,(20-51)@(7-10))'     5319896.86 2836.44 3028.87
> 
> Konstantin Ananyev (6):
>   test/ring: add contention stress test
>   ring: rework ring layout to allow new sync schemes
>   ring: introduce RTS ring mode
>   test/ring: add contention stress test for RTS ring
>   ring: introduce HTS ring mode
>   test/ring: add contention stress test for HTS ring
> 
>  app/test/Makefile                      |   3 +
>  app/test/meson.build                   |   3 +
>  app/test/test_pdump.c                  |   6 +-
>  app/test/test_ring_hts_stress.c        |  28 ++
>  app/test/test_ring_rts_stress.c        |  28 ++
>  app/test/test_ring_stress.c            |  27 ++
>  app/test/test_ring_stress.h            | 477 +++++++++++++++++++
>  lib/librte_pdump/rte_pdump.c           |   2 +-
>  lib/librte_port/rte_port_ring.c        |  12 +-
>  lib/librte_ring/Makefile               |   4 +-
>  lib/librte_ring/meson.build            |   4 +-
>  lib/librte_ring/rte_ring.c             |  84 +++-
>  lib/librte_ring/rte_ring.h             | 619 +++++++++++++++++++++++--
>  lib/librte_ring/rte_ring_elem.h        |   8 +-
>  lib/librte_ring/rte_ring_hts_generic.h | 228 +++++++++
> lib/librte_ring/rte_ring_rts_generic.h | 240 ++++++++++
>  16 files changed, 1721 insertions(+), 52 deletions(-)  create mode 100644
> app/test/test_ring_hts_stress.c  create mode 100644
> app/test/test_ring_rts_stress.c  create mode 100644
> app/test/test_ring_stress.c  create mode 100644 app/test/test_ring_stress.h
> create mode 100644 lib/librte_ring/rte_ring_hts_generic.h
>  create mode 100644 lib/librte_ring/rte_ring_rts_generic.h
> 
> --
> 2.17.1


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 0/4] Introduce IF proxy library
  2020-03-25  8:08  3%   ` David Marchand
@ 2020-03-25 11:11  4%     ` Morten Brørup
  2020-03-26 17:42  3%       ` Andrzej Ostruszka
  2020-03-26 12:41  3%     ` Andrzej Ostruszka
  1 sibling, 1 reply; 200+ results
From: Morten Brørup @ 2020-03-25 11:11 UTC (permalink / raw)
  To: Andrzej Ostruszka, David Marchand; +Cc: dev

Andrzej,

> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of David Marchand
> Sent: Wednesday, March 25, 2020 9:08 AM
> 
> Hello Andrzej,
> 
> On Tue, Mar 10, 2020 at 12:11 PM Andrzej Ostruszka
> <aostruszka@marvell.com> wrote:
> >

<snip>

> >
> > What has changed since the RFC
> > ==============================
> >
> > - Platform dependent parts has been separated into a ifpx_platform
> >   structure with callbacks for initialization, getting information
> about
> >   the interface, listening to the changes and closing of the library.
> >   That should allow easier reimplementation.
> >
> > - Notification scheme has been changed - instead of having just
> >   callbacks now event queueing is also available (or a mix of those
> >   two).

Thank you for adding event queueing!

David mentions ABI forward compatibility below. Consider using a dynamically sized generic TLV (type, length, value) message format instead of a big union structure for the events. This would make it easier to extend the list of event types without breaking the ABI.

And I am still strongly opposed to the callback method:
The callbacks are handled as DPDK interrupts, which are running in a non-DPDK thread, i.e. a running callback may be preempted by some other Linux process. This makes it difficult to implement callbacks correctly.
The risk of someone calling a non-thread safe function from a callback is high, e.g. DPDK hash table manipulation (except lookup) is not thread safe.

Your documentation is far too vague about this:
Please note however that the context in which these callbacks are 
called is most probably different from the one in which packets are 
handled and it is application writer responsibility to use proper 
synchronization mechanisms - if they are needed.

You need a big fat WARNING about how difficult the DPDK interrupt thread is to work with. As I described above, it is not "most probably" it is "certainly" a very different kind of context.

Did you check that the functions you use in your example callbacks are all thread safe and non-blocking, so they can safely be called from a non-DPDK thread that may be preempted by a another Linux process?

<snip>

> 
> I can see we end up exposing structures for registering callbacks.
> Did you consider some ways to avoid exposure of those? (thinking of
> ABI maintenance for when this library will elect to non-experimental).
> I can see some canary at the end of an enum, can we do without it?
> 
> Is there a pb with merging ifpx support into the existing l3fwd
> application rather than introduce a new example?
> 
> 
> --
> David Marchand
> 


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 0/4] Introduce IF proxy library
  @ 2020-03-25  8:08  3%   ` David Marchand
  2020-03-25 11:11  4%     ` Morten Brørup
  2020-03-26 12:41  3%     ` Andrzej Ostruszka
  0 siblings, 2 replies; 200+ results
From: David Marchand @ 2020-03-25  8:08 UTC (permalink / raw)
  To: Andrzej Ostruszka; +Cc: dev

Hello Andrzej,

On Tue, Mar 10, 2020 at 12:11 PM Andrzej Ostruszka
<aostruszka@marvell.com> wrote:
>
> What is this useful for
> =======================
>
> Usually, when an ethernet port is assigned to DPDK it vanishes from the
> system and user looses ability to control it via normal configuration
> utilities (e.g. those from iproute2 package).  Moreover by default DPDK
> application is not aware of the network configuration of the system.
>
> To address both of these issues application needs to:
> - add some command line interface (or other mechanism) allowing for
>   control of the port and its configuration
> - query the status of network configuration and monitor its changes
>
> The purpose of this library is to help with both of these tasks (as long
> as they remain in domain of configuration available to the system).  In
> other words, if DPDK application has some special needs, that cannot be
> addressed by the normal system configuration utilities, then they need
> to be solved by the application itself.
>
> The connection between DPDK and system is based on the existence of
> ports that are visible to both DPDK and system (like Tap, KNI and
> possibly some other drivers).  These ports serve as an interface
> proxies.
>
> Let's visualize the action of the library by the following example:
>
>               Linux             |            DPDK
> ==============================================================
>                                 |
>                                 |   +-------+       +-------+
>                                 |   | Port1 |       | Port2 |
> "ip link set dev tap1 mtu 1600" |   +-------+       +-------+
>                           |     |       ^              ^ ^
>                           |  +------+   | mtu_change   | |
>                           `->| Tap1 |---' callback     | |
>                              +------+                  | |
> "ip addr add 198.51.100.14 \    |                      | |
>                   dev tap2"     |                      | |
>                           |  +------+                  | |
>                           +->| Tap2 |------------------' |
>                           |  +------+  addr_add callback |
> "ip route add 198.0.2.0/24 \    |  |                     |
>                   dev tap2"     |  | route_add callback  |
>                                 |  `---------------------'
>
> So we have two ports Port1 and Port2 that are not visible to the system.
> We create two proxy interfaces (here based on Tap driver) and bind the
> ports to their proxies.  When user issues a command changing MTU for
> Tap1 interface the library notes this and calls "mtu_change" callback
> for the Port1.  Similarly when user adds an IPv4 address to the Tap2
> interface "addr_add" callback is called for the Port2 and the same
> happens for configuration of routing rule pointing to Tap2.  Apart from
> callbacks this library can notify about changes via adding events to
> notification queues.  See below for more inforamtion about that and
> a complete list of available callbacks.
>
> Please note that nothing has been mentioned about forwarding of the
> packets between system and DPDK.  Since the proxies are normal DPDK
> ports you can receive/send to them via usual RX/TX burst API.  However
> since the library is not aware of the structure of packet processing
> used by the application it cannot automatically forward the packets - it
> is responsibility of the application to include proxy ports into its
> packet processing engine.
>
> As mentioned above the intention of the library is to:
> - provide information about network configuration that would allow
>   application to decide what to do with the packets received on DPDK
>   ports,
> - allow for control of the ports via standard configuration utilities
>
> Although the library only helps you to identify proxy for given port
> (and vice versa) and calls appropriate callbacks it does open some
> interesting possibilities.  For example you can use the proxy ports to
> forward packets for protocols that you do not wish to handle in DPDK
> application to the system protocol stack and just listen to the
> configuration changes - so that way you can "offload" handling of those
> protocols to the system.
>
> How to use it
> =============
>
> Usage of this library is rather simple.  You have to:
> 1. Create proxy (if you don't have port suitable for being proxy or you
>   have one but do not wish to use it as a proxy).
> 2. Bind port to proxy.
> 3. Register callbacks and/or event queues.
> 4. Start listening to the network configuration.
>
> The only mandatory requirement for DPDK port to be able to act as
> a proxy is that it is visible in the system - this is checked during
> port to proxy binding by calling rte_eth_dev_info_get() on proxy port
> and inspecting 'if_index' field (it has to be non-zero).
> One can create such port in the application by calling:
>
>   proxy_id = rte_ifpx_create(RTE_IFPX_DEFAULT);
>
> Upon success this returns id of DPDK proxy port created
> (RTE_MAX_ETHPORTS on failure).  The argument selects type of proxy port
> to create (currently Tap/KNI only).  This function actually is just
> a wrapper around:
>
>   uint16_t rte_ifpx_create_by_devarg(const char *devarg);
>
> creating valid 'devarg' string for the chosen type of proxy.  If you have
> other driver capable of acting as a proxy you can call
> rte_ifpx_create_by_devarg() directly passing appropriate argument.
>
> Once you have id of both port and proxy you can bind the two via:
>
>   rte_ifpx_port_bind(port_id, proxy_id);
>
> This creates logical binding - as mentioned above there is no automatic
> packet forwarding.  With this binding whenever user changes the state of
> proxy interface in the system (link up/down, change mac/mtu, add/remove
> IPv4/IPv6) you get appropriate notification for the bound port.
>
> So far we've mentioned several times that the library calls callbacks.
> They are grouped in 'struct rte_ifpx_callbacks' and user provides them
> to the library via:
>
>   rte_ifpx_callbacks_register(&cbs);
>
> It is worth mentioning that the context (lcore/thread) in which these
> callbacks are called is implementation defined.  It might differ between
> different platforms, so the application needs to assume that some kind
> of inter lcore/thread synchronization/communication is required.
>
> Apart from notification via callbacks this library also supports
> notifying about the changes via adding events to the configured
> notification queues.  The queues are registered via:
>
>   int rte_ifpx_queue_add(struct rte_ring *r);
>
> and the actual logic used is: if there is callback registered then it is
> called, if it returns non-zero then event is considered completed,
> otherwise event is added to each configured notification queue.
> That way application can update data structures that are safe to be
> modified by single writer from within callback or do the common
> preprocessing steps (if any needed) in callback and data that is
> replicated can be updated during handling of queued events.
>
> Once we have bindings in place and notification configured, the only
> essential part that remains is to get the current network configuration
> and start listening to its changes.  This is accomplished via a call to:
>
>   rte_ifpx_listen();
>
> And basically this is all one needs to understand how to use this
> library.  Other less essential parts include:
> - ability to query what events are available for given platform
> - getting mapping between proxy and port
> - unbinding the ports from proxy
> - destroying proxy port
> - closing the listening service
> - getting basic information about proxy
>
>
> Currently available features and implementation
> ===============================================
>
> The library's API is system independent but it obviously needs some
> system dependent parts.  We provide exemplary Linux implementation (based
> on netlink sockets).  Very similar implementation is possible for
> FreeBSD (with the usage of PF_ROUTE sockets).  Windows implementation
> would need to differ much (probably IP Helper library would be of some help).
>
> Here is the list of currently implemented callbacks:
>
> struct rte_ifpx_callbacks {
>   int (*mac_change)(const struct rte_ifpx_mac_change *event);
>   int (*mtu_change)(const struct rte_ifpx_mtu_change *event);
>   int (*link_change)(const struct rte_ifpx_link_change *event);
>   int (*addr_add)(const struct rte_ifpx_addr_change *event);
>   int (*addr_del)(const struct rte_ifpx_addr_change *event);
>   int (*addr6_add)(const struct rte_ifpx_addr6_change *event);
>   int (*addr6_del)(const struct rte_ifpx_addr6_change *event);
>   int (*route_add)(const struct rte_ifpx_route_change *event);
>   int (*route_del)(const struct rte_ifpx_route_change *event);
>   int (*route6_add)(const struct rte_ifpx_route6_change *event);
>   int (*route6_del)(const struct rte_ifpx_route6_change *event);
>   int (*neigh_add)(const struct rte_ifpx_neigh_change *event);
>   int (*neigh_del)(const struct rte_ifpx_neigh_change *event);
>   int (*neigh6_add)(const struct rte_ifpx_neigh6_change *event);
>   int (*neigh6_del)(const struct rte_ifpx_neigh6_change *event);
>   int (*cfg_done)(void);
> };
>
> They are all rather self-descriptive with the exception of the last one.
> When the user calls rte_ifpx_listen() the library first queries the
> system for its current configuration.  That might require several
> request/reply exchanges between DPDK and system and once it is finished
> this callback is called to let application know that all info has been
> gathered.
>
> It is worth to mention also that while typical case would be a 1-to-1
> mapping between port and proxy, the 1-to-many mapping is also supported.
> In that case related callbacks will be called for each port bound to
> given proxy interface - it is application responsibility to define
> semantic of such mapping (e.g. all changes apply to all ports, or link
> changes apply to all but other are accepted in "round robin" fashion, or
> some other logic).
>
> As mentioned above Linux implementation is based on netlink socket.
> This socket is registered as file descriptor in EAL interrupts
> (similarly to how EAL alarms are implemented).
>
> What has changed since the RFC
> ==============================
>
> - Platform dependent parts has been separated into a ifpx_platform
>   structure with callbacks for initialization, getting information about
>   the interface, listening to the changes and closing of the library.
>   That should allow easier reimplementation.
>
> - Notification scheme has been changed - instead of having just
>   callbacks now event queueing is also available (or a mix of those
>   two).
>
> - Filtering of events only related to the proxy ports - previously all
>   network configuration changes were reported.  But DPDK application
>   doesn't need to know whole configuration - only just portion related
>   to the proxy ports.  If a packet comes that does not match rules then
>   it can be forwarded via proxy to the system to decide what to do with
>   it.  If that is not desired and such packets should be dropped then
>   null port can be created with proxy and e.g. default route installed
>   on it.
>
> - Removed previous example which was just printing notification.
>   Instead added a simplified (stripped vectorization and other
>   performance improvements) version of l3fwd that should serve as an
>   example of using this library in real applications.
>
> Changes in V2
> =============
> - Cleaned up checkpatch warnings
> - Removed dead/unused code and added gateway clearing in l3fwd-ifpx

I can see we end up exposing structures for registering callbacks.
Did you consider some ways to avoid exposure of those? (thinking of
ABI maintenance for when this library will elect to non-experimental).
I can see some canary at the end of an enum, can we do without it?

Is there a pb with merging ifpx support into the existing l3fwd
application rather than introduce a new example?


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  2020-03-24  9:35  0%             ` Andrew Rybchenko
@ 2020-03-24 12:41  0%               ` Tonghao Zhang
  0 siblings, 0 replies; 200+ results
From: Tonghao Zhang @ 2020-03-24 12:41 UTC (permalink / raw)
  To: Andrew Rybchenko
  Cc: Olivier Matz, Jerin Jacob, dpdk-dev, Gage Eads, Artem V. Andreev,
	Jerin Jacob, Nithin Dabilpuram, Vamsi Attunuru, Hemant Agrawal

On Tue, Mar 24, 2020 at 5:36 PM Andrew Rybchenko
<arybchenko@solarflare.com> wrote:
>
> On 3/9/20 11:27 AM, Olivier Matz wrote:
> > Hi,
> >
> > On Mon, Mar 09, 2020 at 11:01:25AM +0800, Tonghao Zhang wrote:
> >> On Sat, Mar 7, 2020 at 8:54 PM Andrew Rybchenko
> >> <arybchenko@solarflare.com> wrote:
> >>>
> >>> On 3/7/20 3:51 PM, Andrew Rybchenko wrote:
> >>>> On 3/6/20 4:37 PM, Jerin Jacob wrote:
> >>>>> On Fri, Mar 6, 2020 at 7:06 PM <xiangxia.m.yue@gmail.com> wrote:
> >>>>>> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> >>>>>>
> >>>>>> The order of mempool initiation affects mempool index in the
> >>>>>> rte_mempool_ops_table. For example, when building APPs with:
> >>>>>>
> >>>>>> $ gcc -lrte_mempool_bucket -lrte_mempool_ring ...
> >>>>>>
> >>>>>> The "bucket" mempool will be registered firstly, and its index
> >>>>>> in table is 0 while the index of "ring" mempool is 1. DPDK
> >>>>>> uses the mk/rte.app.mk to build APPs, and others, for example,
> >>>>>> Open vSwitch, use the libdpdk.a or libdpdk.so to build it.
> >>>>>> The mempool lib linked in dpdk and Open vSwitch is different.
> >>>>>>
> >>>>>> The mempool can be used between primary and secondary process,
> >>>>>> such as dpdk-pdump and pdump-pmd/Open vSwitch(pdump enabled).
> >>>>>> There will be a crash because dpdk-pdump creates the "ring_mp_mc"
> >>>>>> ring which index in table is 0, but the index of "bucket" ring
> >>>>>> is 0 in Open vSwitch. If Open vSwitch use the index 0 to get
> >>>>>> mempool ops and malloc memory from mempool. The crash will occur:
> >>>>>>
> >>>>>>      bucket_dequeue (access null and crash)
> >>>>>>      rte_mempool_get_ops (should get "ring_mp_mc",
> >>>>>>                           but get "bucket" mempool)
> >>>>>>      rte_mempool_ops_dequeue_bulk
> >>>>>>      ...
> >>>>>>      rte_pktmbuf_alloc
> >>>>>>      rte_pktmbuf_copy
> >>>>>>      pdump_copy
> >>>>>>      pdump_rx
> >>>>>>      rte_eth_rx_burst
> >>>>>>
> >>>>>> To avoid the crash, there are some solution:
> >>>>>> * constructor priority: Different mempool uses different
> >>>>>>    priority in RTE_INIT, but it's not easy to maintain.
> >>>>>>
> >>>>>> * change mk/rte.app.mk: Change the order in mk/rte.app.mk to
> >>>>>>    be same as libdpdk.a/libdpdk.so, but when adding a new mempool
> >>>>>>    driver in future, we must make sure the order.
> >>>>>>
> >>>>>> * register mempool orderly: Sort the mempool when registering,
> >>>>>>    so the lib linked will not affect the index in mempool table.
> >>>>>>
> >>>>>> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> >>>>>> Acked-by: Olivier Matz <olivier.matz@6wind.com>
> >>>>> Acked-by: Jerin Jacob <jerinj@marvell.com>
> >>>>
> >>>> The patch is OK, but the fact that ops index changes during
> >>>> mempool driver lifetime is frightening. In fact it breaks
> >>>> rte_mempool_register_ops() return value semantics (read
> >>>> as API break). The return value is not used in DPDK, but it
> >>>> is a public function. If I'm not mistaken it should be taken
> >>>> into account.
> >
> > Good points.
> >
> > The fact that the ops index changes during mempool driver lifetime is
> > indeed frightening, especially knowning that this is a dynamic
> > registration that could happen at any moment in the life of the
> > application. Also, breaking the ABI is not desirable.
> >
> > Let me try to propose something else to solve your issue:
> >
> > 1/ At init, the primary process allocates a struct in shared memory
> >    (named memzone):
> >
> >    struct rte_mempool_shared_ops {
> >      size_t num_mempool_ops;
> >      struct {
> >        char name[RTE_MEMPOOL_OPS_NAMESIZE];
> >      } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];
> >      char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];
> >      rte_spinlock_t mempool;
> >    }
> >
> > 2/ When we register a mempool ops, we first get a name and id from the
> >    shared struct: with the lock held, lookup for the registered name and
> >    return its index, else get the last id and copy the name in the struct.
> >
> > 3/ Then do as before (in the per-process global table), except that we
> >    reuse the registered id.
> >
> > We can remove the num_ops field from rte_mempool_ops_table.
> >
> > Thoughts?
>
> I like the solution.
The patch will be sent, thanks.


-- 
Best regards, Tonghao

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  2020-03-09  8:27  3%           ` Olivier Matz
  2020-03-09  8:55  0%             ` Tonghao Zhang
@ 2020-03-24  9:35  0%             ` Andrew Rybchenko
  2020-03-24 12:41  0%               ` Tonghao Zhang
  1 sibling, 1 reply; 200+ results
From: Andrew Rybchenko @ 2020-03-24  9:35 UTC (permalink / raw)
  To: Olivier Matz, Tonghao Zhang
  Cc: Jerin Jacob, dpdk-dev, Gage Eads, Artem V. Andreev, Jerin Jacob,
	Nithin Dabilpuram, Vamsi Attunuru, Hemant Agrawal

On 3/9/20 11:27 AM, Olivier Matz wrote:
> Hi,
> 
> On Mon, Mar 09, 2020 at 11:01:25AM +0800, Tonghao Zhang wrote:
>> On Sat, Mar 7, 2020 at 8:54 PM Andrew Rybchenko
>> <arybchenko@solarflare.com> wrote:
>>>
>>> On 3/7/20 3:51 PM, Andrew Rybchenko wrote:
>>>> On 3/6/20 4:37 PM, Jerin Jacob wrote:
>>>>> On Fri, Mar 6, 2020 at 7:06 PM <xiangxia.m.yue@gmail.com> wrote:
>>>>>> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
>>>>>>
>>>>>> The order of mempool initiation affects mempool index in the
>>>>>> rte_mempool_ops_table. For example, when building APPs with:
>>>>>>
>>>>>> $ gcc -lrte_mempool_bucket -lrte_mempool_ring ...
>>>>>>
>>>>>> The "bucket" mempool will be registered firstly, and its index
>>>>>> in table is 0 while the index of "ring" mempool is 1. DPDK
>>>>>> uses the mk/rte.app.mk to build APPs, and others, for example,
>>>>>> Open vSwitch, use the libdpdk.a or libdpdk.so to build it.
>>>>>> The mempool lib linked in dpdk and Open vSwitch is different.
>>>>>>
>>>>>> The mempool can be used between primary and secondary process,
>>>>>> such as dpdk-pdump and pdump-pmd/Open vSwitch(pdump enabled).
>>>>>> There will be a crash because dpdk-pdump creates the "ring_mp_mc"
>>>>>> ring which index in table is 0, but the index of "bucket" ring
>>>>>> is 0 in Open vSwitch. If Open vSwitch use the index 0 to get
>>>>>> mempool ops and malloc memory from mempool. The crash will occur:
>>>>>>
>>>>>>      bucket_dequeue (access null and crash)
>>>>>>      rte_mempool_get_ops (should get "ring_mp_mc",
>>>>>>                           but get "bucket" mempool)
>>>>>>      rte_mempool_ops_dequeue_bulk
>>>>>>      ...
>>>>>>      rte_pktmbuf_alloc
>>>>>>      rte_pktmbuf_copy
>>>>>>      pdump_copy
>>>>>>      pdump_rx
>>>>>>      rte_eth_rx_burst
>>>>>>
>>>>>> To avoid the crash, there are some solution:
>>>>>> * constructor priority: Different mempool uses different
>>>>>>    priority in RTE_INIT, but it's not easy to maintain.
>>>>>>
>>>>>> * change mk/rte.app.mk: Change the order in mk/rte.app.mk to
>>>>>>    be same as libdpdk.a/libdpdk.so, but when adding a new mempool
>>>>>>    driver in future, we must make sure the order.
>>>>>>
>>>>>> * register mempool orderly: Sort the mempool when registering,
>>>>>>    so the lib linked will not affect the index in mempool table.
>>>>>>
>>>>>> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
>>>>>> Acked-by: Olivier Matz <olivier.matz@6wind.com>
>>>>> Acked-by: Jerin Jacob <jerinj@marvell.com>
>>>>
>>>> The patch is OK, but the fact that ops index changes during
>>>> mempool driver lifetime is frightening. In fact it breaks
>>>> rte_mempool_register_ops() return value semantics (read
>>>> as API break). The return value is not used in DPDK, but it
>>>> is a public function. If I'm not mistaken it should be taken
>>>> into account.
> 
> Good points.
> 
> The fact that the ops index changes during mempool driver lifetime is
> indeed frightening, especially knowning that this is a dynamic
> registration that could happen at any moment in the life of the
> application. Also, breaking the ABI is not desirable.
> 
> Let me try to propose something else to solve your issue:
> 
> 1/ At init, the primary process allocates a struct in shared memory
>    (named memzone):
> 
>    struct rte_mempool_shared_ops {
>      size_t num_mempool_ops;
>      struct {
>        char name[RTE_MEMPOOL_OPS_NAMESIZE];
>      } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];
>      char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];
>      rte_spinlock_t mempool;
>    }
> 
> 2/ When we register a mempool ops, we first get a name and id from the
>    shared struct: with the lock held, lookup for the registered name and
>    return its index, else get the last id and copy the name in the struct.
> 
> 3/ Then do as before (in the per-process global table), except that we
>    reuse the registered id.
> 
> We can remove the num_ops field from rte_mempool_ops_table.
> 
> Thoughts?

I like the solution.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] devtools: fix check symbol change script
  2020-03-23 11:56  3% ` [dpdk-dev] [PATCH v2] " Nithin Dabilpuram
@ 2020-03-23 13:19  0%   ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-03-23 13:19 UTC (permalink / raw)
  To: Nithin Dabilpuram
  Cc: Thomas Monjalon, Neil Horman, dev, Jerin Jacob Kollanukkaran,
	bingz, dpdk stable

On Mon, Mar 23, 2020 at 12:56 PM Nithin Dabilpuram
<ndabilpuram@marvell.com> wrote:
>
> Fix check symbol change script to detect new diff file when
> it is in between  "--- /dev/null" to "b/lib/...".
> Current awk line expects line to start with "a/..."
> which is not always true for all diffs.
> As a result if in_map was '1' earlier, it will not be changed
> to '0' and we get check patch errors which are not true.
>
> Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
> Cc: stable@dpdk.org
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
> Acked-by: Neil Horman <nhorman@tuxdriver.com>
> Tested-by: Jerin Jacob <jerinj@marvell.com>

Thanks Nithin, applied.

-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v2] devtools: fix check symbol change script
  2020-03-19 14:44  3% [dpdk-dev] [PATCH] devtools: fix check symbol change script Nithin Dabilpuram
  2020-03-19 14:56  0% ` David Marchand
  2020-03-22 14:37  0% ` Jerin Jacob
@ 2020-03-23 11:56  3% ` Nithin Dabilpuram
  2020-03-23 13:19  0%   ` David Marchand
  2 siblings, 1 reply; 200+ results
From: Nithin Dabilpuram @ 2020-03-23 11:56 UTC (permalink / raw)
  To: thomas, david.marchand, Neil Horman
  Cc: dev, jerinj, bingz, Nithin Dabilpuram, stable

Fix check symbol change script to detect new diff file when
it is in between  "--- /dev/null" to "b/lib/...".
Current awk line expects line to start with "a/..."
which is not always true for all diffs.
As a result if in_map was '1' earlier, it will not be changed
to '0' and we get check patch errors which are not true.

Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
Cc: nhorman@tuxdriver.com
Cc: stable@dpdk.org

Signed-off-by: David Marchand <david.marchand@redhat.com>
Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Tested-by: Jerin Jacob <jerinj@marvell.com>
---

v2:
- Updated logic from David to fix "not map" check 

 devtools/check-symbol-change.sh | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/devtools/check-symbol-change.sh b/devtools/check-symbol-change.sh
index c5434f3..ed2178e 100755
--- a/devtools/check-symbol-change.sh
+++ b/devtools/check-symbol-change.sh
@@ -17,13 +17,11 @@ build_map_changes()
 		# map files are altered, and all section/symbol names
 		# appearing between a triggering of this rule and the
 		# next trigger of this rule are associated with this file
-		/[-+] a\/.*\.map/ {map=$2; in_map=1}
+		/[-+] [ab]\/.*\.map/ {map=$2; in_map=1; next}
 
-		# Same pattern as above, only it matches on anything that
-		# does not end in 'map', indicating we have left the map chunk.
-		# When we hit this, turn off the in_map variable, which
-		# supresses the subordonate rules below
-		/[-+] a\/.*\.[^map]/ {in_map=0}
+		# The previous rule catches all .map files, anything else
+		# indicates we left the map chunk.
+		/[-+] [ab]\// {in_map=0}
 
 		# Triggering this rule, which starts a line and ends it
 		# with a { identifies a versioned section.  The section name is
-- 
2.8.4


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] devtools: fix check symbol change script
  2020-03-19 14:44  3% [dpdk-dev] [PATCH] devtools: fix check symbol change script Nithin Dabilpuram
  2020-03-19 14:56  0% ` David Marchand
@ 2020-03-22 14:37  0% ` Jerin Jacob
  2020-03-23 11:56  3% ` [dpdk-dev] [PATCH v2] " Nithin Dabilpuram
  2 siblings, 0 replies; 200+ results
From: Jerin Jacob @ 2020-03-22 14:37 UTC (permalink / raw)
  To: Nithin Dabilpuram
  Cc: Thomas Monjalon, David Marchand, Neil Horman, dpdk-dev,
	Jerin Jacob, dpdk stable

On Thu, Mar 19, 2020 at 8:14 PM Nithin Dabilpuram
<ndabilpuram@marvell.com> wrote:
>
> Fix check symbol change script to detect new diff file when
> it is in between  "--- /dev/null" to "b/lib/...".
> Current awk line expects line to start with "a/..."
> which is not always true for all diffs.
> As a result if in_map was '1' earlier, it will not be changed
> to '0' and we get check patch errors which are not true as the non
> version.map files get interpreted as version map file.
>
> Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
> Cc: nhorman@tuxdriver.com
> Cc: stable@dpdk.org
>
> Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>

Tested-by: Jerin Jacob <jerinj@marvell.com>


> ---
> Note: We have two examples where checkpatch errors are because of this
> because the version.map file change comes earlier in the diff. Because of
> this bug, any new file change that comes after version.map file diff
> as "/dev/null" to "b/.." gets misdetected as version.map file.
> * http://patches.dpdk.org/patch/66878/
> * https://patchwork.dpdk.org/patch/66900/
>  devtools/check-symbol-change.sh | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/devtools/check-symbol-change.sh b/devtools/check-symbol-change.sh
> index c5434f3..19ce82f 100755
> --- a/devtools/check-symbol-change.sh
> +++ b/devtools/check-symbol-change.sh
> @@ -17,13 +17,13 @@ build_map_changes()
>                 # map files are altered, and all section/symbol names
>                 # appearing between a triggering of this rule and the
>                 # next trigger of this rule are associated with this file
> -               /[-+] a\/.*\.map/ {map=$2; in_map=1}
> +               /[-+] [ab]\/.*\.map/ {map=$2; in_map=1}
>
>                 # Same pattern as above, only it matches on anything that
>                 # does not end in 'map', indicating we have left the map chunk.
>                 # When we hit this, turn off the in_map variable, which
>                 # supresses the subordonate rules below
> -               /[-+] a\/.*\.[^map]/ {in_map=0}
> +               /[-+] [ab]\/.*\.[^map]/ {in_map=0}
>
>                 # Triggering this rule, which starts a line and ends it
>                 # with a { identifies a versioned section.  The section name is
> --
> 2.8.4
>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ring: make ring implementation non-inlined
  2020-03-20 17:54  0% ` Stephen Hemminger
@ 2020-03-21  1:03  0%   ` Ananyev, Konstantin
  0 siblings, 0 replies; 200+ results
From: Ananyev, Konstantin @ 2020-03-21  1:03 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, olivier.matz, honnappa.nagarahalli, jerinj, drc



> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Friday, March 20, 2020 5:55 PM
> To: Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Cc: dev@dpdk.org; olivier.matz@6wind.com; honnappa.nagarahalli@arm.com; jerinj@marvell.com; drc@linux.vnet.ibm.com
> Subject: Re: [RFC] ring: make ring implementation non-inlined
> 
> On Fri, 20 Mar 2020 16:41:38 +0000
> Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:
> 
> > As was discussed here:
> > http://mails.dpdk.org/archives/dev/2020-February/158586.html
> > this RFC aimed to hide ring internals into .c and make all
> > ring functions non-inlined. In theory that might help to
> > maintain ABI stability in future.
> > This is just a POC to measure the impact of proposed idea,
> > proper implementation would definetly need some extra effort.
> > On IA box (SKX) ring_perf_autotest shows ~20-30 cycles extra for
> > enqueue+dequeue pair. On some more realistic code, I suspect
> > the impact it might be a bit higher.
> > For MP/MC bulk transfers degradation seems quite small,
> > though for SP/SC and/or small transfers it is more then noticable
> > (see exact numbers below).
> > From my perspective we'd probably keep it inlined for now
> > to avoid any non-anticipated perfomance degradations.
> > Though intersted to see perf results and opinions from
> > other interested parties.
> >
> > Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> > ring_perf_autotest (without patch/with patch)
> >
> > ### Testing single element enq/deq ###
> > legacy APIs: SP/SC: single: 8.75/43.23
> > legacy APIs: MP/MC: single: 56.18/80.44
> >
> > ### Testing burst enq/deq ###
> > legacy APIs: SP/SC: burst (size: 8): 37.36/53.37
> > legacy APIs: SP/SC: burst (size: 32): 93.97/117.30
> > legacy APIs: MP/MC: burst (size: 8): 78.23/91.45
> > legacy APIs: MP/MC: burst (size: 32): 131.59/152.49
> >
> > ### Testing bulk enq/deq ###
> > legacy APIs: SP/SC: bulk (size: 8): 37.29/54.48
> > legacy APIs: SP/SC: bulk (size: 32): 92.68/113.01
> > legacy APIs: MP/MC: bulk (size: 8): 78.40/93.50
> > legacy APIs: MP/MC: bulk (size: 32): 131.49/154.25
> >
> > ### Testing empty bulk deq ###
> > legacy APIs: SP/SC: bulk (size: 8): 4.00/16.86
> > legacy APIs: MP/MC: bulk (size: 8): 7.01/15.55
> >
> > ### Testing using two hyperthreads ###
> > legacy APIs: SP/SC: bulk (size: 8): 10.64/17.56
> > legacy APIs: MP/MC: bulk (size: 8): 15.30/16.69
> > legacy APIs: SP/SC: bulk (size: 32): 5.84/7.09
> > legacy APIs: MP/MC: bulk (size: 32): 6.34/7.54
> >
> > ### Testing using two physical cores ###
> > legacy APIs: SP/SC: bulk (size: 8): 24.34/42.40
> > legacy APIs: MP/MC: bulk (size: 8): 70.34/71.82
> > legacy APIs: SP/SC: bulk (size: 32): 12.67/14.68
> > legacy APIs: MP/MC: bulk (size: 32): 22.41/17.93
> >
> > ### Testing single element enq/deq ###
> > elem APIs: element size 16B: SP/SC: single: 10.65/41.96
> > elem APIs: element size 16B: MP/MC: single: 44.33/81.36
> >
> > ### Testing burst enq/deq ###
> > elem APIs: element size 16B: SP/SC: burst (size: 8): 39.20/58.52
> > elem APIs: element size 16B: SP/SC: burst (size: 32): 123.19/142.79
> > elem APIs: element size 16B: MP/MC: burst (size: 8): 80.72/101.36
> > elem APIs: element size 16B: MP/MC: burst (size: 32): 169.21/185.38
> >
> > ### Testing bulk enq/deq ###
> > elem APIs: element size 16B: SP/SC: bulk (size: 8): 41.64/58.46
> > elem APIs: element size 16B: SP/SC: bulk (size: 32): 122.74/142.52
> > elem APIs: element size 16B: MP/MC: bulk (size: 8): 80.60/103.14
> > elem APIs: element size 16B: MP/MC: bulk (size: 32): 169.39/186.67
> >
> > ### Testing empty bulk deq ###
> > elem APIs: element size 16B: SP/SC: bulk (size: 8): 5.01/17.17
> > elem APIs: element size 16B: MP/MC: bulk (size: 8): 6.01/14.80
> >
> > ### Testing using two hyperthreads ###
> > elem APIs: element size 16B: SP/SC: bulk (size: 8): 12.02/17.18
> > elem APIs: element size 16B: MP/MC: bulk (size: 8): 16.81/21.14
> > elem APIs: element size 16B: SP/SC: bulk (size: 32): 7.87/9.01
> > elem APIs: element size 16B: MP/MC: bulk (size: 32): 8.22/10.57
> >
> > ### Testing using two physical cores ###
> > elem APIs: element size 16B: SP/SC: bulk (size: 8): 27.00/51.94
> > elem APIs: element size 16B: MP/MC: bulk (size: 8): 78.24/74.48
> > elem APIs: element size 16B: SP/SC: bulk (size: 32): 15.41/16.14
> > elem APIs: element size 16B: MP/MC: bulk (size: 32): 18.72/21.64
> >
> > Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> 
> What is impact with LTO? I suspect compiler might have a chance to
> get speed back with LTO.

Might be, but LTO is not enabled by default.
So don't see much point in digging any further here.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC] ring: make ring implementation non-inlined
  2020-03-20 16:41  3% [dpdk-dev] [RFC] ring: make ring implementation non-inlined Konstantin Ananyev
@ 2020-03-20 17:54  0% ` Stephen Hemminger
  2020-03-21  1:03  0%   ` Ananyev, Konstantin
  2020-03-25 21:09  4% ` Jerin Jacob
  1 sibling, 1 reply; 200+ results
From: Stephen Hemminger @ 2020-03-20 17:54 UTC (permalink / raw)
  To: Konstantin Ananyev; +Cc: dev, olivier.matz, honnappa.nagarahalli, jerinj, drc

On Fri, 20 Mar 2020 16:41:38 +0000
Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:

> As was discussed here:
> http://mails.dpdk.org/archives/dev/2020-February/158586.html
> this RFC aimed to hide ring internals into .c and make all
> ring functions non-inlined. In theory that might help to
> maintain ABI stability in future.
> This is just a POC to measure the impact of proposed idea,
> proper implementation would definetly need some extra effort.
> On IA box (SKX) ring_perf_autotest shows ~20-30 cycles extra for
> enqueue+dequeue pair. On some more realistic code, I suspect
> the impact it might be a bit higher.
> For MP/MC bulk transfers degradation seems quite small,
> though for SP/SC and/or small transfers it is more then noticable
> (see exact numbers below).
> From my perspective we'd probably keep it inlined for now
> to avoid any non-anticipated perfomance degradations.
> Though intersted to see perf results and opinions from
> other interested parties.
> 
> Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
> ring_perf_autotest (without patch/with patch)
> 
> ### Testing single element enq/deq ###
> legacy APIs: SP/SC: single: 8.75/43.23
> legacy APIs: MP/MC: single: 56.18/80.44
> 
> ### Testing burst enq/deq ###
> legacy APIs: SP/SC: burst (size: 8): 37.36/53.37
> legacy APIs: SP/SC: burst (size: 32): 93.97/117.30
> legacy APIs: MP/MC: burst (size: 8): 78.23/91.45
> legacy APIs: MP/MC: burst (size: 32): 131.59/152.49
> 
> ### Testing bulk enq/deq ###
> legacy APIs: SP/SC: bulk (size: 8): 37.29/54.48
> legacy APIs: SP/SC: bulk (size: 32): 92.68/113.01
> legacy APIs: MP/MC: bulk (size: 8): 78.40/93.50
> legacy APIs: MP/MC: bulk (size: 32): 131.49/154.25
> 
> ### Testing empty bulk deq ###
> legacy APIs: SP/SC: bulk (size: 8): 4.00/16.86
> legacy APIs: MP/MC: bulk (size: 8): 7.01/15.55
> 
> ### Testing using two hyperthreads ###
> legacy APIs: SP/SC: bulk (size: 8): 10.64/17.56
> legacy APIs: MP/MC: bulk (size: 8): 15.30/16.69
> legacy APIs: SP/SC: bulk (size: 32): 5.84/7.09
> legacy APIs: MP/MC: bulk (size: 32): 6.34/7.54
> 
> ### Testing using two physical cores ###
> legacy APIs: SP/SC: bulk (size: 8): 24.34/42.40
> legacy APIs: MP/MC: bulk (size: 8): 70.34/71.82
> legacy APIs: SP/SC: bulk (size: 32): 12.67/14.68
> legacy APIs: MP/MC: bulk (size: 32): 22.41/17.93
> 
> ### Testing single element enq/deq ###
> elem APIs: element size 16B: SP/SC: single: 10.65/41.96
> elem APIs: element size 16B: MP/MC: single: 44.33/81.36
> 
> ### Testing burst enq/deq ###
> elem APIs: element size 16B: SP/SC: burst (size: 8): 39.20/58.52
> elem APIs: element size 16B: SP/SC: burst (size: 32): 123.19/142.79
> elem APIs: element size 16B: MP/MC: burst (size: 8): 80.72/101.36
> elem APIs: element size 16B: MP/MC: burst (size: 32): 169.21/185.38
> 
> ### Testing bulk enq/deq ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 41.64/58.46
> elem APIs: element size 16B: SP/SC: bulk (size: 32): 122.74/142.52
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 80.60/103.14
> elem APIs: element size 16B: MP/MC: bulk (size: 32): 169.39/186.67
> 
> ### Testing empty bulk deq ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 5.01/17.17
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 6.01/14.80
> 
> ### Testing using two hyperthreads ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 12.02/17.18
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 16.81/21.14
> elem APIs: element size 16B: SP/SC: bulk (size: 32): 7.87/9.01
> elem APIs: element size 16B: MP/MC: bulk (size: 32): 8.22/10.57
> 
> ### Testing using two physical cores ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 27.00/51.94
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 78.24/74.48
> elem APIs: element size 16B: SP/SC: bulk (size: 32): 15.41/16.14
> elem APIs: element size 16B: MP/MC: bulk (size: 32): 18.72/21.64
> 
> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

What is impact with LTO? I suspect compiler might have a chance to
get speed back with LTO.


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [RFC] ring: make ring implementation non-inlined
@ 2020-03-20 16:41  3% Konstantin Ananyev
  2020-03-20 17:54  0% ` Stephen Hemminger
  2020-03-25 21:09  4% ` Jerin Jacob
  0 siblings, 2 replies; 200+ results
From: Konstantin Ananyev @ 2020-03-20 16:41 UTC (permalink / raw)
  To: dev
  Cc: olivier.matz, honnappa.nagarahalli, jerinj, drc, stephen,
	Konstantin Ananyev

As was discussed here:
http://mails.dpdk.org/archives/dev/2020-February/158586.html
this RFC aimed to hide ring internals into .c and make all
ring functions non-inlined. In theory that might help to
maintain ABI stability in future.
This is just a POC to measure the impact of proposed idea,
proper implementation would definetly need some extra effort.
On IA box (SKX) ring_perf_autotest shows ~20-30 cycles extra for
enqueue+dequeue pair. On some more realistic code, I suspect
the impact it might be a bit higher.
For MP/MC bulk transfers degradation seems quite small,
though for SP/SC and/or small transfers it is more then noticable
(see exact numbers below).
From my perspective we'd probably keep it inlined for now
to avoid any non-anticipated perfomance degradations.
Though intersted to see perf results and opinions from
other interested parties.

Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
ring_perf_autotest (without patch/with patch)

### Testing single element enq/deq ###
legacy APIs: SP/SC: single: 8.75/43.23
legacy APIs: MP/MC: single: 56.18/80.44

### Testing burst enq/deq ###
legacy APIs: SP/SC: burst (size: 8): 37.36/53.37
legacy APIs: SP/SC: burst (size: 32): 93.97/117.30
legacy APIs: MP/MC: burst (size: 8): 78.23/91.45
legacy APIs: MP/MC: burst (size: 32): 131.59/152.49

### Testing bulk enq/deq ###
legacy APIs: SP/SC: bulk (size: 8): 37.29/54.48
legacy APIs: SP/SC: bulk (size: 32): 92.68/113.01
legacy APIs: MP/MC: bulk (size: 8): 78.40/93.50
legacy APIs: MP/MC: bulk (size: 32): 131.49/154.25

### Testing empty bulk deq ###
legacy APIs: SP/SC: bulk (size: 8): 4.00/16.86
legacy APIs: MP/MC: bulk (size: 8): 7.01/15.55

### Testing using two hyperthreads ###
legacy APIs: SP/SC: bulk (size: 8): 10.64/17.56
legacy APIs: MP/MC: bulk (size: 8): 15.30/16.69
legacy APIs: SP/SC: bulk (size: 32): 5.84/7.09
legacy APIs: MP/MC: bulk (size: 32): 6.34/7.54

### Testing using two physical cores ###
legacy APIs: SP/SC: bulk (size: 8): 24.34/42.40
legacy APIs: MP/MC: bulk (size: 8): 70.34/71.82
legacy APIs: SP/SC: bulk (size: 32): 12.67/14.68
legacy APIs: MP/MC: bulk (size: 32): 22.41/17.93

### Testing single element enq/deq ###
elem APIs: element size 16B: SP/SC: single: 10.65/41.96
elem APIs: element size 16B: MP/MC: single: 44.33/81.36

### Testing burst enq/deq ###
elem APIs: element size 16B: SP/SC: burst (size: 8): 39.20/58.52
elem APIs: element size 16B: SP/SC: burst (size: 32): 123.19/142.79
elem APIs: element size 16B: MP/MC: burst (size: 8): 80.72/101.36
elem APIs: element size 16B: MP/MC: burst (size: 32): 169.21/185.38

### Testing bulk enq/deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 41.64/58.46
elem APIs: element size 16B: SP/SC: bulk (size: 32): 122.74/142.52
elem APIs: element size 16B: MP/MC: bulk (size: 8): 80.60/103.14
elem APIs: element size 16B: MP/MC: bulk (size: 32): 169.39/186.67

### Testing empty bulk deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 5.01/17.17
elem APIs: element size 16B: MP/MC: bulk (size: 8): 6.01/14.80

### Testing using two hyperthreads ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 12.02/17.18
elem APIs: element size 16B: MP/MC: bulk (size: 8): 16.81/21.14
elem APIs: element size 16B: SP/SC: bulk (size: 32): 7.87/9.01
elem APIs: element size 16B: MP/MC: bulk (size: 32): 8.22/10.57

### Testing using two physical cores ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 27.00/51.94
elem APIs: element size 16B: MP/MC: bulk (size: 8): 78.24/74.48
elem APIs: element size 16B: SP/SC: bulk (size: 32): 15.41/16.14
elem APIs: element size 16B: MP/MC: bulk (size: 32): 18.72/21.64

Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
---
 app/proc-info/main.c                 |  20 +-
 app/test-pmd/cmdline.c               |   2 +-
 app/test/commands.c                  |   2 +-
 app/test/test_pdump.c                |   6 +-
 app/test/test_ring_stress.h          |   2 +-
 config/common_base                   |   2 +-
 drivers/crypto/ccp/ccp_pmd_ops.c     |   2 +-
 drivers/crypto/meson.build           |   1 -
 drivers/net/ring/rte_eth_ring.c      |  17 +-
 lib/librte_eventdev/rte_event_ring.c |   6 +-
 lib/librte_eventdev/rte_event_ring.h |  17 +-
 lib/librte_pdump/rte_pdump.c         |   3 +-
 lib/librte_port/rte_port_ring.c      |  29 +-
 lib/librte_ring/Makefile             |   6 +-
 lib/librte_ring/meson.build          |   6 +-
 lib/librte_ring/ring_elem.c          | 919 +++++++++++++++++++++++++++
 lib/librte_ring/ring_impl.c          | 750 ++++++++++++++++++++++
 lib/librte_ring/ring_impl.h          |  64 ++
 lib/librte_ring/rte_ring.c           |   3 +-
 lib/librte_ring/rte_ring.h           | 412 ++----------
 lib/librte_ring/rte_ring_elem.h      | 519 ++-------------
 lib/librte_ring/rte_ring_version.map |  46 ++
 22 files changed, 1938 insertions(+), 896 deletions(-)
 create mode 100644 lib/librte_ring/ring_elem.c
 create mode 100644 lib/librte_ring/ring_impl.c
 create mode 100644 lib/librte_ring/ring_impl.h

diff --git a/app/proc-info/main.c b/app/proc-info/main.c
index abeca4aab..aa8f113c1 100644
--- a/app/proc-info/main.c
+++ b/app/proc-info/main.c
@@ -1137,25 +1137,7 @@ show_ring(char *name)
 	if (name != NULL) {
 		struct rte_ring *ptr = rte_ring_lookup(name);
 		if (ptr != NULL) {
-			printf("  - Name (%s) on socket (%d)\n"
-				"  - flags:\n"
-				"\t  -- Single Producer Enqueue (%u)\n"
-				"\t  -- Single Consmer Dequeue (%u)\n",
-				ptr->name,
-				ptr->memzone->socket_id,
-				ptr->flags & RING_F_SP_ENQ,
-				ptr->flags & RING_F_SC_DEQ);
-			printf("  - size (%u) mask (0x%x) capacity (%u)\n",
-				ptr->size,
-				ptr->mask,
-				ptr->capacity);
-			printf("  - count (%u) free count (%u)\n",
-				rte_ring_count(ptr),
-				rte_ring_free_count(ptr));
-			printf("  - full (%d) empty (%d)\n",
-				rte_ring_full(ptr),
-				rte_ring_empty(ptr));
-
+			rte_ring_dump(stdout, ptr);
 			STATS_BDR_STR(50, "");
 			return;
 		}
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index a037a55c6..000853067 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -9562,7 +9562,7 @@ dump_struct_sizes(void)
 #define DUMP_SIZE(t) printf("sizeof(" #t ") = %u\n", (unsigned)sizeof(t));
 	DUMP_SIZE(struct rte_mbuf);
 	DUMP_SIZE(struct rte_mempool);
-	DUMP_SIZE(struct rte_ring);
+	//DUMP_SIZE(struct rte_ring);
 #undef DUMP_SIZE
 }
 
diff --git a/app/test/commands.c b/app/test/commands.c
index 3bf767bf7..89f93cdb2 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -107,7 +107,7 @@ dump_struct_sizes(void)
 #define DUMP_SIZE(t) printf("sizeof(" #t ") = %u\n", (unsigned)sizeof(t));
 	DUMP_SIZE(struct rte_mbuf);
 	DUMP_SIZE(struct rte_mempool);
-	DUMP_SIZE(struct rte_ring);
+	//DUMP_SIZE(struct rte_ring);
 #undef DUMP_SIZE
 }
 
diff --git a/app/test/test_pdump.c b/app/test/test_pdump.c
index ad183184c..6a1180bcb 100644
--- a/app/test/test_pdump.c
+++ b/app/test/test_pdump.c
@@ -57,8 +57,7 @@ run_pdump_client_tests(void)
 	if (ret < 0)
 		return -1;
 	mp->flags = 0x0000;
-	ring_client = rte_ring_create("SR0", RING_SIZE, rte_socket_id(),
-				      RING_F_SP_ENQ | RING_F_SC_DEQ);
+	ring_client = rte_ring_create("SR0", RING_SIZE, rte_socket_id(), 0);
 	if (ring_client == NULL) {
 		printf("rte_ring_create SR0 failed");
 		return -1;
@@ -71,9 +70,6 @@ run_pdump_client_tests(void)
 	}
 	rte_eth_dev_probing_finish(eth_dev);
 
-	ring_client->prod.single = 0;
-	ring_client->cons.single = 0;
-
 	printf("\n***** flags = RTE_PDUMP_FLAG_TX *****\n");
 
 	for (itr = 0; itr < NUM_ITR; itr++) {
diff --git a/app/test/test_ring_stress.h b/app/test/test_ring_stress.h
index c6f0bc9f1..27d4adfb2 100644
--- a/app/test/test_ring_stress.h
+++ b/app/test/test_ring_stress.h
@@ -350,7 +350,7 @@ mt1_init(struct rte_ring **rng, void **data, uint32_t num)
 	/* alloc ring */
 	nr = 2 * num;
 	sz = rte_ring_get_memsize(nr);
-	r = rte_zmalloc(NULL, sz, alignof(*r));
+	r = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
 	if (r == NULL) {
 		printf("%s: alloca(%zu) for FIFO with %u elems failed",
 			__func__, sz, nr);
diff --git a/config/common_base b/config/common_base
index 7ca2f28b1..87ab0766d 100644
--- a/config/common_base
+++ b/config/common_base
@@ -670,7 +670,7 @@ CONFIG_RTE_LIBRTE_PMD_ZUC=n
 
 # Compile PMD for Crypto Scheduler device
 #
-CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=y
+CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=n
 
 #
 # Compile PMD for NULL Crypto device
diff --git a/drivers/crypto/ccp/ccp_pmd_ops.c b/drivers/crypto/ccp/ccp_pmd_ops.c
index a19e85ecb..938977dc0 100644
--- a/drivers/crypto/ccp/ccp_pmd_ops.c
+++ b/drivers/crypto/ccp/ccp_pmd_ops.c
@@ -666,7 +666,7 @@ ccp_pmd_qp_create_batch_info_ring(struct ccp_qp *qp,
 
 	r = rte_ring_lookup(qp->name);
 	if (r) {
-		if (r->size >= ring_size) {
+		if (rte_ring_get_size(r) >= ring_size) {
 			CCP_LOG_INFO(
 				"Reusing ring %s for processed packets",
 				qp->name);
diff --git a/drivers/crypto/meson.build b/drivers/crypto/meson.build
index 7fa1fbe26..8c8b78db3 100644
--- a/drivers/crypto/meson.build
+++ b/drivers/crypto/meson.build
@@ -16,7 +16,6 @@ drivers = ['aesni_gcm',
 	   'octeontx2',
 	   'openssl',
 	   'qat',
-	   'scheduler',
 	   'snow3g',
 	   'virtio',
 	   'zuc']
diff --git a/drivers/net/ring/rte_eth_ring.c b/drivers/net/ring/rte_eth_ring.c
index 41acbc513..0eaac0dc3 100644
--- a/drivers/net/ring/rte_eth_ring.c
+++ b/drivers/net/ring/rte_eth_ring.c
@@ -41,6 +41,8 @@ struct ring_queue {
 	struct rte_ring *rng;
 	rte_atomic64_t rx_pkts;
 	rte_atomic64_t tx_pkts;
+	uint32_t rx_sync_type;
+	uint32_t tx_sync_type;
 };
 
 struct pmd_internals {
@@ -74,7 +76,7 @@ eth_ring_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
 	struct ring_queue *r = q;
 	const uint16_t nb_rx = (uint16_t)rte_ring_dequeue_burst(r->rng,
 			ptrs, nb_bufs, NULL);
-	if (r->rng->flags & RING_F_SC_DEQ)
+	if (r->rx_sync_type == RTE_RING_SYNC_ST)
 		r->rx_pkts.cnt += nb_rx;
 	else
 		rte_atomic64_add(&(r->rx_pkts), nb_rx);
@@ -88,7 +90,7 @@ eth_ring_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
 	struct ring_queue *r = q;
 	const uint16_t nb_tx = (uint16_t)rte_ring_enqueue_burst(r->rng,
 			ptrs, nb_bufs, NULL);
-	if (r->rng->flags & RING_F_SP_ENQ)
+	if (r->tx_sync_type == RTE_RING_SYNC_ST)
 		r->tx_pkts.cnt += nb_tx;
 	else
 		rte_atomic64_add(&(r->tx_pkts), nb_tx);
@@ -306,10 +308,14 @@ do_eth_dev_ring_create(const char *name,
 	internals->max_tx_queues = nb_tx_queues;
 	for (i = 0; i < nb_rx_queues; i++) {
 		internals->rx_ring_queues[i].rng = rx_queues[i];
+		internals->rx_ring_queues[i].rx_sync_type =
+			rte_ring_get_cons_sync_type(rx_queues[i]);
 		data->rx_queues[i] = &internals->rx_ring_queues[i];
 	}
 	for (i = 0; i < nb_tx_queues; i++) {
 		internals->tx_ring_queues[i].rng = tx_queues[i];
+		internals->tx_ring_queues[i].tx_sync_type =
+			rte_ring_get_prod_sync_type(rx_queues[i]);
 		data->tx_queues[i] = &internals->tx_ring_queues[i];
 	}
 
@@ -403,8 +409,11 @@ rte_eth_from_rings(const char *name, struct rte_ring *const rx_queues[],
 int
 rte_eth_from_ring(struct rte_ring *r)
 {
-	return rte_eth_from_rings(r->name, &r, 1, &r, 1,
-			r->memzone ? r->memzone->socket_id : SOCKET_ID_ANY);
+	const struct rte_memzone *mz;
+
+	mz = rte_ring_get_memzone(r);
+	return rte_eth_from_rings(rte_ring_get_name(r), &r, 1, &r, 1,
+			mz ? mz->socket_id : SOCKET_ID_ANY);
 }
 
 static int
diff --git a/lib/librte_eventdev/rte_event_ring.c b/lib/librte_eventdev/rte_event_ring.c
index d27e23901..99700a18c 100644
--- a/lib/librte_eventdev/rte_event_ring.c
+++ b/lib/librte_eventdev/rte_event_ring.c
@@ -16,12 +16,8 @@ int
 rte_event_ring_init(struct rte_event_ring *r, const char *name,
 	unsigned int count, unsigned int flags)
 {
-	/* compilation-time checks */
-	RTE_BUILD_BUG_ON((sizeof(struct rte_event_ring) &
-			  RTE_CACHE_LINE_MASK) != 0);
-
 	/* init the ring structure */
-	return rte_ring_init(&r->r, name, count, flags);
+	return rte_ring_init(r, name, count, flags);
 }
 
 /* create the ring */
diff --git a/lib/librte_eventdev/rte_event_ring.h b/lib/librte_eventdev/rte_event_ring.h
index c0861b0ec..b31b33b3e 100644
--- a/lib/librte_eventdev/rte_event_ring.h
+++ b/lib/librte_eventdev/rte_event_ring.h
@@ -32,9 +32,8 @@
  * used inside software eventdev implementations and by applications
  * directly as needed.
  */
-struct rte_event_ring {
-	struct rte_ring r;
-};
+
+#define rte_event_ring	rte_ring
 
 /**
  * Returns the number of events in the ring
@@ -47,7 +46,7 @@ struct rte_event_ring {
 static __rte_always_inline unsigned int
 rte_event_ring_count(const struct rte_event_ring *r)
 {
-	return rte_ring_count(&r->r);
+	return rte_ring_count(r);
 }
 
 /**
@@ -62,7 +61,7 @@ rte_event_ring_count(const struct rte_event_ring *r)
 static __rte_always_inline unsigned int
 rte_event_ring_free_count(const struct rte_event_ring *r)
 {
-	return rte_ring_free_count(&r->r);
+	return rte_ring_free_count(r);
 }
 
 /**
@@ -93,7 +92,7 @@ rte_event_ring_enqueue_burst(struct rte_event_ring *r,
 	unsigned int num;
 	uint32_t space;
 
-	num = rte_ring_enqueue_burst_elem(&r->r, events,
+	num = rte_ring_enqueue_burst_elem(r, events,
 				sizeof(struct rte_event), n,
 				&space);
 
@@ -129,7 +128,7 @@ rte_event_ring_dequeue_burst(struct rte_event_ring *r,
 	unsigned int num;
 	uint32_t remaining;
 
-	num = rte_ring_dequeue_burst_elem(&r->r, events,
+	num = rte_ring_dequeue_burst_elem(r, events,
 				sizeof(struct rte_event), n,
 				&remaining);
 
@@ -250,7 +249,7 @@ rte_event_ring_free(struct rte_event_ring *r);
 static inline unsigned int
 rte_event_ring_get_size(const struct rte_event_ring *r)
 {
-	return rte_ring_get_size(&r->r);
+	return rte_ring_get_size(r);
 }
 
 /**
@@ -264,6 +263,6 @@ rte_event_ring_get_size(const struct rte_event_ring *r)
 static inline unsigned int
 rte_event_ring_get_capacity(const struct rte_event_ring *r)
 {
-	return rte_ring_get_capacity(&r->r);
+	return rte_ring_get_capacity(r);
 }
 #endif
diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
index 8a01ac510..43aa07793 100644
--- a/lib/librte_pdump/rte_pdump.c
+++ b/lib/librte_pdump/rte_pdump.c
@@ -380,7 +380,8 @@ pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
 		rte_errno = EINVAL;
 		return -1;
 	}
-	if (ring->prod.single || ring->cons.single) {
+	if (rte_ring_get_prod_sync_type(ring) == RTE_RING_SYNC_ST ||
+			rte_ring_get_cons_sync_type(ring) == RTE_RING_SYNC_ST) {
 		PDUMP_LOG(ERR, "ring with either SP or SC settings"
 		" is not valid for pdump, should have MP and MC settings\n");
 		rte_errno = EINVAL;
diff --git a/lib/librte_port/rte_port_ring.c b/lib/librte_port/rte_port_ring.c
index 47fcdd06a..16fdee0bd 100644
--- a/lib/librte_port/rte_port_ring.c
+++ b/lib/librte_port/rte_port_ring.c
@@ -40,12 +40,15 @@ rte_port_ring_reader_create_internal(void *params, int socket_id,
 	struct rte_port_ring_reader_params *conf =
 			params;
 	struct rte_port_ring_reader *port;
+	uint32_t ring_sync;
+
+	ring_sync = rte_ring_get_cons_sync_type(conf->ring);
 
 	/* Check input parameters */
 	if ((conf == NULL) ||
 		(conf->ring == NULL) ||
-		(conf->ring->cons.single && is_multi) ||
-		(!(conf->ring->cons.single) && !is_multi)) {
+			(ring_sync == RTE_RING_SYNC_ST && is_multi) ||
+			(ring_sync != RTE_RING_SYNC_ST && !is_multi)) {
 		RTE_LOG(ERR, PORT, "%s: Invalid Parameters\n", __func__);
 		return NULL;
 	}
@@ -167,13 +170,16 @@ rte_port_ring_writer_create_internal(void *params, int socket_id,
 	struct rte_port_ring_writer_params *conf =
 			params;
 	struct rte_port_ring_writer *port;
+	uint32_t ring_sync;
+
+	ring_sync = rte_ring_get_prod_sync_type(conf->ring);
 
 	/* Check input parameters */
 	if ((conf == NULL) ||
-		(conf->ring == NULL) ||
-		(conf->ring->prod.single && is_multi) ||
-		(!(conf->ring->prod.single) && !is_multi) ||
-		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {
+			(conf->ring == NULL) ||
+			(ring_sync == RTE_RING_SYNC_ST && is_multi) ||
+			(ring_sync != RTE_RING_SYNC_ST && !is_multi) ||
+			(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {
 		RTE_LOG(ERR, PORT, "%s: Invalid Parameters\n", __func__);
 		return NULL;
 	}
@@ -436,13 +442,16 @@ rte_port_ring_writer_nodrop_create_internal(void *params, int socket_id,
 	struct rte_port_ring_writer_nodrop_params *conf =
 			params;
 	struct rte_port_ring_writer_nodrop *port;
+	uint32_t ring_sync;
+
+	ring_sync = rte_ring_get_prod_sync_type(conf->ring);
 
 	/* Check input parameters */
 	if ((conf == NULL) ||
-		(conf->ring == NULL) ||
-		(conf->ring->prod.single && is_multi) ||
-		(!(conf->ring->prod.single) && !is_multi) ||
-		(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {
+			(conf->ring == NULL) ||
+			(ring_sync == RTE_RING_SYNC_ST && is_multi) ||
+			(ring_sync != RTE_RING_SYNC_ST && !is_multi) ||
+			(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {
 		RTE_LOG(ERR, PORT, "%s: Invalid Parameters\n", __func__);
 		return NULL;
 	}
diff --git a/lib/librte_ring/Makefile b/lib/librte_ring/Makefile
index 917c560ad..8c3cd523d 100644
--- a/lib/librte_ring/Makefile
+++ b/lib/librte_ring/Makefile
@@ -13,11 +13,11 @@ EXPORT_MAP := rte_ring_version.map
 
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_RING) := rte_ring.c
+SRCS-$(CONFIG_RTE_LIBRTE_RING) += ring_impl.c
+SRCS-$(CONFIG_RTE_LIBRTE_RING) += ring_elem.c
 
 # install includes
 SYMLINK-$(CONFIG_RTE_LIBRTE_RING)-include := rte_ring.h \
-					rte_ring_elem.h \
-					rte_ring_generic.h \
-					rte_ring_c11_mem.h
+					rte_ring_elem.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ring/meson.build b/lib/librte_ring/meson.build
index f2f3ccc88..8adbdfc9d 100644
--- a/lib/librte_ring/meson.build
+++ b/lib/librte_ring/meson.build
@@ -1,11 +1,9 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-sources = files('rte_ring.c')
+sources = files('rte_ring.c', 'ring_impl.c', 'ring_elem.c')
 headers = files('rte_ring.h',
-		'rte_ring_elem.h',
-		'rte_ring_c11_mem.h',
-		'rte_ring_generic.h')
+		'rte_ring_elem.h')
 
 # rte_ring_create_elem and rte_ring_get_memsize_elem are experimental
 allow_experimental_apis = true
diff --git a/lib/librte_ring/ring_elem.c b/lib/librte_ring/ring_elem.c
new file mode 100644
index 000000000..3588725e7
--- /dev/null
+++ b/lib/librte_ring/ring_elem.c
@@ -0,0 +1,919 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2019 Arm Limited
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+/**
+ * @file
+ * RTE Ring with user defined element size
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <rte_common.h>
+#include <rte_config.h>
+#include <rte_memory.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memzone.h>
+#include <rte_pause.h>
+
+#include "ring_impl.h"
+
+static __rte_always_inline void
+__rte_ring_enqueue_elems_32(struct rte_ring *r, const uint32_t size,
+		uint32_t idx, const void *obj_table, uint32_t n)
+{
+	unsigned int i;
+	uint32_t *ring = (uint32_t *)&r[1];
+	const uint32_t *obj = (const uint32_t *)obj_table;
+	if (likely(idx + n < size)) {
+		for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
+			ring[idx] = obj[i];
+			ring[idx + 1] = obj[i + 1];
+			ring[idx + 2] = obj[i + 2];
+			ring[idx + 3] = obj[i + 3];
+			ring[idx + 4] = obj[i + 4];
+			ring[idx + 5] = obj[i + 5];
+			ring[idx + 6] = obj[i + 6];
+			ring[idx + 7] = obj[i + 7];
+		}
+		switch (n & 0x7) {
+		case 7:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 6:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 5:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 4:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 3:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 2:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 1:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		}
+	} else {
+		for (i = 0; idx < size; i++, idx++)
+			ring[idx] = obj[i];
+		/* Start at the beginning */
+		for (idx = 0; i < n; i++, idx++)
+			ring[idx] = obj[i];
+	}
+}
+
+static __rte_always_inline void
+__rte_ring_enqueue_elems_64(struct rte_ring *r, uint32_t prod_head,
+		const void *obj_table, uint32_t n)
+{
+	unsigned int i;
+	const uint32_t size = r->size;
+	uint32_t idx = prod_head & r->mask;
+	uint64_t *ring = (uint64_t *)&r[1];
+	const uint64_t *obj = (const uint64_t *)obj_table;
+	if (likely(idx + n < size)) {
+		for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
+			ring[idx] = obj[i];
+			ring[idx + 1] = obj[i + 1];
+			ring[idx + 2] = obj[i + 2];
+			ring[idx + 3] = obj[i + 3];
+		}
+		switch (n & 0x3) {
+		case 3:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 2:
+			ring[idx++] = obj[i++]; /* fallthrough */
+		case 1:
+			ring[idx++] = obj[i++];
+		}
+	} else {
+		for (i = 0; idx < size; i++, idx++)
+			ring[idx] = obj[i];
+		/* Start at the beginning */
+		for (idx = 0; i < n; i++, idx++)
+			ring[idx] = obj[i];
+	}
+}
+
+static __rte_always_inline void
+__rte_ring_enqueue_elems_128(struct rte_ring *r, uint32_t prod_head,
+		const void *obj_table, uint32_t n)
+{
+	unsigned int i;
+	const uint32_t size = r->size;
+	uint32_t idx = prod_head & r->mask;
+	rte_int128_t *ring = (rte_int128_t *)&r[1];
+	const rte_int128_t *obj = (const rte_int128_t *)obj_table;
+	if (likely(idx + n < size)) {
+		for (i = 0; i < (n & ~0x1); i += 2, idx += 2)
+			memcpy((void *)(ring + idx),
+				(const void *)(obj + i), 32);
+		switch (n & 0x1) {
+		case 1:
+			memcpy((void *)(ring + idx),
+				(const void *)(obj + i), 16);
+		}
+	} else {
+		for (i = 0; idx < size; i++, idx++)
+			memcpy((void *)(ring + idx),
+				(const void *)(obj + i), 16);
+		/* Start at the beginning */
+		for (idx = 0; i < n; i++, idx++)
+			memcpy((void *)(ring + idx),
+				(const void *)(obj + i), 16);
+	}
+}
+
+/* the actual enqueue of elements on the ring.
+ * Placed here since identical code needed in both
+ * single and multi producer enqueue functions.
+ */
+static __rte_always_inline void
+__rte_ring_enqueue_elems(struct rte_ring *r, uint32_t prod_head,
+		const void *obj_table, uint32_t esize, uint32_t num)
+{
+	/* 8B and 16B copies implemented individually to retain
+	 * the current performance.
+	 */
+	if (esize == 8)
+		__rte_ring_enqueue_elems_64(r, prod_head, obj_table, num);
+	else if (esize == 16)
+		__rte_ring_enqueue_elems_128(r, prod_head, obj_table, num);
+	else {
+		uint32_t idx, scale, nr_idx, nr_num, nr_size;
+
+		/* Normalize to uint32_t */
+		scale = esize / sizeof(uint32_t);
+		nr_num = num * scale;
+		idx = prod_head & r->mask;
+		nr_idx = idx * scale;
+		nr_size = r->size * scale;
+		__rte_ring_enqueue_elems_32(r, nr_size, nr_idx,
+				obj_table, nr_num);
+	}
+}
+
+static __rte_always_inline void
+__rte_ring_dequeue_elems_32(struct rte_ring *r, const uint32_t size,
+		uint32_t idx, void *obj_table, uint32_t n)
+{
+	unsigned int i;
+	uint32_t *ring = (uint32_t *)&r[1];
+	uint32_t *obj = (uint32_t *)obj_table;
+	if (likely(idx + n < size)) {
+		for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
+			obj[i] = ring[idx];
+			obj[i + 1] = ring[idx + 1];
+			obj[i + 2] = ring[idx + 2];
+			obj[i + 3] = ring[idx + 3];
+			obj[i + 4] = ring[idx + 4];
+			obj[i + 5] = ring[idx + 5];
+			obj[i + 6] = ring[idx + 6];
+			obj[i + 7] = ring[idx + 7];
+		}
+		switch (n & 0x7) {
+		case 7:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 6:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 5:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 4:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 3:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 2:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 1:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		}
+	} else {
+		for (i = 0; idx < size; i++, idx++)
+			obj[i] = ring[idx];
+		/* Start at the beginning */
+		for (idx = 0; i < n; i++, idx++)
+			obj[i] = ring[idx];
+	}
+}
+
+static __rte_always_inline void
+__rte_ring_dequeue_elems_64(struct rte_ring *r, uint32_t prod_head,
+		void *obj_table, uint32_t n)
+{
+	unsigned int i;
+	const uint32_t size = r->size;
+	uint32_t idx = prod_head & r->mask;
+	uint64_t *ring = (uint64_t *)&r[1];
+	uint64_t *obj = (uint64_t *)obj_table;
+	if (likely(idx + n < size)) {
+		for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
+			obj[i] = ring[idx];
+			obj[i + 1] = ring[idx + 1];
+			obj[i + 2] = ring[idx + 2];
+			obj[i + 3] = ring[idx + 3];
+		}
+		switch (n & 0x3) {
+		case 3:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 2:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		case 1:
+			obj[i++] = ring[idx++]; /* fallthrough */
+		}
+	} else {
+		for (i = 0; idx < size; i++, idx++)
+			obj[i] = ring[idx];
+		/* Start at the beginning */
+		for (idx = 0; i < n; i++, idx++)
+			obj[i] = ring[idx];
+	}
+}
+
+static __rte_always_inline void
+__rte_ring_dequeue_elems_128(struct rte_ring *r, uint32_t prod_head,
+		void *obj_table, uint32_t n)
+{
+	unsigned int i;
+	const uint32_t size = r->size;
+	uint32_t idx = prod_head & r->mask;
+	rte_int128_t *ring = (rte_int128_t *)&r[1];
+	rte_int128_t *obj = (rte_int128_t *)obj_table;
+	if (likely(idx + n < size)) {
+		for (i = 0; i < (n & ~0x1); i += 2, idx += 2)
+			memcpy((void *)(obj + i), (void *)(ring + idx), 32);
+		switch (n & 0x1) {
+		case 1:
+			memcpy((void *)(obj + i), (void *)(ring + idx), 16);
+		}
+	} else {
+		for (i = 0; idx < size; i++, idx++)
+			memcpy((void *)(obj + i), (void *)(ring + idx), 16);
+		/* Start at the beginning */
+		for (idx = 0; i < n; i++, idx++)
+			memcpy((void *)(obj + i), (void *)(ring + idx), 16);
+	}
+}
+
+/* the actual dequeue of elements from the ring.
+ * Placed here since identical code needed in both
+ * single and multi producer enqueue functions.
+ */
+static __rte_always_inline void
+__rte_ring_dequeue_elems(struct rte_ring *r, uint32_t cons_head,
+		void *obj_table, uint32_t esize, uint32_t num)
+{
+	/* 8B and 16B copies implemented individually to retain
+	 * the current performance.
+	 */
+	if (esize == 8)
+		__rte_ring_dequeue_elems_64(r, cons_head, obj_table, num);
+	else if (esize == 16)
+		__rte_ring_dequeue_elems_128(r, cons_head, obj_table, num);
+	else {
+		uint32_t idx, scale, nr_idx, nr_num, nr_size;
+
+		/* Normalize to uint32_t */
+		scale = esize / sizeof(uint32_t);
+		nr_num = num * scale;
+		idx = cons_head & r->mask;
+		nr_idx = idx * scale;
+		nr_size = r->size * scale;
+		__rte_ring_dequeue_elems_32(r, nr_size, nr_idx,
+				obj_table, nr_num);
+	}
+}
+
+/* Between load and load. there might be cpu reorder in weak model
+ * (powerpc/arm).
+ * There are 2 choices for the users
+ * 1.use rmb() memory barrier
+ * 2.use one-direction load_acquire/store_release barrier,defined by
+ * CONFIG_RTE_USE_C11_MEM_MODEL=y
+ * It depends on performance test results.
+ * By default, move common functions to rte_ring_generic.h
+ */
+#ifdef RTE_USE_C11_MEM_MODEL
+#include "rte_ring_c11_mem.h"
+#else
+#include "rte_ring_generic.h"
+#endif
+
+/**
+ * @internal Enqueue several objects on the ring
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param is_sp
+ *   Indicates whether to use single producer or multi-producer head update
+ * @param free_space
+ *   returns the amount of space after the enqueue operation has finished
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_enqueue_elem(struct rte_ring *r, const void *obj_table,
+		unsigned int esize, unsigned int n,
+		enum rte_ring_queue_behavior behavior, unsigned int is_sp,
+		unsigned int *free_space)
+{
+	uint32_t prod_head, prod_next;
+	uint32_t free_entries;
+
+	n = __rte_ring_move_prod_head(r, is_sp, n, behavior,
+			&prod_head, &prod_next, &free_entries);
+	if (n == 0)
+		goto end;
+
+	__rte_ring_enqueue_elems(r, prod_head, obj_table, esize, n);
+
+	update_tail(&r->prod, prod_head, prod_next, is_sp, 1);
+end:
+	if (free_space != NULL)
+		*free_space = free_entries - n;
+	return n;
+}
+
+/**
+ * @internal Dequeue several objects from the ring
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to pull from the ring.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param is_sc
+ *   Indicates whether to use single consumer or multi-consumer head update
+ * @param available
+ *   returns the number of remaining ring entries after the dequeue has finished
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_dequeue_elem(struct rte_ring *r, void *obj_table,
+		unsigned int esize, unsigned int n,
+		enum rte_ring_queue_behavior behavior, unsigned int is_sc,
+		unsigned int *available)
+{
+	uint32_t cons_head, cons_next;
+	uint32_t entries;
+
+	n = __rte_ring_move_cons_head(r, (int)is_sc, n, behavior,
+			&cons_head, &cons_next, &entries);
+	if (n == 0)
+		goto end;
+
+	__rte_ring_dequeue_elems(r, cons_head, obj_table, esize, n);
+
+	update_tail(&r->cons, cons_head, cons_next, is_sc, 0);
+
+end:
+	if (available != NULL)
+		*available = entries - n;
+	return n;
+}
+
+/**
+ * Enqueue several objects on the ring (multi-producers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * producer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+unsigned int
+rte_ring_mp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_FIXED, __IS_MP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring
+ *
+ * @warning This API is NOT multi-producers safe
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+unsigned int
+rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_FIXED, __IS_SP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring.
+ *
+ * This function calls the multi-producer or the single-producer
+ * version depending on the default behavior that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+unsigned int
+rte_ring_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_FIXED, r->prod.single, free_space);
+}
+
+/**
+ * Enqueue one object on a ring (multi-producers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * producer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj
+ *   A pointer to the object to be added.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @return
+ *   - 0: Success; objects enqueued.
+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
+ */
+int
+rte_ring_mp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
+{
+	return rte_ring_mp_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :
+								-ENOBUFS;
+}
+
+/**
+ * Enqueue one object on a ring
+ *
+ * @warning This API is NOT multi-producers safe
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj
+ *   A pointer to the object to be added.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @return
+ *   - 0: Success; objects enqueued.
+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
+ */
+int
+rte_ring_sp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
+{
+	return rte_ring_sp_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :
+								-ENOBUFS;
+}
+
+/**
+ * Enqueue one object on a ring.
+ *
+ * This function calls the multi-producer or the single-producer
+ * version, depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj
+ *   A pointer to the object to be added.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @return
+ *   - 0: Success; objects enqueued.
+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
+ */
+int
+rte_ring_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
+{
+	return rte_ring_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :
+								-ENOBUFS;
+}
+
+/**
+ * Dequeue several objects from a ring (multi-consumers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * consumer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+unsigned int
+rte_ring_mc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
+				RTE_RING_QUEUE_FIXED, __IS_MC, available);
+}
+
+/**
+ * Dequeue several objects from a ring (NOT multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table,
+ *   must be strictly positive.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+unsigned int
+rte_ring_sc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_FIXED, __IS_SC, available);
+}
+
+/**
+ * Dequeue several objects from a ring.
+ *
+ * This function calls the multi-consumers or the single-consumer
+ * version, depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+unsigned int
+rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_FIXED, r->cons.single, available);
+}
+
+/**
+ * Dequeue one object from a ring (multi-consumers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * consumer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_p
+ *   A pointer to the object that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @return
+ *   - 0: Success; objects dequeued.
+ *   - -ENOENT: Not enough entries in the ring to dequeue; no object is
+ *     dequeued.
+ */
+int
+rte_ring_mc_dequeue_elem(struct rte_ring *r, void *obj_p,
+				unsigned int esize)
+{
+	return rte_ring_mc_dequeue_bulk_elem(r, obj_p, esize, 1, NULL)  ? 0 :
+								-ENOENT;
+}
+
+/**
+ * Dequeue one object from a ring (NOT multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_p
+ *   A pointer to the object that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @return
+ *   - 0: Success; objects dequeued.
+ *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
+ *     dequeued.
+ */
+int
+rte_ring_sc_dequeue_elem(struct rte_ring *r, void *obj_p,
+				unsigned int esize)
+{
+	return rte_ring_sc_dequeue_bulk_elem(r, obj_p, esize, 1, NULL) ? 0 :
+								-ENOENT;
+}
+
+/**
+ * Dequeue one object from a ring.
+ *
+ * This function calls the multi-consumers or the single-consumer
+ * version depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_p
+ *   A pointer to the object that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @return
+ *   - 0: Success, objects dequeued.
+ *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
+ *     dequeued.
+ */
+int
+rte_ring_dequeue_elem(struct rte_ring *r, void *obj_p, unsigned int esize)
+{
+	return rte_ring_dequeue_bulk_elem(r, obj_p, esize, 1, NULL) ? 0 :
+								-ENOENT;
+}
+
+/**
+ * Enqueue several objects on the ring (multi-producers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * producer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+unsigned
+rte_ring_mp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_MP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring
+ *
+ * @warning This API is NOT multi-producers safe
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+unsigned
+rte_ring_sp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_SP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring.
+ *
+ * This function calls the multi-producer or the single-producer
+ * version depending on the default behavior that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+unsigned
+rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, r->prod.single, free_space);
+}
+
+/**
+ * Dequeue several objects from a ring (multi-consumers safe). When the request
+ * objects are more than the available objects, only dequeue the actual number
+ * of objects
+ *
+ * This function uses a "compare and set" instruction to move the
+ * consumer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+unsigned
+rte_ring_mc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_MC, available);
+}
+
+/**
+ * Dequeue several objects from a ring (NOT multi-consumers safe).When the
+ * request objects are more than the available objects, only dequeue the
+ * actual number of objects
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+unsigned
+rte_ring_sc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_SC, available);
+}
+
+/**
+ * Dequeue multiple objects from a ring up to a maximum number.
+ *
+ * This function calls the multi-consumers or the single-consumer
+ * version, depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of objects that will be filled.
+ * @param esize
+ *   The size of ring element, in bytes. It must be a multiple of 4.
+ *   This must be the same value used while creating the ring. Otherwise
+ *   the results are undefined.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - Number of objects dequeued
+ */
+unsigned int
+rte_ring_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
+		unsigned int esize, unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
+				RTE_RING_QUEUE_VARIABLE,
+				r->cons.single, available);
+}
diff --git a/lib/librte_ring/ring_impl.c b/lib/librte_ring/ring_impl.c
new file mode 100644
index 000000000..ee85c515f
--- /dev/null
+++ b/lib/librte_ring/ring_impl.c
@@ -0,0 +1,750 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <rte_common.h>
+#include <rte_config.h>
+#include <rte_memory.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memzone.h>
+#include <rte_pause.h>
+#include "ring_impl.h"
+
+/* the actual enqueue of pointers on the ring.
+ * Placed here since identical code needed in both
+ * single and multi producer enqueue functions */
+#define ENQUEUE_PTRS(r, ring_start, prod_head, obj_table, n, obj_type) do { \
+	unsigned int i; \
+	const uint32_t size = (r)->size; \
+	uint32_t idx = prod_head & (r)->mask; \
+	obj_type *ring = (obj_type *)ring_start; \
+	if (likely(idx + n < size)) { \
+		for (i = 0; i < (n & ((~(unsigned)0x3))); i+=4, idx+=4) { \
+			ring[idx] = obj_table[i]; \
+			ring[idx+1] = obj_table[i+1]; \
+			ring[idx+2] = obj_table[i+2]; \
+			ring[idx+3] = obj_table[i+3]; \
+		} \
+		switch (n & 0x3) { \
+		case 3: \
+			ring[idx++] = obj_table[i++]; /* fallthrough */ \
+		case 2: \
+			ring[idx++] = obj_table[i++]; /* fallthrough */ \
+		case 1: \
+			ring[idx++] = obj_table[i++]; \
+		} \
+	} else { \
+		for (i = 0; idx < size; i++, idx++)\
+			ring[idx] = obj_table[i]; \
+		for (idx = 0; i < n; i++, idx++) \
+			ring[idx] = obj_table[i]; \
+	} \
+} while (0)
+
+/* the actual copy of pointers on the ring to obj_table.
+ * Placed here since identical code needed in both
+ * single and multi consumer dequeue functions */
+#define DEQUEUE_PTRS(r, ring_start, cons_head, obj_table, n, obj_type) do { \
+	unsigned int i; \
+	uint32_t idx = cons_head & (r)->mask; \
+	const uint32_t size = (r)->size; \
+	obj_type *ring = (obj_type *)ring_start; \
+	if (likely(idx + n < size)) { \
+		for (i = 0; i < (n & (~(unsigned)0x3)); i+=4, idx+=4) {\
+			obj_table[i] = ring[idx]; \
+			obj_table[i+1] = ring[idx+1]; \
+			obj_table[i+2] = ring[idx+2]; \
+			obj_table[i+3] = ring[idx+3]; \
+		} \
+		switch (n & 0x3) { \
+		case 3: \
+			obj_table[i++] = ring[idx++]; /* fallthrough */ \
+		case 2: \
+			obj_table[i++] = ring[idx++]; /* fallthrough */ \
+		case 1: \
+			obj_table[i++] = ring[idx++]; \
+		} \
+	} else { \
+		for (i = 0; idx < size; i++, idx++) \
+			obj_table[i] = ring[idx]; \
+		for (idx = 0; i < n; i++, idx++) \
+			obj_table[i] = ring[idx]; \
+	} \
+} while (0)
+
+/* Between load and load. there might be cpu reorder in weak model
+ * (powerpc/arm).
+ * There are 2 choices for the users
+ * 1.use rmb() memory barrier
+ * 2.use one-direction load_acquire/store_release barrier,defined by
+ * CONFIG_RTE_USE_C11_MEM_MODEL=y
+ * It depends on performance test results.
+ * By default, move common functions to rte_ring_generic.h
+ */
+#ifdef RTE_USE_C11_MEM_MODEL
+#include "rte_ring_c11_mem.h"
+#else
+#include "rte_ring_generic.h"
+#endif
+
+/**
+ * @internal Enqueue several objects on the ring
+ *
+  * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
+ * @param is_sp
+ *   Indicates whether to use single producer or multi-producer head update
+ * @param free_space
+ *   returns the amount of space after the enqueue operation has finished
+ * @return
+ *   Actual number of objects enqueued.
+ *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_enqueue(struct rte_ring *r, void * const *obj_table,
+		 unsigned int n, enum rte_ring_queue_behavior behavior,
+		 unsigned int is_sp, unsigned int *free_space)
+{
+	uint32_t prod_head, prod_next;
+	uint32_t free_entries;
+
+	n = __rte_ring_move_prod_head(r, is_sp, n, behavior,
+			&prod_head, &prod_next, &free_entries);
+	if (n == 0)
+		goto end;
+
+	ENQUEUE_PTRS(r, &r[1], prod_head, obj_table, n, void *);
+
+	update_tail(&r->prod, prod_head, prod_next, is_sp, 1);
+end:
+	if (free_space != NULL)
+		*free_space = free_entries - n;
+	return n;
+}
+
+/**
+ * @internal Dequeue several objects from the ring
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to pull from the ring.
+ * @param behavior
+ *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
+ *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
+ * @param is_sc
+ *   Indicates whether to use single consumer or multi-consumer head update
+ * @param available
+ *   returns the number of remaining ring entries after the dequeue has finished
+ * @return
+ *   - Actual number of objects dequeued.
+ *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
+ */
+static __rte_always_inline unsigned int
+__rte_ring_do_dequeue(struct rte_ring *r, void **obj_table,
+		 unsigned int n, enum rte_ring_queue_behavior behavior,
+		 unsigned int is_sc, unsigned int *available)
+{
+	uint32_t cons_head, cons_next;
+	uint32_t entries;
+
+	n = __rte_ring_move_cons_head(r, (int)is_sc, n, behavior,
+			&cons_head, &cons_next, &entries);
+	if (n == 0)
+		goto end;
+
+	DEQUEUE_PTRS(r, &r[1], cons_head, obj_table, n, void *);
+
+	update_tail(&r->cons, cons_head, cons_next, is_sc, 0);
+
+end:
+	if (available != NULL)
+		*available = entries - n;
+	return n;
+}
+
+/**
+ * Enqueue several objects on the ring (multi-producers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * producer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+unsigned int
+rte_ring_mp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			__IS_MP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring (NOT multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+unsigned int
+rte_ring_sp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			__IS_SP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring.
+ *
+ * This function calls the multi-producer or the single-producer
+ * version depending on the default behavior that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   The number of objects enqueued, either 0 or n
+ */
+unsigned int
+rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
+		      unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			r->prod.single, free_space);
+}
+
+/**
+ * Enqueue one object on a ring (multi-producers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * producer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj
+ *   A pointer to the object to be added.
+ * @return
+ *   - 0: Success; objects enqueued.
+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
+ */
+int
+rte_ring_mp_enqueue(struct rte_ring *r, void *obj)
+{
+	return rte_ring_mp_enqueue_bulk(r, &obj, 1, NULL) ? 0 : -ENOBUFS;
+}
+
+/**
+ * Enqueue one object on a ring (NOT multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj
+ *   A pointer to the object to be added.
+ * @return
+ *   - 0: Success; objects enqueued.
+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
+ */
+int
+rte_ring_sp_enqueue(struct rte_ring *r, void *obj)
+{
+	return rte_ring_sp_enqueue_bulk(r, &obj, 1, NULL) ? 0 : -ENOBUFS;
+}
+
+/**
+ * Enqueue one object on a ring.
+ *
+ * This function calls the multi-producer or the single-producer
+ * version, depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj
+ *   A pointer to the object to be added.
+ * @return
+ *   - 0: Success; objects enqueued.
+ *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
+ */
+int
+rte_ring_enqueue(struct rte_ring *r, void *obj)
+{
+	return rte_ring_enqueue_bulk(r, &obj, 1, NULL) ? 0 : -ENOBUFS;
+}
+
+/**
+ * Dequeue several objects from a ring (multi-consumers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * consumer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+unsigned int
+rte_ring_mc_dequeue_bulk(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			__IS_MC, available);
+}
+
+/**
+ * Dequeue several objects from a ring (NOT multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table,
+ *   must be strictly positive.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+unsigned int
+rte_ring_sc_dequeue_bulk(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+			__IS_SC, available);
+}
+
+/**
+ * Dequeue several objects from a ring.
+ *
+ * This function calls the multi-consumers or the single-consumer
+ * version, depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   The number of objects dequeued, either 0 or n
+ */
+unsigned int
+rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,
+		unsigned int *available)
+{
+	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
+				r->cons.single, available);
+}
+
+/**
+ * Dequeue one object from a ring (multi-consumers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * consumer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_p
+ *   A pointer to a void * pointer (object) that will be filled.
+ * @return
+ *   - 0: Success; objects dequeued.
+ *   - -ENOENT: Not enough entries in the ring to dequeue; no object is
+ *     dequeued.
+ */
+int
+rte_ring_mc_dequeue(struct rte_ring *r, void **obj_p)
+{
+	return rte_ring_mc_dequeue_bulk(r, obj_p, 1, NULL)  ? 0 : -ENOENT;
+}
+
+/**
+ * Dequeue one object from a ring (NOT multi-consumers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_p
+ *   A pointer to a void * pointer (object) that will be filled.
+ * @return
+ *   - 0: Success; objects dequeued.
+ *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
+ *     dequeued.
+ */
+int
+rte_ring_sc_dequeue(struct rte_ring *r, void **obj_p)
+{
+	return rte_ring_sc_dequeue_bulk(r, obj_p, 1, NULL) ? 0 : -ENOENT;
+}
+
+/**
+ * Dequeue one object from a ring.
+ *
+ * This function calls the multi-consumers or the single-consumer
+ * version depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_p
+ *   A pointer to a void * pointer (object) that will be filled.
+ * @return
+ *   - 0: Success, objects dequeued.
+ *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
+ *     dequeued.
+ */
+int
+rte_ring_dequeue(struct rte_ring *r, void **obj_p)
+{
+	return rte_ring_dequeue_bulk(r, obj_p, 1, NULL) ? 0 : -ENOENT;
+}
+
+/**
+ * Return the number of entries in a ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   The number of entries in the ring.
+ */
+unsigned
+rte_ring_count(const struct rte_ring *r)
+{
+	uint32_t prod_tail = r->prod.tail;
+	uint32_t cons_tail = r->cons.tail;
+	uint32_t count = (prod_tail - cons_tail) & r->mask;
+	return (count > r->capacity) ? r->capacity : count;
+}
+
+/**
+ * Return the number of free entries in a ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   The number of free entries in the ring.
+ */
+unsigned
+rte_ring_free_count(const struct rte_ring *r)
+{
+	return r->capacity - rte_ring_count(r);
+}
+
+/**
+ * Test if a ring is full.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   - 1: The ring is full.
+ *   - 0: The ring is not full.
+ */
+int
+rte_ring_full(const struct rte_ring *r)
+{
+	return rte_ring_free_count(r) == 0;
+}
+
+/**
+ * Test if a ring is empty.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   - 1: The ring is empty.
+ *   - 0: The ring is not empty.
+ */
+int
+rte_ring_empty(const struct rte_ring *r)
+{
+	return rte_ring_count(r) == 0;
+}
+
+const char *
+rte_ring_get_name(const struct rte_ring *r)
+{
+	return r->name;
+}
+
+const struct rte_memzone *
+rte_ring_get_memzone(const struct rte_ring *r)
+{
+	return r->memzone;
+}
+
+/**
+ * Return the size of the ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   The size of the data store used by the ring.
+ *   NOTE: this is not the same as the usable space in the ring. To query that
+ *   use ``rte_ring_get_capacity()``.
+ */
+unsigned int
+rte_ring_get_size(const struct rte_ring *r)
+{
+	return r->size;
+}
+
+/**
+ * Return the number of elements which can be stored in the ring.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @return
+ *   The usable size of the ring.
+ */
+unsigned int
+rte_ring_get_capacity(const struct rte_ring *r)
+{
+	return r->capacity;
+}
+
+uint32_t
+rte_ring_get_prod_sync_type(const struct rte_ring *r)
+{
+	return (r->prod.single == __IS_SP) ?
+		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
+}
+
+uint32_t
+rte_ring_get_cons_sync_type(const struct rte_ring *r)
+{
+	return (r->cons.single == __IS_SC) ?
+		RTE_RING_SYNC_ST : RTE_RING_SYNC_MT;
+}
+
+/**
+ * Dump the status of all rings on the console
+ *
+ * @param f
+ *   A pointer to a file for output
+ */
+void rte_ring_list_dump(FILE *f);
+
+/**
+ * Search a ring from its name
+ *
+ * @param name
+ *   The name of the ring.
+ * @return
+ *   The pointer to the ring matching the name, or NULL if not found,
+ *   with rte_errno set appropriately. Possible rte_errno values include:
+ *    - ENOENT - required entry not available to return.
+ */
+struct rte_ring *rte_ring_lookup(const char *name);
+
+/**
+ * Enqueue several objects on the ring (multi-producers safe).
+ *
+ * This function uses a "compare and set" instruction to move the
+ * producer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+unsigned
+rte_ring_mp_enqueue_burst(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_MP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring (NOT multi-producers safe).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+unsigned
+rte_ring_sp_enqueue_burst(struct rte_ring *r, void * const *obj_table,
+			 unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_SP, free_space);
+}
+
+/**
+ * Enqueue several objects on a ring.
+ *
+ * This function calls the multi-producer or the single-producer
+ * version depending on the default behavior that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects).
+ * @param n
+ *   The number of objects to add in the ring from the obj_table.
+ * @param free_space
+ *   if non-NULL, returns the amount of space in the ring after the
+ *   enqueue operation has finished.
+ * @return
+ *   - n: Actual number of objects enqueued.
+ */
+unsigned
+rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table,
+		      unsigned int n, unsigned int *free_space)
+{
+	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_VARIABLE,
+			r->prod.single, free_space);
+}
+
+/**
+ * Dequeue several objects from a ring (multi-consumers safe). When the request
+ * objects are more than the available objects, only dequeue the actual number
+ * of objects
+ *
+ * This function uses a "compare and set" instruction to move the
+ * consumer index atomically.
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+unsigned
+rte_ring_mc_dequeue_burst(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_MC, available);
+}
+
+/**
+ * Dequeue several objects from a ring (NOT multi-consumers safe).When the
+ * request objects are more than the available objects, only dequeue the
+ * actual number of objects
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - n: Actual number of objects dequeued, 0 if ring is empty
+ */
+unsigned
+rte_ring_sc_dequeue_burst(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue(r, obj_table, n,
+			RTE_RING_QUEUE_VARIABLE, __IS_SC, available);
+}
+
+/**
+ * Dequeue multiple objects from a ring up to a maximum number.
+ *
+ * This function calls the multi-consumers or the single-consumer
+ * version, depending on the default behaviour that was specified at
+ * ring creation time (see flags).
+ *
+ * @param r
+ *   A pointer to the ring structure.
+ * @param obj_table
+ *   A pointer to a table of void * pointers (objects) that will be filled.
+ * @param n
+ *   The number of objects to dequeue from the ring to the obj_table.
+ * @param available
+ *   If non-NULL, returns the number of remaining ring entries after the
+ *   dequeue has finished.
+ * @return
+ *   - Number of objects dequeued
+ */
+unsigned
+rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table,
+		unsigned int n, unsigned int *available)
+{
+	return __rte_ring_do_dequeue(r, obj_table, n,
+				RTE_RING_QUEUE_VARIABLE,
+				r->cons.single, available);
+}
diff --git a/lib/librte_ring/ring_impl.h b/lib/librte_ring/ring_impl.h
new file mode 100644
index 000000000..4ed375511
--- /dev/null
+++ b/lib/librte_ring/ring_impl.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010-2017 Intel Corporation
+ * Copyright (c) 2007-2009 Kip Macy kmacy@freebsd.org
+ * All rights reserved.
+ * Derived from FreeBSD's bufring.h
+ * Used as BSD-3 Licensed with permission from Kip Macy.
+ */
+
+#ifndef _RING_IMPL_H_
+#define _RING_IMPL_H_
+
+#include <rte_ring.h>
+#include <rte_ring_elem.h>
+
+/* @internal defines for passing to the enqueue dequeue worker functions */
+#define __IS_SP 1
+#define __IS_MP 0
+#define __IS_SC 1
+#define __IS_MC 0
+
+/* structure to hold a pair of head/tail values and other metadata */
+struct rte_ring_headtail {
+	volatile uint32_t head;  /**< Prod/consumer head. */
+	volatile uint32_t tail;  /**< Prod/consumer tail. */
+	uint32_t single;         /**< True if single prod/cons */
+};
+
+/**
+ * An RTE ring structure.
+ *
+ * The producer and the consumer have a head and a tail index. The particularity
+ * of these index is that they are not between 0 and size(ring). These indexes
+ * are between 0 and 2^32, and we mask their value when we access the ring[]
+ * field. Thanks to this assumption, we can do subtractions between 2 index
+ * values in a modulo-32bit base: that's why the overflow of the indexes is not
+ * a problem.
+ */
+struct rte_ring {
+	/*
+	 * Note: this field kept the RTE_MEMZONE_NAMESIZE size due to ABI
+	 * compatibility requirements, it could be changed to RTE_RING_NAMESIZE
+	 * next time the ABI changes
+	 */
+	char name[RTE_MEMZONE_NAMESIZE] __rte_cache_aligned; /**< Name of the ring. */
+	int flags;               /**< Flags supplied at creation. */
+	const struct rte_memzone *memzone;
+			/**< Memzone, if any, containing the rte_ring */
+	uint32_t size;           /**< Size of ring. */
+	uint32_t mask;           /**< Mask (size-1) of ring. */
+	uint32_t capacity;       /**< Usable size of ring */
+
+	char pad0 __rte_cache_aligned; /**< empty cache line */
+
+	/** Ring producer status. */
+	struct rte_ring_headtail prod __rte_cache_aligned;
+	char pad1 __rte_cache_aligned; /**< empty cache line */
+
+	/** Ring consumer status. */
+	struct rte_ring_headtail cons __rte_cache_aligned;
+	char pad2 __rte_cache_aligned; /**< empty cache line */
+};
+
+#endif /* _RING_IMPL_H_ */
diff --git a/lib/librte_ring/rte_ring.c b/lib/librte_ring/rte_ring.c
index 77e5de099..ec9392585 100644
--- a/lib/librte_ring/rte_ring.c
+++ b/lib/librte_ring/rte_ring.c
@@ -32,8 +32,7 @@
 #include <rte_spinlock.h>
 #include <rte_tailq.h>
 
-#include "rte_ring.h"
-#include "rte_ring_elem.h"
+#include "ring_impl.h"
 
 TAILQ_HEAD(rte_ring_list, rte_tailq_entry);
 
diff --git a/lib/librte_ring/rte_ring.h b/lib/librte_ring/rte_ring.h
index 18fc5d845..a1442c360 100644
--- a/lib/librte_ring/rte_ring.h
+++ b/lib/librte_ring/rte_ring.h
@@ -56,53 +56,17 @@ enum rte_ring_queue_behavior {
 	RTE_RING_QUEUE_VARIABLE   /* Enq/Deq as many items as possible from ring */
 };
 
+/** prod/cons sync types */
+enum {
+	RTE_RING_SYNC_MT,     /**< multi-thread safe (default mode) */
+	RTE_RING_SYNC_ST,     /**< single thread only */
+};
+
 #define RTE_RING_MZ_PREFIX "RG_"
 /** The maximum length of a ring name. */
 #define RTE_RING_NAMESIZE (RTE_MEMZONE_NAMESIZE - \
 			   sizeof(RTE_RING_MZ_PREFIX) + 1)
 
-/* structure to hold a pair of head/tail values and other metadata */
-struct rte_ring_headtail {
-	volatile uint32_t head;  /**< Prod/consumer head. */
-	volatile uint32_t tail;  /**< Prod/consumer tail. */
-	uint32_t single;         /**< True if single prod/cons */
-};
-
-/**
- * An RTE ring structure.
- *
- * The producer and the consumer have a head and a tail index. The particularity
- * of these index is that they are not between 0 and size(ring). These indexes
- * are between 0 and 2^32, and we mask their value when we access the ring[]
- * field. Thanks to this assumption, we can do subtractions between 2 index
- * values in a modulo-32bit base: that's why the overflow of the indexes is not
- * a problem.
- */
-struct rte_ring {
-	/*
-	 * Note: this field kept the RTE_MEMZONE_NAMESIZE size due to ABI
-	 * compatibility requirements, it could be changed to RTE_RING_NAMESIZE
-	 * next time the ABI changes
-	 */
-	char name[RTE_MEMZONE_NAMESIZE] __rte_cache_aligned; /**< Name of the ring. */
-	int flags;               /**< Flags supplied at creation. */
-	const struct rte_memzone *memzone;
-			/**< Memzone, if any, containing the rte_ring */
-	uint32_t size;           /**< Size of ring. */
-	uint32_t mask;           /**< Mask (size-1) of ring. */
-	uint32_t capacity;       /**< Usable size of ring */
-
-	char pad0 __rte_cache_aligned; /**< empty cache line */
-
-	/** Ring producer status. */
-	struct rte_ring_headtail prod __rte_cache_aligned;
-	char pad1 __rte_cache_aligned; /**< empty cache line */
-
-	/** Ring consumer status. */
-	struct rte_ring_headtail cons __rte_cache_aligned;
-	char pad2 __rte_cache_aligned; /**< empty cache line */
-};
-
 #define RING_F_SP_ENQ 0x0001 /**< The default enqueue is "single-producer". */
 #define RING_F_SC_DEQ 0x0002 /**< The default dequeue is "single-consumer". */
 /**
@@ -116,11 +80,7 @@ struct rte_ring {
 #define RING_F_EXACT_SZ 0x0004
 #define RTE_RING_SZ_MASK  (0x7fffffffU) /**< Ring size mask */
 
-/* @internal defines for passing to the enqueue dequeue worker functions */
-#define __IS_SP 1
-#define __IS_MP 0
-#define __IS_SC 1
-#define __IS_MC 0
+struct rte_ring;
 
 /**
  * Calculate the memory size needed for a ring
@@ -235,168 +195,6 @@ void rte_ring_free(struct rte_ring *r);
  */
 void rte_ring_dump(FILE *f, const struct rte_ring *r);
 
-/* the actual enqueue of pointers on the ring.
- * Placed here since identical code needed in both
- * single and multi producer enqueue functions */
-#define ENQUEUE_PTRS(r, ring_start, prod_head, obj_table, n, obj_type) do { \
-	unsigned int i; \
-	const uint32_t size = (r)->size; \
-	uint32_t idx = prod_head & (r)->mask; \
-	obj_type *ring = (obj_type *)ring_start; \
-	if (likely(idx + n < size)) { \
-		for (i = 0; i < (n & ((~(unsigned)0x3))); i+=4, idx+=4) { \
-			ring[idx] = obj_table[i]; \
-			ring[idx+1] = obj_table[i+1]; \
-			ring[idx+2] = obj_table[i+2]; \
-			ring[idx+3] = obj_table[i+3]; \
-		} \
-		switch (n & 0x3) { \
-		case 3: \
-			ring[idx++] = obj_table[i++]; /* fallthrough */ \
-		case 2: \
-			ring[idx++] = obj_table[i++]; /* fallthrough */ \
-		case 1: \
-			ring[idx++] = obj_table[i++]; \
-		} \
-	} else { \
-		for (i = 0; idx < size; i++, idx++)\
-			ring[idx] = obj_table[i]; \
-		for (idx = 0; i < n; i++, idx++) \
-			ring[idx] = obj_table[i]; \
-	} \
-} while (0)
-
-/* the actual copy of pointers on the ring to obj_table.
- * Placed here since identical code needed in both
- * single and multi consumer dequeue functions */
-#define DEQUEUE_PTRS(r, ring_start, cons_head, obj_table, n, obj_type) do { \
-	unsigned int i; \
-	uint32_t idx = cons_head & (r)->mask; \
-	const uint32_t size = (r)->size; \
-	obj_type *ring = (obj_type *)ring_start; \
-	if (likely(idx + n < size)) { \
-		for (i = 0; i < (n & (~(unsigned)0x3)); i+=4, idx+=4) {\
-			obj_table[i] = ring[idx]; \
-			obj_table[i+1] = ring[idx+1]; \
-			obj_table[i+2] = ring[idx+2]; \
-			obj_table[i+3] = ring[idx+3]; \
-		} \
-		switch (n & 0x3) { \
-		case 3: \
-			obj_table[i++] = ring[idx++]; /* fallthrough */ \
-		case 2: \
-			obj_table[i++] = ring[idx++]; /* fallthrough */ \
-		case 1: \
-			obj_table[i++] = ring[idx++]; \
-		} \
-	} else { \
-		for (i = 0; idx < size; i++, idx++) \
-			obj_table[i] = ring[idx]; \
-		for (idx = 0; i < n; i++, idx++) \
-			obj_table[i] = ring[idx]; \
-	} \
-} while (0)
-
-/* Between load and load. there might be cpu reorder in weak model
- * (powerpc/arm).
- * There are 2 choices for the users
- * 1.use rmb() memory barrier
- * 2.use one-direction load_acquire/store_release barrier,defined by
- * CONFIG_RTE_USE_C11_MEM_MODEL=y
- * It depends on performance test results.
- * By default, move common functions to rte_ring_generic.h
- */
-#ifdef RTE_USE_C11_MEM_MODEL
-#include "rte_ring_c11_mem.h"
-#else
-#include "rte_ring_generic.h"
-#endif
-
-/**
- * @internal Enqueue several objects on the ring
- *
-  * @param r
- *   A pointer to the ring structure.
- * @param obj_table
- *   A pointer to a table of void * pointers (objects).
- * @param n
- *   The number of objects to add in the ring from the obj_table.
- * @param behavior
- *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
- *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
- * @param is_sp
- *   Indicates whether to use single producer or multi-producer head update
- * @param free_space
- *   returns the amount of space after the enqueue operation has finished
- * @return
- *   Actual number of objects enqueued.
- *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
- */
-static __rte_always_inline unsigned int
-__rte_ring_do_enqueue(struct rte_ring *r, void * const *obj_table,
-		 unsigned int n, enum rte_ring_queue_behavior behavior,
-		 unsigned int is_sp, unsigned int *free_space)
-{
-	uint32_t prod_head, prod_next;
-	uint32_t free_entries;
-
-	n = __rte_ring_move_prod_head(r, is_sp, n, behavior,
-			&prod_head, &prod_next, &free_entries);
-	if (n == 0)
-		goto end;
-
-	ENQUEUE_PTRS(r, &r[1], prod_head, obj_table, n, void *);
-
-	update_tail(&r->prod, prod_head, prod_next, is_sp, 1);
-end:
-	if (free_space != NULL)
-		*free_space = free_entries - n;
-	return n;
-}
-
-/**
- * @internal Dequeue several objects from the ring
- *
- * @param r
- *   A pointer to the ring structure.
- * @param obj_table
- *   A pointer to a table of void * pointers (objects).
- * @param n
- *   The number of objects to pull from the ring.
- * @param behavior
- *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
- *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
- * @param is_sc
- *   Indicates whether to use single consumer or multi-consumer head update
- * @param available
- *   returns the number of remaining ring entries after the dequeue has finished
- * @return
- *   - Actual number of objects dequeued.
- *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
- */
-static __rte_always_inline unsigned int
-__rte_ring_do_dequeue(struct rte_ring *r, void **obj_table,
-		 unsigned int n, enum rte_ring_queue_behavior behavior,
-		 unsigned int is_sc, unsigned int *available)
-{
-	uint32_t cons_head, cons_next;
-	uint32_t entries;
-
-	n = __rte_ring_move_cons_head(r, (int)is_sc, n, behavior,
-			&cons_head, &cons_next, &entries);
-	if (n == 0)
-		goto end;
-
-	DEQUEUE_PTRS(r, &r[1], cons_head, obj_table, n, void *);
-
-	update_tail(&r->cons, cons_head, cons_next, is_sc, 0);
-
-end:
-	if (available != NULL)
-		*available = entries - n;
-	return n;
-}
-
 /**
  * Enqueue several objects on the ring (multi-producers safe).
  *
@@ -415,13 +213,9 @@ __rte_ring_do_dequeue(struct rte_ring *r, void **obj_table,
  * @return
  *   The number of objects enqueued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_mp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
-			 unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-			__IS_MP, free_space);
-}
+			 unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring (NOT multi-producers safe).
@@ -438,13 +232,9 @@ rte_ring_mp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
  * @return
  *   The number of objects enqueued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_sp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
-			 unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-			__IS_SP, free_space);
-}
+			 unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring.
@@ -465,13 +255,9 @@ rte_ring_sp_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
  * @return
  *   The number of objects enqueued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
-		      unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-			r->prod.single, free_space);
-}
+		      unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue one object on a ring (multi-producers safe).
@@ -487,11 +273,8 @@ rte_ring_enqueue_bulk(struct rte_ring *r, void * const *obj_table,
  *   - 0: Success; objects enqueued.
  *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
  */
-static __rte_always_inline int
-rte_ring_mp_enqueue(struct rte_ring *r, void *obj)
-{
-	return rte_ring_mp_enqueue_bulk(r, &obj, 1, NULL) ? 0 : -ENOBUFS;
-}
+int
+rte_ring_mp_enqueue(struct rte_ring *r, void *obj);
 
 /**
  * Enqueue one object on a ring (NOT multi-producers safe).
@@ -504,11 +287,8 @@ rte_ring_mp_enqueue(struct rte_ring *r, void *obj)
  *   - 0: Success; objects enqueued.
  *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
  */
-static __rte_always_inline int
-rte_ring_sp_enqueue(struct rte_ring *r, void *obj)
-{
-	return rte_ring_sp_enqueue_bulk(r, &obj, 1, NULL) ? 0 : -ENOBUFS;
-}
+int
+rte_ring_sp_enqueue(struct rte_ring *r, void *obj);
 
 /**
  * Enqueue one object on a ring.
@@ -525,11 +305,8 @@ rte_ring_sp_enqueue(struct rte_ring *r, void *obj)
  *   - 0: Success; objects enqueued.
  *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
  */
-static __rte_always_inline int
-rte_ring_enqueue(struct rte_ring *r, void *obj)
-{
-	return rte_ring_enqueue_bulk(r, &obj, 1, NULL) ? 0 : -ENOBUFS;
-}
+int
+rte_ring_enqueue(struct rte_ring *r, void *obj);
 
 /**
  * Dequeue several objects from a ring (multi-consumers safe).
@@ -549,13 +326,9 @@ rte_ring_enqueue(struct rte_ring *r, void *obj)
  * @return
  *   The number of objects dequeued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_mc_dequeue_bulk(struct rte_ring *r, void **obj_table,
-		unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-			__IS_MC, available);
-}
+		unsigned int n, unsigned int *available);
 
 /**
  * Dequeue several objects from a ring (NOT multi-consumers safe).
@@ -573,13 +346,9 @@ rte_ring_mc_dequeue_bulk(struct rte_ring *r, void **obj_table,
  * @return
  *   The number of objects dequeued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_sc_dequeue_bulk(struct rte_ring *r, void **obj_table,
-		unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-			__IS_SC, available);
-}
+		unsigned int n, unsigned int *available);
 
 /**
  * Dequeue several objects from a ring.
@@ -600,13 +369,9 @@ rte_ring_sc_dequeue_bulk(struct rte_ring *r, void **obj_table,
  * @return
  *   The number of objects dequeued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,
-		unsigned int *available)
-{
-	return __rte_ring_do_dequeue(r, obj_table, n, RTE_RING_QUEUE_FIXED,
-				r->cons.single, available);
-}
+		unsigned int *available);
 
 /**
  * Dequeue one object from a ring (multi-consumers safe).
@@ -623,11 +388,8 @@ rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,
  *   - -ENOENT: Not enough entries in the ring to dequeue; no object is
  *     dequeued.
  */
-static __rte_always_inline int
-rte_ring_mc_dequeue(struct rte_ring *r, void **obj_p)
-{
-	return rte_ring_mc_dequeue_bulk(r, obj_p, 1, NULL)  ? 0 : -ENOENT;
-}
+int
+rte_ring_mc_dequeue(struct rte_ring *r, void **obj_p);
 
 /**
  * Dequeue one object from a ring (NOT multi-consumers safe).
@@ -641,11 +403,8 @@ rte_ring_mc_dequeue(struct rte_ring *r, void **obj_p)
  *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
  *     dequeued.
  */
-static __rte_always_inline int
-rte_ring_sc_dequeue(struct rte_ring *r, void **obj_p)
-{
-	return rte_ring_sc_dequeue_bulk(r, obj_p, 1, NULL) ? 0 : -ENOENT;
-}
+int
+rte_ring_sc_dequeue(struct rte_ring *r, void **obj_p);
 
 /**
  * Dequeue one object from a ring.
@@ -663,11 +422,8 @@ rte_ring_sc_dequeue(struct rte_ring *r, void **obj_p)
  *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
  *     dequeued.
  */
-static __rte_always_inline int
-rte_ring_dequeue(struct rte_ring *r, void **obj_p)
-{
-	return rte_ring_dequeue_bulk(r, obj_p, 1, NULL) ? 0 : -ENOENT;
-}
+int
+rte_ring_dequeue(struct rte_ring *r, void **obj_p);
 
 /**
  * Flush a ring.
@@ -694,14 +450,8 @@ rte_ring_reset(struct rte_ring *r);
  * @return
  *   The number of entries in the ring.
  */
-static inline unsigned
-rte_ring_count(const struct rte_ring *r)
-{
-	uint32_t prod_tail = r->prod.tail;
-	uint32_t cons_tail = r->cons.tail;
-	uint32_t count = (prod_tail - cons_tail) & r->mask;
-	return (count > r->capacity) ? r->capacity : count;
-}
+unsigned
+rte_ring_count(const struct rte_ring *r);
 
 /**
  * Return the number of free entries in a ring.
@@ -711,11 +461,8 @@ rte_ring_count(const struct rte_ring *r)
  * @return
  *   The number of free entries in the ring.
  */
-static inline unsigned
-rte_ring_free_count(const struct rte_ring *r)
-{
-	return r->capacity - rte_ring_count(r);
-}
+unsigned
+rte_ring_free_count(const struct rte_ring *r);
 
 /**
  * Test if a ring is full.
@@ -726,11 +473,8 @@ rte_ring_free_count(const struct rte_ring *r)
  *   - 1: The ring is full.
  *   - 0: The ring is not full.
  */
-static inline int
-rte_ring_full(const struct rte_ring *r)
-{
-	return rte_ring_free_count(r) == 0;
-}
+int
+rte_ring_full(const struct rte_ring *r);
 
 /**
  * Test if a ring is empty.
@@ -741,11 +485,14 @@ rte_ring_full(const struct rte_ring *r)
  *   - 1: The ring is empty.
  *   - 0: The ring is not empty.
  */
-static inline int
-rte_ring_empty(const struct rte_ring *r)
-{
-	return rte_ring_count(r) == 0;
-}
+int
+rte_ring_empty(const struct rte_ring *r);
+
+const char *
+rte_ring_get_name(const struct rte_ring *r);
+
+const struct rte_memzone *
+rte_ring_get_memzone(const struct rte_ring *r);
 
 /**
  * Return the size of the ring.
@@ -757,11 +504,8 @@ rte_ring_empty(const struct rte_ring *r)
  *   NOTE: this is not the same as the usable space in the ring. To query that
  *   use ``rte_ring_get_capacity()``.
  */
-static inline unsigned int
-rte_ring_get_size(const struct rte_ring *r)
-{
-	return r->size;
-}
+unsigned int
+rte_ring_get_size(const struct rte_ring *r);
 
 /**
  * Return the number of elements which can be stored in the ring.
@@ -771,11 +515,14 @@ rte_ring_get_size(const struct rte_ring *r)
  * @return
  *   The usable size of the ring.
  */
-static inline unsigned int
-rte_ring_get_capacity(const struct rte_ring *r)
-{
-	return r->capacity;
-}
+unsigned int
+rte_ring_get_capacity(const struct rte_ring *r);
+
+uint32_t
+rte_ring_get_prod_sync_type(const struct rte_ring *r);
+
+uint32_t
+rte_ring_get_cons_sync_type(const struct rte_ring *r);
 
 /**
  * Dump the status of all rings on the console
@@ -815,13 +562,9 @@ struct rte_ring *rte_ring_lookup(const char *name);
  * @return
  *   - n: Actual number of objects enqueued.
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_mp_enqueue_burst(struct rte_ring *r, void * const *obj_table,
-			 unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue(r, obj_table, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_MP, free_space);
-}
+			 unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring (NOT multi-producers safe).
@@ -838,13 +581,9 @@ rte_ring_mp_enqueue_burst(struct rte_ring *r, void * const *obj_table,
  * @return
  *   - n: Actual number of objects enqueued.
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_sp_enqueue_burst(struct rte_ring *r, void * const *obj_table,
-			 unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue(r, obj_table, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_SP, free_space);
-}
+			 unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring.
@@ -865,13 +604,9 @@ rte_ring_sp_enqueue_burst(struct rte_ring *r, void * const *obj_table,
  * @return
  *   - n: Actual number of objects enqueued.
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table,
-		      unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue(r, obj_table, n, RTE_RING_QUEUE_VARIABLE,
-			r->prod.single, free_space);
-}
+		      unsigned int n, unsigned int *free_space);
 
 /**
  * Dequeue several objects from a ring (multi-consumers safe). When the request
@@ -893,13 +628,9 @@ rte_ring_enqueue_burst(struct rte_ring *r, void * const *obj_table,
  * @return
  *   - n: Actual number of objects dequeued, 0 if ring is empty
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_mc_dequeue_burst(struct rte_ring *r, void **obj_table,
-		unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue(r, obj_table, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_MC, available);
-}
+		unsigned int n, unsigned int *available);
 
 /**
  * Dequeue several objects from a ring (NOT multi-consumers safe).When the
@@ -918,13 +649,9 @@ rte_ring_mc_dequeue_burst(struct rte_ring *r, void **obj_table,
  * @return
  *   - n: Actual number of objects dequeued, 0 if ring is empty
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_sc_dequeue_burst(struct rte_ring *r, void **obj_table,
-		unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue(r, obj_table, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_SC, available);
-}
+		unsigned int n, unsigned int *available);
 
 /**
  * Dequeue multiple objects from a ring up to a maximum number.
@@ -945,14 +672,9 @@ rte_ring_sc_dequeue_burst(struct rte_ring *r, void **obj_table,
  * @return
  *   - Number of objects dequeued
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table,
-		unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue(r, obj_table, n,
-				RTE_RING_QUEUE_VARIABLE,
-				r->cons.single, available);
-}
+		unsigned int n, unsigned int *available);
 
 #ifdef __cplusplus
 }
diff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h
index 3976757ed..2a6b00370 100644
--- a/lib/librte_ring/rte_ring_elem.h
+++ b/lib/librte_ring/rte_ring_elem.h
@@ -109,380 +109,6 @@ __rte_experimental
 struct rte_ring *rte_ring_create_elem(const char *name, unsigned int esize,
 			unsigned int count, int socket_id, unsigned int flags);
 
-static __rte_always_inline void
-__rte_ring_enqueue_elems_32(struct rte_ring *r, const uint32_t size,
-		uint32_t idx, const void *obj_table, uint32_t n)
-{
-	unsigned int i;
-	uint32_t *ring = (uint32_t *)&r[1];
-	const uint32_t *obj = (const uint32_t *)obj_table;
-	if (likely(idx + n < size)) {
-		for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
-			ring[idx] = obj[i];
-			ring[idx + 1] = obj[i + 1];
-			ring[idx + 2] = obj[i + 2];
-			ring[idx + 3] = obj[i + 3];
-			ring[idx + 4] = obj[i + 4];
-			ring[idx + 5] = obj[i + 5];
-			ring[idx + 6] = obj[i + 6];
-			ring[idx + 7] = obj[i + 7];
-		}
-		switch (n & 0x7) {
-		case 7:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 6:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 5:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 4:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 3:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 2:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 1:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		}
-	} else {
-		for (i = 0; idx < size; i++, idx++)
-			ring[idx] = obj[i];
-		/* Start at the beginning */
-		for (idx = 0; i < n; i++, idx++)
-			ring[idx] = obj[i];
-	}
-}
-
-static __rte_always_inline void
-__rte_ring_enqueue_elems_64(struct rte_ring *r, uint32_t prod_head,
-		const void *obj_table, uint32_t n)
-{
-	unsigned int i;
-	const uint32_t size = r->size;
-	uint32_t idx = prod_head & r->mask;
-	uint64_t *ring = (uint64_t *)&r[1];
-	const uint64_t *obj = (const uint64_t *)obj_table;
-	if (likely(idx + n < size)) {
-		for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
-			ring[idx] = obj[i];
-			ring[idx + 1] = obj[i + 1];
-			ring[idx + 2] = obj[i + 2];
-			ring[idx + 3] = obj[i + 3];
-		}
-		switch (n & 0x3) {
-		case 3:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 2:
-			ring[idx++] = obj[i++]; /* fallthrough */
-		case 1:
-			ring[idx++] = obj[i++];
-		}
-	} else {
-		for (i = 0; idx < size; i++, idx++)
-			ring[idx] = obj[i];
-		/* Start at the beginning */
-		for (idx = 0; i < n; i++, idx++)
-			ring[idx] = obj[i];
-	}
-}
-
-static __rte_always_inline void
-__rte_ring_enqueue_elems_128(struct rte_ring *r, uint32_t prod_head,
-		const void *obj_table, uint32_t n)
-{
-	unsigned int i;
-	const uint32_t size = r->size;
-	uint32_t idx = prod_head & r->mask;
-	rte_int128_t *ring = (rte_int128_t *)&r[1];
-	const rte_int128_t *obj = (const rte_int128_t *)obj_table;
-	if (likely(idx + n < size)) {
-		for (i = 0; i < (n & ~0x1); i += 2, idx += 2)
-			memcpy((void *)(ring + idx),
-				(const void *)(obj + i), 32);
-		switch (n & 0x1) {
-		case 1:
-			memcpy((void *)(ring + idx),
-				(const void *)(obj + i), 16);
-		}
-	} else {
-		for (i = 0; idx < size; i++, idx++)
-			memcpy((void *)(ring + idx),
-				(const void *)(obj + i), 16);
-		/* Start at the beginning */
-		for (idx = 0; i < n; i++, idx++)
-			memcpy((void *)(ring + idx),
-				(const void *)(obj + i), 16);
-	}
-}
-
-/* the actual enqueue of elements on the ring.
- * Placed here since identical code needed in both
- * single and multi producer enqueue functions.
- */
-static __rte_always_inline void
-__rte_ring_enqueue_elems(struct rte_ring *r, uint32_t prod_head,
-		const void *obj_table, uint32_t esize, uint32_t num)
-{
-	/* 8B and 16B copies implemented individually to retain
-	 * the current performance.
-	 */
-	if (esize == 8)
-		__rte_ring_enqueue_elems_64(r, prod_head, obj_table, num);
-	else if (esize == 16)
-		__rte_ring_enqueue_elems_128(r, prod_head, obj_table, num);
-	else {
-		uint32_t idx, scale, nr_idx, nr_num, nr_size;
-
-		/* Normalize to uint32_t */
-		scale = esize / sizeof(uint32_t);
-		nr_num = num * scale;
-		idx = prod_head & r->mask;
-		nr_idx = idx * scale;
-		nr_size = r->size * scale;
-		__rte_ring_enqueue_elems_32(r, nr_size, nr_idx,
-				obj_table, nr_num);
-	}
-}
-
-static __rte_always_inline void
-__rte_ring_dequeue_elems_32(struct rte_ring *r, const uint32_t size,
-		uint32_t idx, void *obj_table, uint32_t n)
-{
-	unsigned int i;
-	uint32_t *ring = (uint32_t *)&r[1];
-	uint32_t *obj = (uint32_t *)obj_table;
-	if (likely(idx + n < size)) {
-		for (i = 0; i < (n & ~0x7); i += 8, idx += 8) {
-			obj[i] = ring[idx];
-			obj[i + 1] = ring[idx + 1];
-			obj[i + 2] = ring[idx + 2];
-			obj[i + 3] = ring[idx + 3];
-			obj[i + 4] = ring[idx + 4];
-			obj[i + 5] = ring[idx + 5];
-			obj[i + 6] = ring[idx + 6];
-			obj[i + 7] = ring[idx + 7];
-		}
-		switch (n & 0x7) {
-		case 7:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 6:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 5:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 4:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 3:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 2:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 1:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		}
-	} else {
-		for (i = 0; idx < size; i++, idx++)
-			obj[i] = ring[idx];
-		/* Start at the beginning */
-		for (idx = 0; i < n; i++, idx++)
-			obj[i] = ring[idx];
-	}
-}
-
-static __rte_always_inline void
-__rte_ring_dequeue_elems_64(struct rte_ring *r, uint32_t prod_head,
-		void *obj_table, uint32_t n)
-{
-	unsigned int i;
-	const uint32_t size = r->size;
-	uint32_t idx = prod_head & r->mask;
-	uint64_t *ring = (uint64_t *)&r[1];
-	uint64_t *obj = (uint64_t *)obj_table;
-	if (likely(idx + n < size)) {
-		for (i = 0; i < (n & ~0x3); i += 4, idx += 4) {
-			obj[i] = ring[idx];
-			obj[i + 1] = ring[idx + 1];
-			obj[i + 2] = ring[idx + 2];
-			obj[i + 3] = ring[idx + 3];
-		}
-		switch (n & 0x3) {
-		case 3:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 2:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		case 1:
-			obj[i++] = ring[idx++]; /* fallthrough */
-		}
-	} else {
-		for (i = 0; idx < size; i++, idx++)
-			obj[i] = ring[idx];
-		/* Start at the beginning */
-		for (idx = 0; i < n; i++, idx++)
-			obj[i] = ring[idx];
-	}
-}
-
-static __rte_always_inline void
-__rte_ring_dequeue_elems_128(struct rte_ring *r, uint32_t prod_head,
-		void *obj_table, uint32_t n)
-{
-	unsigned int i;
-	const uint32_t size = r->size;
-	uint32_t idx = prod_head & r->mask;
-	rte_int128_t *ring = (rte_int128_t *)&r[1];
-	rte_int128_t *obj = (rte_int128_t *)obj_table;
-	if (likely(idx + n < size)) {
-		for (i = 0; i < (n & ~0x1); i += 2, idx += 2)
-			memcpy((void *)(obj + i), (void *)(ring + idx), 32);
-		switch (n & 0x1) {
-		case 1:
-			memcpy((void *)(obj + i), (void *)(ring + idx), 16);
-		}
-	} else {
-		for (i = 0; idx < size; i++, idx++)
-			memcpy((void *)(obj + i), (void *)(ring + idx), 16);
-		/* Start at the beginning */
-		for (idx = 0; i < n; i++, idx++)
-			memcpy((void *)(obj + i), (void *)(ring + idx), 16);
-	}
-}
-
-/* the actual dequeue of elements from the ring.
- * Placed here since identical code needed in both
- * single and multi producer enqueue functions.
- */
-static __rte_always_inline void
-__rte_ring_dequeue_elems(struct rte_ring *r, uint32_t cons_head,
-		void *obj_table, uint32_t esize, uint32_t num)
-{
-	/* 8B and 16B copies implemented individually to retain
-	 * the current performance.
-	 */
-	if (esize == 8)
-		__rte_ring_dequeue_elems_64(r, cons_head, obj_table, num);
-	else if (esize == 16)
-		__rte_ring_dequeue_elems_128(r, cons_head, obj_table, num);
-	else {
-		uint32_t idx, scale, nr_idx, nr_num, nr_size;
-
-		/* Normalize to uint32_t */
-		scale = esize / sizeof(uint32_t);
-		nr_num = num * scale;
-		idx = cons_head & r->mask;
-		nr_idx = idx * scale;
-		nr_size = r->size * scale;
-		__rte_ring_dequeue_elems_32(r, nr_size, nr_idx,
-				obj_table, nr_num);
-	}
-}
-
-/* Between load and load. there might be cpu reorder in weak model
- * (powerpc/arm).
- * There are 2 choices for the users
- * 1.use rmb() memory barrier
- * 2.use one-direction load_acquire/store_release barrier,defined by
- * CONFIG_RTE_USE_C11_MEM_MODEL=y
- * It depends on performance test results.
- * By default, move common functions to rte_ring_generic.h
- */
-#ifdef RTE_USE_C11_MEM_MODEL
-#include "rte_ring_c11_mem.h"
-#else
-#include "rte_ring_generic.h"
-#endif
-
-/**
- * @internal Enqueue several objects on the ring
- *
- * @param r
- *   A pointer to the ring structure.
- * @param obj_table
- *   A pointer to a table of objects.
- * @param esize
- *   The size of ring element, in bytes. It must be a multiple of 4.
- *   This must be the same value used while creating the ring. Otherwise
- *   the results are undefined.
- * @param n
- *   The number of objects to add in the ring from the obj_table.
- * @param behavior
- *   RTE_RING_QUEUE_FIXED:    Enqueue a fixed number of items from a ring
- *   RTE_RING_QUEUE_VARIABLE: Enqueue as many items as possible from ring
- * @param is_sp
- *   Indicates whether to use single producer or multi-producer head update
- * @param free_space
- *   returns the amount of space after the enqueue operation has finished
- * @return
- *   Actual number of objects enqueued.
- *   If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
- */
-static __rte_always_inline unsigned int
-__rte_ring_do_enqueue_elem(struct rte_ring *r, const void *obj_table,
-		unsigned int esize, unsigned int n,
-		enum rte_ring_queue_behavior behavior, unsigned int is_sp,
-		unsigned int *free_space)
-{
-	uint32_t prod_head, prod_next;
-	uint32_t free_entries;
-
-	n = __rte_ring_move_prod_head(r, is_sp, n, behavior,
-			&prod_head, &prod_next, &free_entries);
-	if (n == 0)
-		goto end;
-
-	__rte_ring_enqueue_elems(r, prod_head, obj_table, esize, n);
-
-	update_tail(&r->prod, prod_head, prod_next, is_sp, 1);
-end:
-	if (free_space != NULL)
-		*free_space = free_entries - n;
-	return n;
-}
-
-/**
- * @internal Dequeue several objects from the ring
- *
- * @param r
- *   A pointer to the ring structure.
- * @param obj_table
- *   A pointer to a table of objects.
- * @param esize
- *   The size of ring element, in bytes. It must be a multiple of 4.
- *   This must be the same value used while creating the ring. Otherwise
- *   the results are undefined.
- * @param n
- *   The number of objects to pull from the ring.
- * @param behavior
- *   RTE_RING_QUEUE_FIXED:    Dequeue a fixed number of items from a ring
- *   RTE_RING_QUEUE_VARIABLE: Dequeue as many items as possible from ring
- * @param is_sc
- *   Indicates whether to use single consumer or multi-consumer head update
- * @param available
- *   returns the number of remaining ring entries after the dequeue has finished
- * @return
- *   - Actual number of objects dequeued.
- *     If behavior == RTE_RING_QUEUE_FIXED, this will be 0 or n only.
- */
-static __rte_always_inline unsigned int
-__rte_ring_do_dequeue_elem(struct rte_ring *r, void *obj_table,
-		unsigned int esize, unsigned int n,
-		enum rte_ring_queue_behavior behavior, unsigned int is_sc,
-		unsigned int *available)
-{
-	uint32_t cons_head, cons_next;
-	uint32_t entries;
-
-	n = __rte_ring_move_cons_head(r, (int)is_sc, n, behavior,
-			&cons_head, &cons_next, &entries);
-	if (n == 0)
-		goto end;
-
-	__rte_ring_dequeue_elems(r, cons_head, obj_table, esize, n);
-
-	update_tail(&r->cons, cons_head, cons_next, is_sc, 0);
-
-end:
-	if (available != NULL)
-		*available = entries - n;
-	return n;
-}
-
 /**
  * Enqueue several objects on the ring (multi-producers safe).
  *
@@ -505,13 +131,9 @@ __rte_ring_do_dequeue_elem(struct rte_ring *r, void *obj_table,
  * @return
  *   The number of objects enqueued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_mp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_FIXED, __IS_MP, free_space);
-}
+		unsigned int esize, unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring
@@ -534,13 +156,9 @@ rte_ring_mp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
  * @return
  *   The number of objects enqueued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_FIXED, __IS_SP, free_space);
-}
+		unsigned int esize, unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring.
@@ -565,13 +183,9 @@ rte_ring_sp_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
  * @return
  *   The number of objects enqueued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_FIXED, r->prod.single, free_space);
-}
+		unsigned int esize, unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue one object on a ring (multi-producers safe).
@@ -591,12 +205,8 @@ rte_ring_enqueue_bulk_elem(struct rte_ring *r, const void *obj_table,
  *   - 0: Success; objects enqueued.
  *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
  */
-static __rte_always_inline int
-rte_ring_mp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
-{
-	return rte_ring_mp_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :
-								-ENOBUFS;
-}
+int
+rte_ring_mp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize);
 
 /**
  * Enqueue one object on a ring
@@ -615,12 +225,8 @@ rte_ring_mp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
  *   - 0: Success; objects enqueued.
  *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
  */
-static __rte_always_inline int
-rte_ring_sp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
-{
-	return rte_ring_sp_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :
-								-ENOBUFS;
-}
+int
+rte_ring_sp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize);
 
 /**
  * Enqueue one object on a ring.
@@ -641,12 +247,8 @@ rte_ring_sp_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
  *   - 0: Success; objects enqueued.
  *   - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
  */
-static __rte_always_inline int
-rte_ring_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
-{
-	return rte_ring_enqueue_bulk_elem(r, obj, esize, 1, NULL) ? 0 :
-								-ENOBUFS;
-}
+int
+rte_ring_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize);
 
 /**
  * Dequeue several objects from a ring (multi-consumers safe).
@@ -670,13 +272,9 @@ rte_ring_enqueue_elem(struct rte_ring *r, void *obj, unsigned int esize)
  * @return
  *   The number of objects dequeued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_mc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-				RTE_RING_QUEUE_FIXED, __IS_MC, available);
-}
+		unsigned int esize, unsigned int n, unsigned int *available);
 
 /**
  * Dequeue several objects from a ring (NOT multi-consumers safe).
@@ -698,13 +296,9 @@ rte_ring_mc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
  * @return
  *   The number of objects dequeued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_sc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_FIXED, __IS_SC, available);
-}
+		unsigned int esize, unsigned int n, unsigned int *available);
 
 /**
  * Dequeue several objects from a ring.
@@ -729,13 +323,9 @@ rte_ring_sc_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
  * @return
  *   The number of objects dequeued, either 0 or n
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_FIXED, r->cons.single, available);
-}
+		unsigned int esize, unsigned int n, unsigned int *available);
 
 /**
  * Dequeue one object from a ring (multi-consumers safe).
@@ -756,13 +346,9 @@ rte_ring_dequeue_bulk_elem(struct rte_ring *r, void *obj_table,
  *   - -ENOENT: Not enough entries in the ring to dequeue; no object is
  *     dequeued.
  */
-static __rte_always_inline int
+int
 rte_ring_mc_dequeue_elem(struct rte_ring *r, void *obj_p,
-				unsigned int esize)
-{
-	return rte_ring_mc_dequeue_bulk_elem(r, obj_p, esize, 1, NULL)  ? 0 :
-								-ENOENT;
-}
+				unsigned int esize);
 
 /**
  * Dequeue one object from a ring (NOT multi-consumers safe).
@@ -780,13 +366,9 @@ rte_ring_mc_dequeue_elem(struct rte_ring *r, void *obj_p,
  *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
  *     dequeued.
  */
-static __rte_always_inline int
+int
 rte_ring_sc_dequeue_elem(struct rte_ring *r, void *obj_p,
-				unsigned int esize)
-{
-	return rte_ring_sc_dequeue_bulk_elem(r, obj_p, esize, 1, NULL) ? 0 :
-								-ENOENT;
-}
+				unsigned int esize);
 
 /**
  * Dequeue one object from a ring.
@@ -808,12 +390,8 @@ rte_ring_sc_dequeue_elem(struct rte_ring *r, void *obj_p,
  *   - -ENOENT: Not enough entries in the ring to dequeue, no object is
  *     dequeued.
  */
-static __rte_always_inline int
-rte_ring_dequeue_elem(struct rte_ring *r, void *obj_p, unsigned int esize)
-{
-	return rte_ring_dequeue_bulk_elem(r, obj_p, esize, 1, NULL) ? 0 :
-								-ENOENT;
-}
+int
+rte_ring_dequeue_elem(struct rte_ring *r, void *obj_p, unsigned int esize);
 
 /**
  * Enqueue several objects on the ring (multi-producers safe).
@@ -837,13 +415,9 @@ rte_ring_dequeue_elem(struct rte_ring *r, void *obj_p, unsigned int esize)
  * @return
  *   - n: Actual number of objects enqueued.
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_mp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_MP, free_space);
-}
+		unsigned int esize, unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring
@@ -866,13 +440,9 @@ rte_ring_mp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
  * @return
  *   - n: Actual number of objects enqueued.
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_sp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_SP, free_space);
-}
+		unsigned int esize, unsigned int n, unsigned int *free_space);
 
 /**
  * Enqueue several objects on a ring.
@@ -897,13 +467,9 @@ rte_ring_sp_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
  * @return
  *   - n: Actual number of objects enqueued.
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *free_space)
-{
-	return __rte_ring_do_enqueue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_VARIABLE, r->prod.single, free_space);
-}
+		unsigned int esize, unsigned int n, unsigned int *free_space);
 
 /**
  * Dequeue several objects from a ring (multi-consumers safe). When the request
@@ -929,13 +495,9 @@ rte_ring_enqueue_burst_elem(struct rte_ring *r, const void *obj_table,
  * @return
  *   - n: Actual number of objects dequeued, 0 if ring is empty
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_mc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_MC, available);
-}
+		unsigned int esize, unsigned int n, unsigned int *available);
 
 /**
  * Dequeue several objects from a ring (NOT multi-consumers safe).When the
@@ -958,13 +520,9 @@ rte_ring_mc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
  * @return
  *   - n: Actual number of objects dequeued, 0 if ring is empty
  */
-static __rte_always_inline unsigned
+unsigned
 rte_ring_sc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-			RTE_RING_QUEUE_VARIABLE, __IS_SC, available);
-}
+		unsigned int esize, unsigned int n, unsigned int *available);
 
 /**
  * Dequeue multiple objects from a ring up to a maximum number.
@@ -989,14 +547,9 @@ rte_ring_sc_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
  * @return
  *   - Number of objects dequeued
  */
-static __rte_always_inline unsigned int
+unsigned int
 rte_ring_dequeue_burst_elem(struct rte_ring *r, void *obj_table,
-		unsigned int esize, unsigned int n, unsigned int *available)
-{
-	return __rte_ring_do_dequeue_elem(r, obj_table, esize, n,
-				RTE_RING_QUEUE_VARIABLE,
-				r->cons.single, available);
-}
+		unsigned int esize, unsigned int n, unsigned int *available);
 
 #ifdef __cplusplus
 }
diff --git a/lib/librte_ring/rte_ring_version.map b/lib/librte_ring/rte_ring_version.map
index e88c143cf..6cceacf95 100644
--- a/lib/librte_ring/rte_ring_version.map
+++ b/lib/librte_ring/rte_ring_version.map
@@ -8,6 +8,52 @@ DPDK_20.0 {
 	rte_ring_init;
 	rte_ring_list_dump;
 	rte_ring_lookup;
+	rte_ring_count;
+	rte_ring_dequeue;
+	rte_ring_dequeue_bulk;
+	rte_ring_dequeue_bulk_elem;
+	rte_ring_dequeue_burst;
+	rte_ring_dequeue_burst_elem;
+	rte_ring_dequeue_elem;
+	rte_ring_empty;
+	rte_ring_enqueue;
+	rte_ring_enqueue_bulk;
+	rte_ring_enqueue_bulk_elem;
+	rte_ring_enqueue_burst;
+	rte_ring_enqueue_burst_elem;
+	rte_ring_enqueue_elem;
+	rte_ring_free_count;
+	rte_ring_full;
+	rte_ring_get_capacity;
+	rte_ring_get_cons_sync_type;
+	rte_ring_get_memzone;
+	rte_ring_get_name;
+	rte_ring_get_prod_sync_type;
+	rte_ring_get_size;
+	rte_ring_mc_dequeue;
+	rte_ring_mc_dequeue_bulk;
+	rte_ring_mc_dequeue_bulk_elem;
+	rte_ring_mc_dequeue_burst;
+	rte_ring_mc_dequeue_burst_elem;
+	rte_ring_mc_dequeue_elem;
+	rte_ring_mp_enqueue;
+	rte_ring_mp_enqueue_bulk;
+	rte_ring_mp_enqueue_bulk_elem;
+	rte_ring_mp_enqueue_burst;
+	rte_ring_mp_enqueue_burst_elem;
+	rte_ring_mp_enqueue_elem;
+	rte_ring_sc_dequeue;
+	rte_ring_sc_dequeue_bulk;
+	rte_ring_sc_dequeue_bulk_elem;
+	rte_ring_sc_dequeue_burst;
+	rte_ring_sc_dequeue_burst_elem;
+	rte_ring_sc_dequeue_elem;
+	rte_ring_sp_enqueue;
+	rte_ring_sp_enqueue_bulk;
+	rte_ring_sp_enqueue_bulk_elem;
+	rte_ring_sp_enqueue_burst;
+	rte_ring_sp_enqueue_burst_elem;
+	rte_ring_sp_enqueue_elem;
 
 	local: *;
 };
-- 
2.17.1


^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH] eal: reorganize directories layout
@ 2020-03-20  0:12  1% Thomas Monjalon
    0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-03-20  0:12 UTC (permalink / raw)
  To: dev
  Cc: david.marchand, Neil Horman, John McNamara, Marko Kovacevic,
	Hemant Agrawal, Sachin Saxena, Matan Azrad, Shahaf Shuler,
	Viacheslav Ovsiienko, Gagandeep Singh, Akhil Goyal, Nipun Gupta,
	Maxime Coquelin, Zhihong Wang, Xiaolong Ye, Ferruh Yigit,
	Cristian Dumitrescu, Jan Viktorin, Gavin Hu, Jerin Jacob,
	Harry van Haaren, Bruce Richardson, Anatoly Burakov, Phil Yang,
	Joyce Kong, Mattias Rönnblom, David Christensen,
	Harini Ramakrishnan, Omar Cardona, Pallavi Kadam, Ranjit Menon,
	Konstantin Ananyev, Olivier Matz

Some clean-up is done in EAL sub-directories.
The goal is to make organization easier to understand,
and to prepare moving some files from common to Unix-only place.

Since the kernel modules are moved to kernel/ directory,
there is no need anymore for the sub-directory eal/ in
linux/, freebsd/ and windows/.

The EAL API (with doxygen documentation) is moved from
common/include/ to include/, which makes more clear that
it is the global API for all environments and architectures.
Note that the arch-specific and os-specific include files are not
in this global include directory, but include/generic/ should
cover the doxygen documentation for them.

The arch-specific directories arm, ppc_64 and x86 in common/arch/
and in common/include/arch are moved at the same level as the
os-specific directories, adding an include/ sub-directory.
It makes more clear that EAL is covering a matrix combining OS and arch.
Note that ppc_64 is renamed to ppc.

These moves offer the opportunity to simplify the make and meson files.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>

---

This change was proposed to the Technical Board in advance:
http://mails.dpdk.org/archives/dev/2020-January/156732.html

If required, the patch may be split:
   1/ remove FreeBSD kernel Makefile
   2/ move arch .c files
   3/ move arch .h files
   4/ move common and generic includes
   5/ move os/eal/ to os/

---
---
 MAINTAINERS                                   |  53 ++++-----
 buildtools/pmdinfogen/meson.build             |   2 +-
 config/arm/meson.build                        |   2 +-
 config/common_armv8a_linux                    |   2 +-
 config/meson.build                            |   2 +-
 devtools/build-tags.sh                        |  14 +--
 doc/api/doxy-api.conf.in                      |   4 +-
 doc/guides/rel_notes/known_issues.rst         |   2 +-
 drivers/bus/dpaa/Makefile                     |   2 +-
 drivers/common/mlx5/meson.build               |   2 +-
 drivers/crypto/caam_jr/Makefile               |   2 +-
 drivers/crypto/dpaa_sec/Makefile              |   2 +-
 drivers/event/dpaa/Makefile                   |   2 +-
 drivers/net/dpaa/Makefile                     |   2 +-
 drivers/net/virtio/meson.build                |   2 +-
 kernel/linux/igb_uio/meson.build              |   2 +-
 kernel/linux/kni/meson.build                  |   4 +-
 lib/librte_cfgfile/Makefile                   |   2 +-
 lib/librte_eal/Makefile                       |   6 +-
 .../arch/arm => arm/include}/meson.build      |   0
 .../arch/arm => arm/include}/rte_atomic.h     |   0
 .../arch/arm => arm/include}/rte_atomic_32.h  |   0
 .../arch/arm => arm/include}/rte_atomic_64.h  |   0
 .../arch/arm => arm/include}/rte_byteorder.h  |   0
 .../arch/arm => arm/include}/rte_cpuflags.h   |   0
 .../arm => arm/include}/rte_cpuflags_32.h     |   0
 .../arm => arm/include}/rte_cpuflags_64.h     |   0
 .../arch/arm => arm/include}/rte_cycles.h     |   0
 .../arch/arm => arm/include}/rte_cycles_32.h  |   0
 .../arch/arm => arm/include}/rte_cycles_64.h  |   0
 .../include/arch/arm => arm/include}/rte_io.h |   0
 .../arch/arm => arm/include}/rte_io_64.h      |   0
 .../arch/arm => arm/include}/rte_mcslock.h    |   0
 .../arch/arm => arm/include}/rte_memcpy.h     |   0
 .../arch/arm => arm/include}/rte_memcpy_32.h  |   0
 .../arch/arm => arm/include}/rte_memcpy_64.h  |   0
 .../arch/arm => arm/include}/rte_pause.h      |   0
 .../arch/arm => arm/include}/rte_pause_32.h   |   0
 .../arch/arm => arm/include}/rte_pause_64.h   |   0
 .../arch/arm => arm/include}/rte_prefetch.h   |   0
 .../arm => arm/include}/rte_prefetch_32.h     |   0
 .../arm => arm/include}/rte_prefetch_64.h     |   0
 .../arch/arm => arm/include}/rte_rwlock.h     |   0
 .../arch/arm => arm/include}/rte_spinlock.h   |   0
 .../arch/arm => arm/include}/rte_ticketlock.h |   0
 .../arch/arm => arm/include}/rte_vect.h       |   0
 lib/librte_eal/arm/meson.build                |  13 +++
 .../{common/arch => }/arm/rte_cpuflags.c      |   0
 .../{common/arch => }/arm/rte_cycles.c        |   0
 .../{common/arch => }/arm/rte_hypervisor.c    |   0
 lib/librte_eal/common/Makefile                |  38 -------
 lib/librte_eal/common/arch/arm/meson.build    |   5 -
 lib/librte_eal/common/arch/ppc_64/meson.build |   5 -
 lib/librte_eal/common/arch/x86/meson.build    |   5 -
 lib/librte_eal/common/meson.build             |  92 ++++------------
 lib/librte_eal/common/rte_service.c           |   2 +-
 lib/librte_eal/freebsd/BSDmakefile.meson      |  14 ---
 lib/librte_eal/freebsd/Makefile               |  90 +++++++++++++++-
 lib/librte_eal/freebsd/{eal => }/eal.c        |   0
 lib/librte_eal/freebsd/eal/Makefile           |  93 ----------------
 lib/librte_eal/freebsd/{eal => }/eal_alarm.c  |   0
 .../freebsd/{eal => }/eal_alarm_private.h     |   0
 .../freebsd/{eal => }/eal_cpuflags.c          |   0
 lib/librte_eal/freebsd/{eal => }/eal_debug.c  |   0
 lib/librte_eal/freebsd/{eal => }/eal_dev.c    |   0
 .../freebsd/{eal => }/eal_hugepage_info.c     |   0
 .../freebsd/{eal => }/eal_interrupts.c        |   0
 lib/librte_eal/freebsd/{eal => }/eal_lcore.c  |   0
 .../freebsd/{eal => }/eal_memalloc.c          |   0
 lib/librte_eal/freebsd/{eal => }/eal_memory.c |   0
 lib/librte_eal/freebsd/{eal => }/eal_thread.c |   0
 lib/librte_eal/freebsd/{eal => }/eal_timer.c  |   0
 .../freebsd/{eal => }/include/rte_os.h        |   0
 lib/librte_eal/freebsd/{eal => }/meson.build  |   8 +-
 .../{common => }/include/generic/rte_atomic.h |   0
 .../include/generic/rte_byteorder.h           |   0
 .../include/generic/rte_cpuflags.h            |   0
 .../{common => }/include/generic/rte_cycles.h |   0
 .../{common => }/include/generic/rte_io.h     |   0
 .../include/generic/rte_mcslock.h             |   0
 .../{common => }/include/generic/rte_memcpy.h |   0
 .../{common => }/include/generic/rte_pause.h  |   0
 .../include/generic/rte_prefetch.h            |   0
 .../{common => }/include/generic/rte_rwlock.h |   0
 .../include/generic/rte_spinlock.h            |   0
 .../include/generic/rte_ticketlock.h          |   0
 .../{common => }/include/generic/rte_vect.h   |   0
 .../{common => }/include/rte_alarm.h          |   0
 .../{common => }/include/rte_bitmap.h         |   0
 .../include/rte_branch_prediction.h           |   0
 lib/librte_eal/{common => }/include/rte_bus.h |   0
 .../{common => }/include/rte_class.h          |   0
 .../{common => }/include/rte_common.h         |   0
 .../{common => }/include/rte_compat.h         |   0
 .../{common => }/include/rte_debug.h          |   0
 lib/librte_eal/{common => }/include/rte_dev.h |   0
 .../{common => }/include/rte_devargs.h        |   0
 lib/librte_eal/{common => }/include/rte_eal.h |   0
 .../{common => }/include/rte_eal_interrupts.h |   0
 .../{common => }/include/rte_eal_memconfig.h  |   0
 .../{common => }/include/rte_errno.h          |   0
 .../{common => }/include/rte_fbarray.h        |   0
 .../include/rte_function_versioning.h         |   0
 .../{common => }/include/rte_hexdump.h        |   0
 .../{common => }/include/rte_hypervisor.h     |   0
 .../{common => }/include/rte_interrupts.h     |   0
 .../{common => }/include/rte_keepalive.h      |   0
 .../{common => }/include/rte_launch.h         |   0
 .../{common => }/include/rte_lcore.h          |   0
 lib/librte_eal/{common => }/include/rte_log.h |   0
 .../{common => }/include/rte_malloc.h         |   0
 .../{common => }/include/rte_memory.h         |   0
 .../{common => }/include/rte_memzone.h        |   0
 .../{common => }/include/rte_option.h         |   0
 .../include/rte_pci_dev_feature_defs.h        |   0
 .../include/rte_pci_dev_features.h            |   0
 .../{common => }/include/rte_per_lcore.h      |   0
 .../{common => }/include/rte_random.h         |   0
 .../{common => }/include/rte_reciprocal.h     |   0
 .../{common => }/include/rte_service.h        |   0
 .../include/rte_service_component.h           |   0
 .../{common => }/include/rte_string_fns.h     |   0
 .../{common => }/include/rte_tailq.h          |   0
 .../{common => }/include/rte_test.h           |   0
 .../{common => }/include/rte_time.h           |   0
 .../{common => }/include/rte_uuid.h           |   0
 .../{common => }/include/rte_version.h        |   0
 .../{common => }/include/rte_vfio.h           |   0
 lib/librte_eal/linux/Makefile                 |  96 ++++++++++++++++-
 lib/librte_eal/linux/{eal => }/eal.c          |   0
 lib/librte_eal/linux/eal/Makefile             | 101 ------------------
 lib/librte_eal/linux/{eal => }/eal_alarm.c    |   0
 lib/librte_eal/linux/{eal => }/eal_cpuflags.c |   0
 lib/librte_eal/linux/{eal => }/eal_debug.c    |   0
 lib/librte_eal/linux/{eal => }/eal_dev.c      |   0
 .../linux/{eal => }/eal_hugepage_info.c       |   0
 .../linux/{eal => }/eal_interrupts.c          |   0
 lib/librte_eal/linux/{eal => }/eal_lcore.c    |   0
 lib/librte_eal/linux/{eal => }/eal_log.c      |   0
 lib/librte_eal/linux/{eal => }/eal_memalloc.c |   0
 lib/librte_eal/linux/{eal => }/eal_memory.c   |   0
 lib/librte_eal/linux/{eal => }/eal_thread.c   |   0
 lib/librte_eal/linux/{eal => }/eal_timer.c    |   0
 lib/librte_eal/linux/{eal => }/eal_vfio.c     |   0
 lib/librte_eal/linux/{eal => }/eal_vfio.h     |   0
 .../linux/{eal => }/eal_vfio_mp_sync.c        |   0
 .../linux/{eal => }/include/rte_kni_common.h  |   0
 .../linux/{eal => }/include/rte_os.h          |   0
 lib/librte_eal/linux/{eal => }/meson.build    |   9 +-
 lib/librte_eal/meson.build                    |  20 ++--
 .../arch/ppc_64 => ppc/include}/meson.build   |   0
 .../arch/ppc_64 => ppc/include}/rte_atomic.h  |   0
 .../ppc_64 => ppc/include}/rte_byteorder.h    |   0
 .../ppc_64 => ppc/include}/rte_cpuflags.h     |   0
 .../arch/ppc_64 => ppc/include}/rte_cycles.h  |   0
 .../arch/ppc_64 => ppc/include}/rte_io.h      |   0
 .../arch/ppc_64 => ppc/include}/rte_mcslock.h |   0
 .../arch/ppc_64 => ppc/include}/rte_memcpy.h  |   0
 .../arch/ppc_64 => ppc/include}/rte_pause.h   |   0
 .../ppc_64 => ppc/include}/rte_prefetch.h     |   0
 .../arch/ppc_64 => ppc/include}/rte_rwlock.h  |   0
 .../ppc_64 => ppc/include}/rte_spinlock.h     |   0
 .../ppc_64 => ppc/include}/rte_ticketlock.h   |   0
 .../arch/ppc_64 => ppc/include}/rte_vect.h    |   0
 lib/librte_eal/ppc/meson.build                |  13 +++
 .../arch/ppc_64 => ppc}/rte_cpuflags.c        |   0
 .../{common/arch/ppc_64 => ppc}/rte_cycles.c  |   0
 .../arch/ppc_64 => ppc}/rte_hypervisor.c      |   0
 lib/librte_eal/windows/{eal => }/eal.c        |   0
 lib/librte_eal/windows/eal/meson.build        |  27 -----
 lib/librte_eal/windows/{eal => }/eal_debug.c  |   0
 lib/librte_eal/windows/{eal => }/eal_lcore.c  |   0
 lib/librte_eal/windows/{eal => }/eal_thread.c |   0
 lib/librte_eal/windows/{eal => }/getopt.c     |   0
 .../windows/{eal => }/include/dirent.h        |   0
 .../windows/{eal => }/include/fnmatch.h       |   0
 .../windows/{eal => }/include/getopt.h        |   0
 .../windows/{eal => }/include/pthread.h       |   0
 .../windows/{eal => }/include/regex.h         |   0
 .../windows/{eal => }/include/rte_os.h        |   0
 .../windows/{eal => }/include/sched.h         |   0
 .../windows/{eal => }/include/sys/queue.h     |   0
 .../windows/{eal => }/include/unistd.h        |   0
 lib/librte_eal/windows/meson.build            |  16 +++
 .../arch/x86 => x86/include}/meson.build      |   0
 .../arch/x86 => x86/include}/rte_atomic.h     |   0
 .../arch/x86 => x86/include}/rte_atomic_32.h  |   0
 .../arch/x86 => x86/include}/rte_atomic_64.h  |   0
 .../arch/x86 => x86/include}/rte_byteorder.h  |   0
 .../x86 => x86/include}/rte_byteorder_32.h    |   0
 .../x86 => x86/include}/rte_byteorder_64.h    |   0
 .../arch/x86 => x86/include}/rte_cpuflags.h   |   0
 .../arch/x86 => x86/include}/rte_cycles.h     |   0
 .../include/arch/x86 => x86/include}/rte_io.h |   0
 .../arch/x86 => x86/include}/rte_mcslock.h    |   0
 .../arch/x86 => x86/include}/rte_memcpy.h     |   0
 .../arch/x86 => x86/include}/rte_pause.h      |   0
 .../arch/x86 => x86/include}/rte_prefetch.h   |   0
 .../arch/x86 => x86/include}/rte_rtm.h        |   0
 .../arch/x86 => x86/include}/rte_rwlock.h     |   0
 .../arch/x86 => x86/include}/rte_spinlock.h   |   0
 .../arch/x86 => x86/include}/rte_ticketlock.h |   0
 .../arch/x86 => x86/include}/rte_vect.h       |   0
 lib/librte_eal/x86/meson.build                |  14 +++
 .../{common/arch => }/x86/rte_cpuflags.c      |   0
 .../{common/arch => }/x86/rte_cpuid.h         |   0
 .../{common/arch => }/x86/rte_cycles.c        |   0
 .../{common/arch => }/x86/rte_hypervisor.c    |   0
 .../{common/arch => }/x86/rte_spinlock.c      |   0
 lib/librte_kvargs/Makefile                    |   2 +-
 license/exceptions.txt                        |   6 +-
 meson.build                                   |   4 +-
 mk/exec-env/freebsd/rte.vars.mk               |   2 +-
 mk/exec-env/linux/rte.vars.mk                 |   2 +-
 214 files changed, 330 insertions(+), 456 deletions(-)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/meson.build (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_atomic.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_atomic_32.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_atomic_64.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_byteorder.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_cpuflags.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_cpuflags_32.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_cpuflags_64.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_cycles.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_cycles_32.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_cycles_64.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_io.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_io_64.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_mcslock.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_memcpy.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_memcpy_32.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_memcpy_64.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_pause.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_pause_32.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_pause_64.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_prefetch.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_prefetch_32.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_prefetch_64.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_rwlock.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_spinlock.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_ticketlock.h (100%)
 rename lib/librte_eal/{common/include/arch/arm => arm/include}/rte_vect.h (100%)
 create mode 100644 lib/librte_eal/arm/meson.build
 rename lib/librte_eal/{common/arch => }/arm/rte_cpuflags.c (100%)
 rename lib/librte_eal/{common/arch => }/arm/rte_cycles.c (100%)
 rename lib/librte_eal/{common/arch => }/arm/rte_hypervisor.c (100%)
 delete mode 100644 lib/librte_eal/common/Makefile
 delete mode 100644 lib/librte_eal/common/arch/arm/meson.build
 delete mode 100644 lib/librte_eal/common/arch/ppc_64/meson.build
 delete mode 100644 lib/librte_eal/common/arch/x86/meson.build
 delete mode 100644 lib/librte_eal/freebsd/BSDmakefile.meson
 rename lib/librte_eal/freebsd/{eal => }/eal.c (100%)
 delete mode 100644 lib/librte_eal/freebsd/eal/Makefile
 rename lib/librte_eal/freebsd/{eal => }/eal_alarm.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_alarm_private.h (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_cpuflags.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_debug.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_dev.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_hugepage_info.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_interrupts.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_lcore.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_memalloc.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_memory.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_thread.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/eal_timer.c (100%)
 rename lib/librte_eal/freebsd/{eal => }/include/rte_os.h (100%)
 rename lib/librte_eal/freebsd/{eal => }/meson.build (77%)
 rename lib/librte_eal/{common => }/include/generic/rte_atomic.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_byteorder.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_cpuflags.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_cycles.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_io.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_mcslock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_memcpy.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_pause.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_prefetch.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_rwlock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_spinlock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_ticketlock.h (100%)
 rename lib/librte_eal/{common => }/include/generic/rte_vect.h (100%)
 rename lib/librte_eal/{common => }/include/rte_alarm.h (100%)
 rename lib/librte_eal/{common => }/include/rte_bitmap.h (100%)
 rename lib/librte_eal/{common => }/include/rte_branch_prediction.h (100%)
 rename lib/librte_eal/{common => }/include/rte_bus.h (100%)
 rename lib/librte_eal/{common => }/include/rte_class.h (100%)
 rename lib/librte_eal/{common => }/include/rte_common.h (100%)
 rename lib/librte_eal/{common => }/include/rte_compat.h (100%)
 rename lib/librte_eal/{common => }/include/rte_debug.h (100%)
 rename lib/librte_eal/{common => }/include/rte_dev.h (100%)
 rename lib/librte_eal/{common => }/include/rte_devargs.h (100%)
 rename lib/librte_eal/{common => }/include/rte_eal.h (100%)
 rename lib/librte_eal/{common => }/include/rte_eal_interrupts.h (100%)
 rename lib/librte_eal/{common => }/include/rte_eal_memconfig.h (100%)
 rename lib/librte_eal/{common => }/include/rte_errno.h (100%)
 rename lib/librte_eal/{common => }/include/rte_fbarray.h (100%)
 rename lib/librte_eal/{common => }/include/rte_function_versioning.h (100%)
 rename lib/librte_eal/{common => }/include/rte_hexdump.h (100%)
 rename lib/librte_eal/{common => }/include/rte_hypervisor.h (100%)
 rename lib/librte_eal/{common => }/include/rte_interrupts.h (100%)
 rename lib/librte_eal/{common => }/include/rte_keepalive.h (100%)
 rename lib/librte_eal/{common => }/include/rte_launch.h (100%)
 rename lib/librte_eal/{common => }/include/rte_lcore.h (100%)
 rename lib/librte_eal/{common => }/include/rte_log.h (100%)
 rename lib/librte_eal/{common => }/include/rte_malloc.h (100%)
 rename lib/librte_eal/{common => }/include/rte_memory.h (100%)
 rename lib/librte_eal/{common => }/include/rte_memzone.h (100%)
 rename lib/librte_eal/{common => }/include/rte_option.h (100%)
 rename lib/librte_eal/{common => }/include/rte_pci_dev_feature_defs.h (100%)
 rename lib/librte_eal/{common => }/include/rte_pci_dev_features.h (100%)
 rename lib/librte_eal/{common => }/include/rte_per_lcore.h (100%)
 rename lib/librte_eal/{common => }/include/rte_random.h (100%)
 rename lib/librte_eal/{common => }/include/rte_reciprocal.h (100%)
 rename lib/librte_eal/{common => }/include/rte_service.h (100%)
 rename lib/librte_eal/{common => }/include/rte_service_component.h (100%)
 rename lib/librte_eal/{common => }/include/rte_string_fns.h (100%)
 rename lib/librte_eal/{common => }/include/rte_tailq.h (100%)
 rename lib/librte_eal/{common => }/include/rte_test.h (100%)
 rename lib/librte_eal/{common => }/include/rte_time.h (100%)
 rename lib/librte_eal/{common => }/include/rte_uuid.h (100%)
 rename lib/librte_eal/{common => }/include/rte_version.h (100%)
 rename lib/librte_eal/{common => }/include/rte_vfio.h (100%)
 rename lib/librte_eal/linux/{eal => }/eal.c (100%)
 delete mode 100644 lib/librte_eal/linux/eal/Makefile
 rename lib/librte_eal/linux/{eal => }/eal_alarm.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_cpuflags.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_debug.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_dev.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_hugepage_info.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_interrupts.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_lcore.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_log.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_memalloc.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_memory.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_thread.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_timer.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_vfio.c (100%)
 rename lib/librte_eal/linux/{eal => }/eal_vfio.h (100%)
 rename lib/librte_eal/linux/{eal => }/eal_vfio_mp_sync.c (100%)
 rename lib/librte_eal/linux/{eal => }/include/rte_kni_common.h (100%)
 rename lib/librte_eal/linux/{eal => }/include/rte_os.h (100%)
 rename lib/librte_eal/linux/{eal => }/meson.build (81%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/meson.build (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_atomic.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_byteorder.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_cpuflags.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_cycles.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_io.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_mcslock.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_memcpy.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_pause.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_prefetch.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_rwlock.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_spinlock.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_ticketlock.h (100%)
 rename lib/librte_eal/{common/include/arch/ppc_64 => ppc/include}/rte_vect.h (100%)
 create mode 100644 lib/librte_eal/ppc/meson.build
 rename lib/librte_eal/{common/arch/ppc_64 => ppc}/rte_cpuflags.c (100%)
 rename lib/librte_eal/{common/arch/ppc_64 => ppc}/rte_cycles.c (100%)
 rename lib/librte_eal/{common/arch/ppc_64 => ppc}/rte_hypervisor.c (100%)
 rename lib/librte_eal/windows/{eal => }/eal.c (100%)
 delete mode 100644 lib/librte_eal/windows/eal/meson.build
 rename lib/librte_eal/windows/{eal => }/eal_debug.c (100%)
 rename lib/librte_eal/windows/{eal => }/eal_lcore.c (100%)
 rename lib/librte_eal/windows/{eal => }/eal_thread.c (100%)
 rename lib/librte_eal/windows/{eal => }/getopt.c (100%)
 rename lib/librte_eal/windows/{eal => }/include/dirent.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/fnmatch.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/getopt.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/pthread.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/regex.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/rte_os.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/sched.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/sys/queue.h (100%)
 rename lib/librte_eal/windows/{eal => }/include/unistd.h (100%)
 create mode 100644 lib/librte_eal/windows/meson.build
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/meson.build (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_atomic.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_atomic_32.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_atomic_64.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_byteorder.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_byteorder_32.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_byteorder_64.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_cpuflags.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_cycles.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_io.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_mcslock.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_memcpy.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_pause.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_prefetch.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_rtm.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_rwlock.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_spinlock.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_ticketlock.h (100%)
 rename lib/librte_eal/{common/include/arch/x86 => x86/include}/rte_vect.h (100%)
 create mode 100644 lib/librte_eal/x86/meson.build
 rename lib/librte_eal/{common/arch => }/x86/rte_cpuflags.c (100%)
 rename lib/librte_eal/{common/arch => }/x86/rte_cpuid.h (100%)
 rename lib/librte_eal/{common/arch => }/x86/rte_cycles.c (100%)
 rename lib/librte_eal/{common/arch => }/x86/rte_hypervisor.c (100%)
 rename lib/librte_eal/{common/arch => }/x86/rte_spinlock.c (100%)

diff --git a/MAINTAINERS b/MAINTAINERS
index c3785554fc..6be6c77574 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -126,7 +126,6 @@ F: doc/guides/prog_guide/ext_app_lib_make_help.rst
 Meson build
 M: Bruce Richardson <bruce.richardson@intel.com>
 F: meson.build
-F: lib/librte_eal/freebsd/BSDmakefile.meson
 F: meson_options.txt
 F: config/rte_config.h
 F: buildtools/call-sphinx-build.py
@@ -143,8 +142,8 @@ F: .ci/
 
 ABI versioning
 M: Neil Horman <nhorman@tuxdriver.com>
-F: lib/librte_eal/common/include/rte_compat.h
-F: lib/librte_eal/common/include/rte_function_versioning.h
+F: lib/librte_eal/include/rte_compat.h
+F: lib/librte_eal/include/rte_function_versioning.h
 F: doc/guides/rel_notes/deprecation.rst
 F: devtools/check-abi.sh
 F: devtools/check-abi-version.sh
@@ -169,9 +168,8 @@ Environment Abstraction Layer
 T: git://dpdk.org/dpdk
 
 EAL API and common code
-F: lib/librte_eal/common/*
-F: lib/librte_eal/common/include/*
-F: lib/librte_eal/common/include/generic/
+F: lib/librte_eal/common/
+F: lib/librte_eal/include/
 F: lib/librte_eal/rte_eal_version.map
 F: doc/guides/prog_guide/env_abstraction_layer.rst
 F: app/test/test_alarm.c
@@ -198,15 +196,15 @@ F: app/test/test_version.c
 
 Memory Allocation
 M: Anatoly Burakov <anatoly.burakov@intel.com>
-F: lib/librte_eal/common/include/rte_fbarray.h
-F: lib/librte_eal/common/include/rte_mem*
-F: lib/librte_eal/common/include/rte_malloc.h
+F: lib/librte_eal/include/rte_fbarray.h
+F: lib/librte_eal/include/rte_mem*
+F: lib/librte_eal/include/rte_malloc.h
 F: lib/librte_eal/common/*malloc*
 F: lib/librte_eal/common/eal_common_fbarray.c
 F: lib/librte_eal/common/eal_common_mem*
 F: lib/librte_eal/common/eal_hugepages.h
-F: lib/librte_eal/linux/eal/eal_mem*
-F: lib/librte_eal/freebsd/eal/eal_mem*
+F: lib/librte_eal/linux/eal_mem*
+F: lib/librte_eal/freebsd/eal_mem*
 F: doc/guides/prog_guide/env_abstraction_layer.rst
 F: app/test/test_external_mem.c
 F: app/test/test_func_reentrancy.c
@@ -216,7 +214,7 @@ F: app/test/test_memory.c
 F: app/test/test_memzone.c
 
 Keep alive
-F: lib/librte_eal/common/include/rte_keepalive.h
+F: lib/librte_eal/include/rte_keepalive.h
 F: lib/librte_eal/common/rte_keepalive.c
 F: examples/l2fwd-keepalive/
 F: doc/guides/sample_app_ug/keep_alive.rst
@@ -232,43 +230,42 @@ F: doc/guides/sample_app_ug/multi_process.rst
 
 Service Cores
 M: Harry van Haaren <harry.van.haaren@intel.com>
-F: lib/librte_eal/common/include/rte_service.h
-F: lib/librte_eal/common/include/rte_service_component.h
+F: lib/librte_eal/include/rte_service.h
+F: lib/librte_eal/include/rte_service_component.h
 F: lib/librte_eal/common/rte_service.c
 F: doc/guides/prog_guide/service_cores.rst
 F: app/test/test_service_cores.c
 
 Bitmap
 M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
-F: lib/librte_eal/common/include/rte_bitmap.h
+F: lib/librte_eal/include/rte_bitmap.h
 F: app/test/test_bitmap.c
 
 MCSlock - EXPERIMENTAL
 M: Phil Yang <phil.yang@arm.com>
-F: lib/librte_eal/common/include/generic/rte_mcslock.h
+F: lib/librte_eal/include/generic/rte_mcslock.h
 F: app/test/test_mcslock.c
 
 Ticketlock
 M: Joyce Kong <joyce.kong@arm.com>
-F: lib/librte_eal/common/include/generic/rte_ticketlock.h
+F: lib/librte_eal/include/generic/rte_ticketlock.h
 F: app/test/test_ticketlock.c
 
 Pseudo-random Number Generation
 M: Mattias Rönnblom <mattias.ronnblom@ericsson.com>
-F: lib/librte_eal/common/include/rte_random.h
+F: lib/librte_eal/include/rte_random.h
 F: lib/librte_eal/common/rte_random.c
 F: app/test/test_rand_perf.c
 
 ARM v7
 M: Jan Viktorin <viktorin@rehivetech.com>
 M: Gavin Hu <gavin.hu@arm.com>
-F: lib/librte_eal/common/arch/arm/
-F: lib/librte_eal/common/include/arch/arm/
+F: lib/librte_eal/arm/
 
 ARM v8
 M: Jerin Jacob <jerinj@marvell.com>
 M: Gavin Hu <gavin.hu@arm.com>
-F: lib/librte_eal/common/include/arch/arm/*_64.h
+F: lib/librte_eal/arm/include/*_64.h
 F: lib/librte_net/net_crc_neon.h
 F: lib/librte_acl/acl_run_neon.*
 F: lib/librte_bpf/bpf_jit_arm64.c
@@ -282,20 +279,17 @@ F: drivers/net/virtio/virtio_rxtx_simple_neon.c
 
 IBM POWER (alpha)
 M: David Christensen <drc@linux.vnet.ibm.com>
-F: lib/librte_eal/common/arch/ppc_64/
-F: lib/librte_eal/common/include/arch/ppc_64/
+F: lib/librte_eal/ppc/
 F: drivers/net/i40e/i40e_rxtx_vec_altivec.c
 F: examples/l3fwd/*altivec.h
 
 Intel x86
 M: Bruce Richardson <bruce.richardson@intel.com>
 M: Konstantin Ananyev <konstantin.ananyev@intel.com>
-F: lib/librte_eal/common/arch/x86/
-F: lib/librte_eal/common/include/arch/x86/
+F: lib/librte_eal/x86/
 
 Linux EAL (with overlaps)
-F: lib/librte_eal/linux/Makefile
-F: lib/librte_eal/linux/eal/
+F: lib/librte_eal/linux/
 F: doc/guides/linux_gsg/
 
 Linux UIO
@@ -305,13 +299,12 @@ F: drivers/bus/pci/linux/*uio*
 
 Linux VFIO
 M: Anatoly Burakov <anatoly.burakov@intel.com>
-F: lib/librte_eal/linux/eal/*vfio*
+F: lib/librte_eal/linux/*vfio*
 F: drivers/bus/pci/linux/*vfio*
 
 FreeBSD EAL (with overlaps)
 M: Bruce Richardson <bruce.richardson@intel.com>
-F: lib/librte_eal/freebsd/Makefile
-F: lib/librte_eal/freebsd/eal/
+F: lib/librte_eal/freebsd/
 F: doc/guides/freebsd_gsg/
 
 FreeBSD contigmem
diff --git a/buildtools/pmdinfogen/meson.build b/buildtools/pmdinfogen/meson.build
index 899ba112cd..7da415b3b7 100644
--- a/buildtools/pmdinfogen/meson.build
+++ b/buildtools/pmdinfogen/meson.build
@@ -6,7 +6,7 @@ if host_machine.system() == 'windows'
 endif
 
 pmdinfogen_inc = [global_inc]
-pmdinfogen_inc += include_directories('../../lib/librte_eal/common/include')
+pmdinfogen_inc += include_directories('../../lib/librte_eal/include')
 pmdinfogen_inc += include_directories('../../lib/librte_pci')
 pmdinfogen = executable('pmdinfogen',
 	'pmdinfogen.c',
diff --git a/config/arm/meson.build b/config/arm/meson.build
index 7e22358358..6e75e6d97e 100644
--- a/config/arm/meson.build
+++ b/config/arm/meson.build
@@ -11,7 +11,7 @@ arm_force_default_march = (machine == 'default')
 flags_common_default = [
 	# Accelarate rte_memcpy. Be sure to run unit test (memcpy_perf_autotest)
 	# to determine the best threshold in code. Refer to notes in source file
-	# (lib/librte_eal/common/include/arch/arm/rte_memcpy_64.h) for more info.
+	# (lib/librte_eal/arm/include/rte_memcpy_64.h) for more info.
 	['RTE_ARCH_ARM64_MEMCPY', false],
 	#	['RTE_ARM64_MEMCPY_ALIGNED_THRESHOLD', 2048],
 	#	['RTE_ARM64_MEMCPY_UNALIGNED_THRESHOLD', 512],
diff --git a/config/common_armv8a_linux b/config/common_armv8a_linux
index 020f8f006c..e942657a0f 100644
--- a/config/common_armv8a_linux
+++ b/config/common_armv8a_linux
@@ -21,7 +21,7 @@ CONFIG_RTE_USE_C11_MEM_MODEL=y
 
 # Accelarate rte_memcpy. Be sure to run unit test (memcpy_perf_autotest)
 # to determine the best threshold in code. Refer to notes in source file
-# (lib/librte_eal/common/include/arch/arm/rte_memcpy_64.h) for more info.
+# (lib/librte_eal/arm/include/rte_memcpy_64.h) for more info.
 CONFIG_RTE_ARCH_ARM64_MEMCPY=n
 #CONFIG_RTE_ARM64_MEMCPY_ALIGNED_THRESHOLD=2048
 #CONFIG_RTE_ARM64_MEMCPY_UNALIGNED_THRESHOLD=512
diff --git a/config/meson.build b/config/meson.build
index abedd76f23..58421342b1 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -234,7 +234,7 @@ if host_machine.cpu_family().startswith('x86')
 elif host_machine.cpu_family().startswith('arm') or host_machine.cpu_family().startswith('aarch')
 	arch_subdir = 'arm'
 elif host_machine.cpu_family().startswith('ppc')
-	arch_subdir = 'ppc_64'
+	arch_subdir = 'ppc'
 endif
 subdir(arch_subdir)
 dpdk_conf.set('RTE_COMPILE_TIME_CPUFLAGS', ','.join(compile_time_cpuflags))
diff --git a/devtools/build-tags.sh b/devtools/build-tags.sh
index dc037f92b3..276fff647b 100755
--- a/devtools/build-tags.sh
+++ b/devtools/build-tags.sh
@@ -79,29 +79,26 @@ bsd_sources()
 
 arm_common()
 {
-	find_sources "lib/librte_eal/common/arch/arm" '*.[chS]'
 	find_sources "$source_dirs" '*neon*.[chS]'
 }
 
 arm_32_sources()
 {
 	arm_common
-	find_sources "lib/librte_eal/common/include/arch/arm" '*.[chS]' \
+	find_sources "lib/librte_eal/arm" '*.[chS]' \
 					"$skip_64b_files"
 }
 
 arm_64_sources()
 {
 	arm_common
-	find_sources "lib/librte_eal/common/include/arch/arm" '*.[chS]' \
+	find_sources "lib/librte_eal/arm" '*.[chS]' \
 					 "$skip_32b_files"
 	find_sources "$source_dirs" '*arm64.[chS]'
 }
 
 x86_common()
 {
-	find_sources "lib/librte_eal/common/arch/x86" '*.[chS]'
-
 	find_sources "examples/performance-thread/common/arch/x86" '*.[chS]'
 	find_sources "$source_dirs" '*_sse*.[chS]'
 	find_sources "$source_dirs" '*_avx*.[chS]'
@@ -111,21 +108,20 @@ x86_common()
 x86_32_sources()
 {
 	x86_common
-	find_sources "lib/librte_eal/common/include/arch/x86" '*.[chS]' \
+	find_sources "lib/librte_eal/x86" '*.[chS]' \
 					"$skip_64b_files"
 }
 
 x86_64_sources()
 {
 	x86_common
-	find_sources "lib/librte_eal/common/include/arch/x86" '*.[chS]' \
+	find_sources "lib/librte_eal/x86" '*.[chS]' \
 					"$skip_32b_files"
 }
 
 ppc_64_sources()
 {
-	find_sources "lib/librte_eal/common/arch/ppc_64" '*.[chS]'
-	find_sources "lib/librte_eal/common/include/arch/ppc_64" '*.[chS]'
+	find_sources "lib/librte_eal/ppc" '*.[chS]'
 	find_sources "$source_dirs" '*altivec*.[chS]'
 }
 
diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in
index 1c4392eecc..65e8146bef 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -17,8 +17,8 @@ INPUT                   = @TOPDIR@/doc/api/doxy-api-index.md \
                           @TOPDIR@/drivers/net/softnic \
                           @TOPDIR@/drivers/raw/dpaa2_cmdif \
                           @TOPDIR@/drivers/raw/dpaa2_qdma \
-                          @TOPDIR@/lib/librte_eal/common/include \
-                          @TOPDIR@/lib/librte_eal/common/include/generic \
+                          @TOPDIR@/lib/librte_eal/include \
+                          @TOPDIR@/lib/librte_eal/include/generic \
                           @TOPDIR@/lib/librte_acl \
                           @TOPDIR@/lib/librte_bbdev \
                           @TOPDIR@/lib/librte_bitratestats \
diff --git a/doc/guides/rel_notes/known_issues.rst b/doc/guides/rel_notes/known_issues.rst
index 68c3d22bea..de0782136d 100644
--- a/doc/guides/rel_notes/known_issues.rst
+++ b/doc/guides/rel_notes/known_issues.rst
@@ -127,7 +127,7 @@ HPET timers do not work on the Osage customer reference platform
    work correctly, provided the BIOS supports HPET.
 
 **Driver/Module**:
-   ``lib/librte_eal/common/include/rte_cycles.h``
+   ``lib/librte_eal/include/rte_cycles.h``
 
 
 Not all variants of supported NIC types have been used in testing
diff --git a/drivers/bus/dpaa/Makefile b/drivers/bus/dpaa/Makefile
index cd1093f744..9e1a31bb75 100644
--- a/drivers/bus/dpaa/Makefile
+++ b/drivers/bus/dpaa/Makefile
@@ -18,7 +18,7 @@ CFLAGS += -I$(RTE_BUS_DPAA)/
 CFLAGS += -I$(RTE_BUS_DPAA)/include
 CFLAGS += -I$(RTE_BUS_DPAA)/base/qbman
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 # versioning export map
 EXPORT_MAP := rte_bus_dpaa_version.map
diff --git a/drivers/common/mlx5/meson.build b/drivers/common/mlx5/meson.build
index 141739fd6f..f671710714 100644
--- a/drivers/common/mlx5/meson.build
+++ b/drivers/common/mlx5/meson.build
@@ -203,7 +203,7 @@ if dlopen_ibverbs
 	dlopen_install_dir = [ eal_pmd_path + '-glue' ]
 	dlopen_includes = [global_inc]
 	dlopen_includes += include_directories(
-		'../../../lib/librte_eal/common/include/generic',
+		'../../../lib/librte_eal/include/generic',
 	)
 	shared_lib = shared_library(
 		dlopen_lib_name,
diff --git a/drivers/crypto/caam_jr/Makefile b/drivers/crypto/caam_jr/Makefile
index 1b1f25a2a2..db17294395 100644
--- a/drivers/crypto/caam_jr/Makefile
+++ b/drivers/crypto/caam_jr/Makefile
@@ -20,7 +20,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/include
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax/caamflib/
 CFLAGS += -I$(RTE_SDK)/drivers/crypto/caam_jr
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 # versioning export map
 EXPORT_MAP := rte_pmd_caam_jr_version.map
diff --git a/drivers/crypto/dpaa_sec/Makefile b/drivers/crypto/dpaa_sec/Makefile
index fbfd775855..13a5ff20cf 100644
--- a/drivers/crypto/dpaa_sec/Makefile
+++ b/drivers/crypto/dpaa_sec/Makefile
@@ -20,7 +20,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/base/qbman
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
 CFLAGS += -I$(RTE_SDK)/drivers/crypto/dpaa_sec/
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax/caamflib/
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_cryptodev
 
diff --git a/drivers/event/dpaa/Makefile b/drivers/event/dpaa/Makefile
index 2f53efdf9e..15ffc157f8 100644
--- a/drivers/event/dpaa/Makefile
+++ b/drivers/event/dpaa/Makefile
@@ -20,7 +20,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa
 CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/include/
 CFLAGS += -I$(RTE_SDK)/drivers/mempool/dpaa
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 LDLIBS += -lrte_pmd_dpaa_sec
 CFLAGS += -I$(RTE_SDK)/drivers/crypto/dpaa_sec
diff --git a/drivers/net/dpaa/Makefile b/drivers/net/dpaa/Makefile
index 8e049b2a0b..f63c9bf540 100644
--- a/drivers/net/dpaa/Makefile
+++ b/drivers/net/dpaa/Makefile
@@ -21,7 +21,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/dpaa/base/qbman
 CFLAGS += -I$(RTE_SDK)/drivers/mempool/dpaa
 CFLAGS += -I$(RTE_SDK)/drivers/common/dpaax
 CFLAGS += -I$(RTE_SDK)/drivers/event/dpaa
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 EXPORT_MAP := rte_pmd_dpaa_version.map
 
diff --git a/drivers/net/virtio/meson.build b/drivers/net/virtio/meson.build
index 04c7fdf25d..5e7ca855c8 100644
--- a/drivers/net/virtio/meson.build
+++ b/drivers/net/virtio/meson.build
@@ -11,7 +11,7 @@ deps += ['kvargs', 'bus_pci']
 
 if arch_subdir == 'x86'
 	sources += files('virtio_rxtx_simple_sse.c')
-elif arch_subdir == 'ppc_64'
+elif arch_subdir == 'ppc'
 	sources += files('virtio_rxtx_simple_altivec.c')
 elif arch_subdir == 'arm' and host_machine.cpu_family().startswith('aarch64')
 	sources += files('virtio_rxtx_simple_neon.c')
diff --git a/kernel/linux/igb_uio/meson.build b/kernel/linux/igb_uio/meson.build
index fac404f078..80540aecee 100644
--- a/kernel/linux/igb_uio/meson.build
+++ b/kernel/linux/igb_uio/meson.build
@@ -12,7 +12,7 @@ custom_target('igb_uio',
 		'M=' + meson.current_build_dir(),
 		'src=' + meson.current_source_dir(),
 		'EXTRA_CFLAGS=-I' + meson.current_source_dir() +
-			'/../../../lib/librte_eal/common/include',
+			'/../../../lib/librte_eal/include',
 		'modules'],
 	depends: mkfile,
 	install: true,
diff --git a/kernel/linux/kni/meson.build b/kernel/linux/kni/meson.build
index f93e97fa09..d696347f22 100644
--- a/kernel/linux/kni/meson.build
+++ b/kernel/linux/kni/meson.build
@@ -17,8 +17,8 @@ custom_target('rte_kni',
 		'M=' + meson.current_build_dir(),
 		'src=' + meson.current_source_dir(),
 		'MODULE_CFLAGS=-include ' + meson.source_root() + '/config/rte_config.h' +
-		' -I' + meson.source_root() + '/lib/librte_eal/common/include' +
-		' -I' + meson.source_root() + '/lib/librte_eal/linux/eal/include' +
+		' -I' + meson.source_root() + '/lib/librte_eal/include' +
+		' -I' + meson.source_root() + '/lib/librte_eal/linux/include' +
 		' -I' + meson.build_root() +
 		' -I' + meson.current_source_dir(),
 		'modules'],
diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile
index d3b08420ff..7c10a4e56c 100644
--- a/lib/librte_cfgfile/Makefile
+++ b/lib/librte_cfgfile/Makefile
@@ -10,7 +10,7 @@ LIB = librte_cfgfile.a
 
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-CFLAGS += -I$(SRCDIR)/../librte_eal/common/include
+CFLAGS += -I$(SRCDIR)/../librte_eal/include
 LDLIBS += -lrte_eal
 
 EXPORT_MAP := rte_cfgfile_version.map
diff --git a/lib/librte_eal/Makefile b/lib/librte_eal/Makefile
index 86434f5b31..2fda40d230 100644
--- a/lib/librte_eal/Makefile
+++ b/lib/librte_eal/Makefile
@@ -3,10 +3,10 @@
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-DIRS-y += common
+DIRS-y += include
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += linux
-DEPDIRS-linux := common
+DEPDIRS-linux := include
 DIRS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += freebsd
-DEPDIRS-freebsd := common
+DEPDIRS-freebsd := include
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/lib/librte_eal/common/include/arch/arm/meson.build b/lib/librte_eal/arm/include/meson.build
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/meson.build
rename to lib/librte_eal/arm/include/meson.build
diff --git a/lib/librte_eal/common/include/arch/arm/rte_atomic.h b/lib/librte_eal/arm/include/rte_atomic.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_atomic.h
rename to lib/librte_eal/arm/include/rte_atomic.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_atomic_32.h b/lib/librte_eal/arm/include/rte_atomic_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_atomic_32.h
rename to lib/librte_eal/arm/include/rte_atomic_32.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_atomic_64.h b/lib/librte_eal/arm/include/rte_atomic_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_atomic_64.h
rename to lib/librte_eal/arm/include/rte_atomic_64.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_byteorder.h b/lib/librte_eal/arm/include/rte_byteorder.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_byteorder.h
rename to lib/librte_eal/arm/include/rte_byteorder.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_cpuflags.h b/lib/librte_eal/arm/include/rte_cpuflags.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_cpuflags.h
rename to lib/librte_eal/arm/include/rte_cpuflags.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_cpuflags_32.h b/lib/librte_eal/arm/include/rte_cpuflags_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_cpuflags_32.h
rename to lib/librte_eal/arm/include/rte_cpuflags_32.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_cpuflags_64.h b/lib/librte_eal/arm/include/rte_cpuflags_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_cpuflags_64.h
rename to lib/librte_eal/arm/include/rte_cpuflags_64.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_cycles.h b/lib/librte_eal/arm/include/rte_cycles.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_cycles.h
rename to lib/librte_eal/arm/include/rte_cycles.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_cycles_32.h b/lib/librte_eal/arm/include/rte_cycles_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_cycles_32.h
rename to lib/librte_eal/arm/include/rte_cycles_32.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_cycles_64.h b/lib/librte_eal/arm/include/rte_cycles_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_cycles_64.h
rename to lib/librte_eal/arm/include/rte_cycles_64.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_io.h b/lib/librte_eal/arm/include/rte_io.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_io.h
rename to lib/librte_eal/arm/include/rte_io.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_io_64.h b/lib/librte_eal/arm/include/rte_io_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_io_64.h
rename to lib/librte_eal/arm/include/rte_io_64.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_mcslock.h b/lib/librte_eal/arm/include/rte_mcslock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_mcslock.h
rename to lib/librte_eal/arm/include/rte_mcslock.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_memcpy.h b/lib/librte_eal/arm/include/rte_memcpy.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_memcpy.h
rename to lib/librte_eal/arm/include/rte_memcpy.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_memcpy_32.h b/lib/librte_eal/arm/include/rte_memcpy_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_memcpy_32.h
rename to lib/librte_eal/arm/include/rte_memcpy_32.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_memcpy_64.h b/lib/librte_eal/arm/include/rte_memcpy_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_memcpy_64.h
rename to lib/librte_eal/arm/include/rte_memcpy_64.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_pause.h b/lib/librte_eal/arm/include/rte_pause.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_pause.h
rename to lib/librte_eal/arm/include/rte_pause.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_pause_32.h b/lib/librte_eal/arm/include/rte_pause_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_pause_32.h
rename to lib/librte_eal/arm/include/rte_pause_32.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_pause_64.h b/lib/librte_eal/arm/include/rte_pause_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_pause_64.h
rename to lib/librte_eal/arm/include/rte_pause_64.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_prefetch.h b/lib/librte_eal/arm/include/rte_prefetch.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_prefetch.h
rename to lib/librte_eal/arm/include/rte_prefetch.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_prefetch_32.h b/lib/librte_eal/arm/include/rte_prefetch_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_prefetch_32.h
rename to lib/librte_eal/arm/include/rte_prefetch_32.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_prefetch_64.h b/lib/librte_eal/arm/include/rte_prefetch_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_prefetch_64.h
rename to lib/librte_eal/arm/include/rte_prefetch_64.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_rwlock.h b/lib/librte_eal/arm/include/rte_rwlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_rwlock.h
rename to lib/librte_eal/arm/include/rte_rwlock.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_spinlock.h b/lib/librte_eal/arm/include/rte_spinlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_spinlock.h
rename to lib/librte_eal/arm/include/rte_spinlock.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_ticketlock.h b/lib/librte_eal/arm/include/rte_ticketlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_ticketlock.h
rename to lib/librte_eal/arm/include/rte_ticketlock.h
diff --git a/lib/librte_eal/common/include/arch/arm/rte_vect.h b/lib/librte_eal/arm/include/rte_vect.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/arm/rte_vect.h
rename to lib/librte_eal/arm/include/rte_vect.h
diff --git a/lib/librte_eal/arm/meson.build b/lib/librte_eal/arm/meson.build
new file mode 100644
index 0000000000..883cdd8060
--- /dev/null
+++ b/lib/librte_eal/arm/meson.build
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation.
+
+includes += include_directories('include')
+
+headers += files(
+)
+
+sources += files(
+	'rte_cpuflags.c',
+	'rte_cycles.c',
+	'rte_hypervisor.c',
+)
diff --git a/lib/librte_eal/common/arch/arm/rte_cpuflags.c b/lib/librte_eal/arm/rte_cpuflags.c
similarity index 100%
rename from lib/librte_eal/common/arch/arm/rte_cpuflags.c
rename to lib/librte_eal/arm/rte_cpuflags.c
diff --git a/lib/librte_eal/common/arch/arm/rte_cycles.c b/lib/librte_eal/arm/rte_cycles.c
similarity index 100%
rename from lib/librte_eal/common/arch/arm/rte_cycles.c
rename to lib/librte_eal/arm/rte_cycles.c
diff --git a/lib/librte_eal/common/arch/arm/rte_hypervisor.c b/lib/librte_eal/arm/rte_hypervisor.c
similarity index 100%
rename from lib/librte_eal/common/arch/arm/rte_hypervisor.c
rename to lib/librte_eal/arm/rte_hypervisor.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
deleted file mode 100644
index c2c6d92cd3..0000000000
--- a/lib/librte_eal/common/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-INC := rte_branch_prediction.h rte_common.h rte_compat.h
-INC += rte_function_versioning.h
-INC += rte_debug.h rte_eal.h rte_eal_interrupts.h
-INC += rte_errno.h rte_launch.h rte_lcore.h
-INC += rte_log.h rte_memory.h rte_memzone.h
-INC += rte_per_lcore.h rte_random.h
-INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
-INC += rte_eal_memconfig.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
-INC += rte_option.h
-INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
-INC += rte_malloc.h rte_keepalive.h rte_time.h
-INC += rte_service.h rte_service_component.h
-INC += rte_bitmap.h rte_vfio.h rte_hypervisor.h rte_test.h
-INC += rte_reciprocal.h rte_fbarray.h rte_uuid.h
-
-GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h
-GENERIC_INC += rte_memcpy.h rte_cpuflags.h
-GENERIC_INC += rte_mcslock.h rte_spinlock.h rte_rwlock.h rte_ticketlock.h
-GENERIC_INC += rte_vect.h rte_pause.h rte_io.h
-
-# defined in mk/arch/$(RTE_ARCH)/rte.vars.mk
-ARCH_DIR ?= $(RTE_ARCH)
-ARCH_INC := $(sort $(notdir $(wildcard $(RTE_SDK)/lib/librte_eal/common/include/arch/$(ARCH_DIR)/*.h)))
-
-SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include := $(addprefix include/,$(INC))
-SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include += \
-	$(addprefix include/arch/$(ARCH_DIR)/,$(ARCH_INC))
-SYMLINK-$(CONFIG_RTE_LIBRTE_EAL)-include/generic := \
-	$(addprefix include/generic/,$(GENERIC_INC))
-
-include $(RTE_SDK)/mk/rte.install.mk
diff --git a/lib/librte_eal/common/arch/arm/meson.build b/lib/librte_eal/common/arch/arm/meson.build
deleted file mode 100644
index 79731e1a2c..0000000000
--- a/lib/librte_eal/common/arch/arm/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2017 Intel Corporation.
-
-eal_common_arch_sources = files('rte_cpuflags.c',
-	'rte_cycles.c', 'rte_hypervisor.c')
diff --git a/lib/librte_eal/common/arch/ppc_64/meson.build b/lib/librte_eal/common/arch/ppc_64/meson.build
deleted file mode 100644
index 40b3dc533a..0000000000
--- a/lib/librte_eal/common/arch/ppc_64/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2018 Luca Boccassi <bluca@debian.org>
-
-eal_common_arch_sources = files('rte_cpuflags.c',
-	'rte_cycles.c', 'rte_hypervisor.c')
diff --git a/lib/librte_eal/common/arch/x86/meson.build b/lib/librte_eal/common/arch/x86/meson.build
deleted file mode 100644
index 14bf204c6f..0000000000
--- a/lib/librte_eal/common/arch/x86/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2017 Intel Corporation
-
-eal_common_arch_sources = files('rte_spinlock.c', 'rte_cpuflags.c',
-	'rte_cycles.c', 'rte_hypervisor.c')
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 2b97715a20..02d9280cc3 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -1,11 +1,25 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-eal_inc += include_directories('.', 'include',
-		join_paths('include/arch', arch_subdir))
+includes += include_directories('.')
 
-common_objs = []
-common_sources = files(
+if is_windows
+	sources += files(
+		'eal_common_bus.c',
+		'eal_common_class.c',
+		'eal_common_devargs.c',
+		'eal_common_errno.c',
+		'eal_common_launch.c',
+		'eal_common_lcore.c',
+		'eal_common_log.c',
+		'eal_common_options.c',
+		'eal_common_thread.c',
+		'rte_option.c',
+	)
+	subdir_done()
+endif
+
+sources += files(
 	'eal_common_bus.c',
 	'eal_common_cpuflags.c',
 	'eal_common_class.c',
@@ -38,73 +52,5 @@ common_sources = files(
 	'rte_option.c',
 	'rte_random.c',
 	'rte_reciprocal.c',
-	'rte_service.c'
+	'rte_service.c',
 )
-
-# get architecture specific sources and objs
-eal_common_arch_sources = []
-eal_common_arch_objs = []
-subdir(join_paths('arch', arch_subdir))
-common_sources += eal_common_arch_sources
-common_objs += eal_common_arch_objs
-
-common_headers = files(
-	'include/rte_alarm.h',
-	'include/rte_branch_prediction.h',
-	'include/rte_bus.h',
-	'include/rte_bitmap.h',
-	'include/rte_class.h',
-	'include/rte_common.h',
-	'include/rte_compat.h',
-	'include/rte_debug.h',
-	'include/rte_devargs.h',
-	'include/rte_dev.h',
-	'include/rte_eal.h',
-	'include/rte_eal_memconfig.h',
-	'include/rte_eal_interrupts.h',
-	'include/rte_errno.h',
-	'include/rte_fbarray.h',
-	'include/rte_hexdump.h',
-	'include/rte_hypervisor.h',
-	'include/rte_interrupts.h',
-	'include/rte_keepalive.h',
-	'include/rte_launch.h',
-	'include/rte_lcore.h',
-	'include/rte_log.h',
-	'include/rte_malloc.h',
-	'include/rte_memory.h',
-	'include/rte_memzone.h',
-	'include/rte_option.h',
-	'include/rte_pci_dev_feature_defs.h',
-	'include/rte_pci_dev_features.h',
-	'include/rte_per_lcore.h',
-	'include/rte_random.h',
-	'include/rte_reciprocal.h',
-	'include/rte_service.h',
-	'include/rte_service_component.h',
-	'include/rte_string_fns.h',
-	'include/rte_tailq.h',
-	'include/rte_time.h',
-	'include/rte_uuid.h',
-	'include/rte_version.h',
-	'include/rte_vfio.h')
-
-# special case install the generic headers, since they go in a subdir
-generic_headers = files(
-	'include/generic/rte_atomic.h',
-	'include/generic/rte_byteorder.h',
-	'include/generic/rte_cpuflags.h',
-	'include/generic/rte_cycles.h',
-	'include/generic/rte_io.h',
-	'include/generic/rte_mcslock.h',
-	'include/generic/rte_memcpy.h',
-	'include/generic/rte_pause.h',
-	'include/generic/rte_prefetch.h',
-	'include/generic/rte_rwlock.h',
-	'include/generic/rte_spinlock.h',
-	'include/generic/rte_ticketlock.h',
-	'include/generic/rte_vect.h')
-install_headers(generic_headers, subdir: 'generic')
-
-# get and install the architecture specific headers
-subdir(join_paths('include/arch', arch_subdir))
diff --git a/lib/librte_eal/common/rte_service.c b/lib/librte_eal/common/rte_service.c
index b0b78baabd..70d17a5d79 100644
--- a/lib/librte_eal/common/rte_service.c
+++ b/lib/librte_eal/common/rte_service.c
@@ -10,7 +10,7 @@
 
 #include <rte_compat.h>
 #include <rte_service.h>
-#include "include/rte_service_component.h"
+#include <rte_service_component.h>
 
 #include <rte_eal.h>
 #include <rte_lcore.h>
diff --git a/lib/librte_eal/freebsd/BSDmakefile.meson b/lib/librte_eal/freebsd/BSDmakefile.meson
deleted file mode 100644
index 53c4e79c61..0000000000
--- a/lib/librte_eal/freebsd/BSDmakefile.meson
+++ /dev/null
@@ -1,14 +0,0 @@
-#   SPDX-License-Identifier: BSD-3-Clause
-#   Copyright(c) 2017 Intel Corporation.
-
-# makefile for building kernel modules using meson
-# takes parameters from the environment
-
-# source file is passed via KMOD_SRC as full path, we only use final
-# component of it, as VPATH is used to find actual file, so as to
-# have the .o files placed in the build, not source directory
-VPATH = ${KMOD_SRC:H}
-SRCS = ${KMOD_SRC:T} device_if.h bus_if.h pci_if.h
-CFLAGS += $(KMOD_CFLAGS)
-
-.include <bsd.kmod.mk>
diff --git a/lib/librte_eal/freebsd/Makefile b/lib/librte_eal/freebsd/Makefile
index fc42058b6b..265edb06f6 100644
--- a/lib/librte_eal/freebsd/Makefile
+++ b/lib/librte_eal/freebsd/Makefile
@@ -1,8 +1,92 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2010-2019 Intel Corporation
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-DIRS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal
+LIB = librte_eal.a
 
-include $(RTE_SDK)/mk/rte.subdir.mk
+ARCH_DIR ?= $(RTE_ARCH)
+VPATH += $(RTE_SDK)/lib/librte_eal/$(ARCH_DIR)
+VPATH += $(RTE_SDK)/lib/librte_eal/common
+
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(SRCDIR)/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
+CFLAGS += $(WERROR_FLAGS) -O3
+
+LDLIBS += -lexecinfo
+LDLIBS += -lpthread
+LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
+
+EXPORT_MAP := ../rte_eal_version.map
+
+# specific to freebsd exec-env
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) := eal.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_cpuflags.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_memory.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_hugepage_info.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_thread.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_debug.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_memalloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_lcore.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_timer.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_interrupts.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_alarm.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_dev.c
+
+# from common dir
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_lcore.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_timer.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_memzone.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_log.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_launch.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_mcfg.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_memalloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_memory.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_tailqs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_errno.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_cpuflags.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_hypervisor.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_string_fns.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_hexdump.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_class.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_bus.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_dev.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_options.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_thread.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_proc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_fbarray.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_uuid.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_malloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += hotplug_mp.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += malloc_elem.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += malloc_heap.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += malloc_mp.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_option.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_service.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_random.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_reciprocal.c
+
+# from arch dir
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_cpuflags.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_hypervisor.c
+SRCS-$(CONFIG_RTE_ARCH_X86) += rte_spinlock.c
+SRCS-y += rte_cycles.c
+
+CFLAGS_eal_common_cpuflags.o := $(CPUFLAGS_LIST)
+
+# workaround for a gcc bug with noreturn attribute
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+CFLAGS_eal_thread.o += -Wno-return-type
+CFLAGS_eal_hpet.o += -Wno-return-type
+endif
+
+INC := rte_os.h
+
+SYMLINK-$(CONFIG_RTE_EXEC_ENV_FREEBSD)-include := $(addprefix include/,$(INC))
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_eal/freebsd/eal/eal.c b/lib/librte_eal/freebsd/eal.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal.c
rename to lib/librte_eal/freebsd/eal.c
diff --git a/lib/librte_eal/freebsd/eal/Makefile b/lib/librte_eal/freebsd/eal/Makefile
deleted file mode 100644
index b160b57906..0000000000
--- a/lib/librte_eal/freebsd/eal/Makefile
+++ /dev/null
@@ -1,93 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2019 Intel Corporation
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-LIB = librte_eal.a
-
-ARCH_DIR ?= $(RTE_ARCH)
-VPATH += $(RTE_SDK)/lib/librte_eal/common
-VPATH += $(RTE_SDK)/lib/librte_eal/common/arch/$(ARCH_DIR)
-
-CFLAGS += -DALLOW_EXPERIMENTAL_API
-CFLAGS += -I$(SRCDIR)/include
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
-CFLAGS += $(WERROR_FLAGS) -O3
-
-LDLIBS += -lexecinfo
-LDLIBS += -lpthread
-LDLIBS += -lgcc_s
-LDLIBS += -lrte_kvargs
-
-EXPORT_MAP := ../../rte_eal_version.map
-
-# specific to freebsd exec-env
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) := eal.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_cpuflags.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_memory.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_hugepage_info.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_thread.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_debug.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_memalloc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_lcore.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_timer.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_interrupts.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_alarm.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_dev.c
-
-# from common dir
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_lcore.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_timer.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_memzone.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_log.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_launch.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_mcfg.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_memalloc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_memory.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_tailqs.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_errno.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_cpuflags.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_hypervisor.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_string_fns.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_hexdump.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_devargs.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_class.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_bus.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_dev.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_options.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_thread.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_proc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_fbarray.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += eal_common_uuid.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_malloc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += hotplug_mp.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += malloc_elem.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += malloc_heap.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += malloc_mp.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_keepalive.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_option.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_service.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_random.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_reciprocal.c
-
-# from arch dir
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_cpuflags.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_FREEBSD) += rte_hypervisor.c
-SRCS-$(CONFIG_RTE_ARCH_X86) += rte_spinlock.c
-SRCS-y += rte_cycles.c
-
-CFLAGS_eal_common_cpuflags.o := $(CPUFLAGS_LIST)
-
-# workaround for a gcc bug with noreturn attribute
-# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
-ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
-CFLAGS_eal_thread.o += -Wno-return-type
-CFLAGS_eal_hpet.o += -Wno-return-type
-endif
-
-INC := rte_os.h
-
-SYMLINK-$(CONFIG_RTE_EXEC_ENV_FREEBSD)-include := $(addprefix include/,$(INC))
-
-include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_eal/freebsd/eal/eal_alarm.c b/lib/librte_eal/freebsd/eal_alarm.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_alarm.c
rename to lib/librte_eal/freebsd/eal_alarm.c
diff --git a/lib/librte_eal/freebsd/eal/eal_alarm_private.h b/lib/librte_eal/freebsd/eal_alarm_private.h
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_alarm_private.h
rename to lib/librte_eal/freebsd/eal_alarm_private.h
diff --git a/lib/librte_eal/freebsd/eal/eal_cpuflags.c b/lib/librte_eal/freebsd/eal_cpuflags.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_cpuflags.c
rename to lib/librte_eal/freebsd/eal_cpuflags.c
diff --git a/lib/librte_eal/freebsd/eal/eal_debug.c b/lib/librte_eal/freebsd/eal_debug.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_debug.c
rename to lib/librte_eal/freebsd/eal_debug.c
diff --git a/lib/librte_eal/freebsd/eal/eal_dev.c b/lib/librte_eal/freebsd/eal_dev.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_dev.c
rename to lib/librte_eal/freebsd/eal_dev.c
diff --git a/lib/librte_eal/freebsd/eal/eal_hugepage_info.c b/lib/librte_eal/freebsd/eal_hugepage_info.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_hugepage_info.c
rename to lib/librte_eal/freebsd/eal_hugepage_info.c
diff --git a/lib/librte_eal/freebsd/eal/eal_interrupts.c b/lib/librte_eal/freebsd/eal_interrupts.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_interrupts.c
rename to lib/librte_eal/freebsd/eal_interrupts.c
diff --git a/lib/librte_eal/freebsd/eal/eal_lcore.c b/lib/librte_eal/freebsd/eal_lcore.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_lcore.c
rename to lib/librte_eal/freebsd/eal_lcore.c
diff --git a/lib/librte_eal/freebsd/eal/eal_memalloc.c b/lib/librte_eal/freebsd/eal_memalloc.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_memalloc.c
rename to lib/librte_eal/freebsd/eal_memalloc.c
diff --git a/lib/librte_eal/freebsd/eal/eal_memory.c b/lib/librte_eal/freebsd/eal_memory.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_memory.c
rename to lib/librte_eal/freebsd/eal_memory.c
diff --git a/lib/librte_eal/freebsd/eal/eal_thread.c b/lib/librte_eal/freebsd/eal_thread.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_thread.c
rename to lib/librte_eal/freebsd/eal_thread.c
diff --git a/lib/librte_eal/freebsd/eal/eal_timer.c b/lib/librte_eal/freebsd/eal_timer.c
similarity index 100%
rename from lib/librte_eal/freebsd/eal/eal_timer.c
rename to lib/librte_eal/freebsd/eal_timer.c
diff --git a/lib/librte_eal/freebsd/eal/include/rte_os.h b/lib/librte_eal/freebsd/include/rte_os.h
similarity index 100%
rename from lib/librte_eal/freebsd/eal/include/rte_os.h
rename to lib/librte_eal/freebsd/include/rte_os.h
diff --git a/lib/librte_eal/freebsd/eal/meson.build b/lib/librte_eal/freebsd/meson.build
similarity index 77%
rename from lib/librte_eal/freebsd/eal/meson.build
rename to lib/librte_eal/freebsd/meson.build
index 1426f7e5f1..b423d970f9 100644
--- a/lib/librte_eal/freebsd/eal/meson.build
+++ b/lib/librte_eal/freebsd/meson.build
@@ -1,11 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-env_objs = []
-env_headers = files(
+includes += include_directories('include')
+
+headers += files(
 		'include/rte_os.h',
 )
-env_sources = files('eal_alarm.c',
+
+sources += files('eal_alarm.c',
 		'eal_cpuflags.c',
 		'eal_debug.c',
 		'eal_hugepage_info.c',
diff --git a/lib/librte_eal/common/include/generic/rte_atomic.h b/lib/librte_eal/include/generic/rte_atomic.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_atomic.h
rename to lib/librte_eal/include/generic/rte_atomic.h
diff --git a/lib/librte_eal/common/include/generic/rte_byteorder.h b/lib/librte_eal/include/generic/rte_byteorder.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_byteorder.h
rename to lib/librte_eal/include/generic/rte_byteorder.h
diff --git a/lib/librte_eal/common/include/generic/rte_cpuflags.h b/lib/librte_eal/include/generic/rte_cpuflags.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_cpuflags.h
rename to lib/librte_eal/include/generic/rte_cpuflags.h
diff --git a/lib/librte_eal/common/include/generic/rte_cycles.h b/lib/librte_eal/include/generic/rte_cycles.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_cycles.h
rename to lib/librte_eal/include/generic/rte_cycles.h
diff --git a/lib/librte_eal/common/include/generic/rte_io.h b/lib/librte_eal/include/generic/rte_io.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_io.h
rename to lib/librte_eal/include/generic/rte_io.h
diff --git a/lib/librte_eal/common/include/generic/rte_mcslock.h b/lib/librte_eal/include/generic/rte_mcslock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_mcslock.h
rename to lib/librte_eal/include/generic/rte_mcslock.h
diff --git a/lib/librte_eal/common/include/generic/rte_memcpy.h b/lib/librte_eal/include/generic/rte_memcpy.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_memcpy.h
rename to lib/librte_eal/include/generic/rte_memcpy.h
diff --git a/lib/librte_eal/common/include/generic/rte_pause.h b/lib/librte_eal/include/generic/rte_pause.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_pause.h
rename to lib/librte_eal/include/generic/rte_pause.h
diff --git a/lib/librte_eal/common/include/generic/rte_prefetch.h b/lib/librte_eal/include/generic/rte_prefetch.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_prefetch.h
rename to lib/librte_eal/include/generic/rte_prefetch.h
diff --git a/lib/librte_eal/common/include/generic/rte_rwlock.h b/lib/librte_eal/include/generic/rte_rwlock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_rwlock.h
rename to lib/librte_eal/include/generic/rte_rwlock.h
diff --git a/lib/librte_eal/common/include/generic/rte_spinlock.h b/lib/librte_eal/include/generic/rte_spinlock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_spinlock.h
rename to lib/librte_eal/include/generic/rte_spinlock.h
diff --git a/lib/librte_eal/common/include/generic/rte_ticketlock.h b/lib/librte_eal/include/generic/rte_ticketlock.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_ticketlock.h
rename to lib/librte_eal/include/generic/rte_ticketlock.h
diff --git a/lib/librte_eal/common/include/generic/rte_vect.h b/lib/librte_eal/include/generic/rte_vect.h
similarity index 100%
rename from lib/librte_eal/common/include/generic/rte_vect.h
rename to lib/librte_eal/include/generic/rte_vect.h
diff --git a/lib/librte_eal/common/include/rte_alarm.h b/lib/librte_eal/include/rte_alarm.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_alarm.h
rename to lib/librte_eal/include/rte_alarm.h
diff --git a/lib/librte_eal/common/include/rte_bitmap.h b/lib/librte_eal/include/rte_bitmap.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_bitmap.h
rename to lib/librte_eal/include/rte_bitmap.h
diff --git a/lib/librte_eal/common/include/rte_branch_prediction.h b/lib/librte_eal/include/rte_branch_prediction.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_branch_prediction.h
rename to lib/librte_eal/include/rte_branch_prediction.h
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/include/rte_bus.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_bus.h
rename to lib/librte_eal/include/rte_bus.h
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/include/rte_class.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_class.h
rename to lib/librte_eal/include/rte_class.h
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/include/rte_common.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_common.h
rename to lib/librte_eal/include/rte_common.h
diff --git a/lib/librte_eal/common/include/rte_compat.h b/lib/librte_eal/include/rte_compat.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_compat.h
rename to lib/librte_eal/include/rte_compat.h
diff --git a/lib/librte_eal/common/include/rte_debug.h b/lib/librte_eal/include/rte_debug.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_debug.h
rename to lib/librte_eal/include/rte_debug.h
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/include/rte_dev.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_dev.h
rename to lib/librte_eal/include/rte_dev.h
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/include/rte_devargs.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_devargs.h
rename to lib/librte_eal/include/rte_devargs.h
diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/include/rte_eal.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_eal.h
rename to lib/librte_eal/include/rte_eal.h
diff --git a/lib/librte_eal/common/include/rte_eal_interrupts.h b/lib/librte_eal/include/rte_eal_interrupts.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_eal_interrupts.h
rename to lib/librte_eal/include/rte_eal_interrupts.h
diff --git a/lib/librte_eal/common/include/rte_eal_memconfig.h b/lib/librte_eal/include/rte_eal_memconfig.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_eal_memconfig.h
rename to lib/librte_eal/include/rte_eal_memconfig.h
diff --git a/lib/librte_eal/common/include/rte_errno.h b/lib/librte_eal/include/rte_errno.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_errno.h
rename to lib/librte_eal/include/rte_errno.h
diff --git a/lib/librte_eal/common/include/rte_fbarray.h b/lib/librte_eal/include/rte_fbarray.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_fbarray.h
rename to lib/librte_eal/include/rte_fbarray.h
diff --git a/lib/librte_eal/common/include/rte_function_versioning.h b/lib/librte_eal/include/rte_function_versioning.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_function_versioning.h
rename to lib/librte_eal/include/rte_function_versioning.h
diff --git a/lib/librte_eal/common/include/rte_hexdump.h b/lib/librte_eal/include/rte_hexdump.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_hexdump.h
rename to lib/librte_eal/include/rte_hexdump.h
diff --git a/lib/librte_eal/common/include/rte_hypervisor.h b/lib/librte_eal/include/rte_hypervisor.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_hypervisor.h
rename to lib/librte_eal/include/rte_hypervisor.h
diff --git a/lib/librte_eal/common/include/rte_interrupts.h b/lib/librte_eal/include/rte_interrupts.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_interrupts.h
rename to lib/librte_eal/include/rte_interrupts.h
diff --git a/lib/librte_eal/common/include/rte_keepalive.h b/lib/librte_eal/include/rte_keepalive.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_keepalive.h
rename to lib/librte_eal/include/rte_keepalive.h
diff --git a/lib/librte_eal/common/include/rte_launch.h b/lib/librte_eal/include/rte_launch.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_launch.h
rename to lib/librte_eal/include/rte_launch.h
diff --git a/lib/librte_eal/common/include/rte_lcore.h b/lib/librte_eal/include/rte_lcore.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_lcore.h
rename to lib/librte_eal/include/rte_lcore.h
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/include/rte_log.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_log.h
rename to lib/librte_eal/include/rte_log.h
diff --git a/lib/librte_eal/common/include/rte_malloc.h b/lib/librte_eal/include/rte_malloc.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_malloc.h
rename to lib/librte_eal/include/rte_malloc.h
diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/include/rte_memory.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_memory.h
rename to lib/librte_eal/include/rte_memory.h
diff --git a/lib/librte_eal/common/include/rte_memzone.h b/lib/librte_eal/include/rte_memzone.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_memzone.h
rename to lib/librte_eal/include/rte_memzone.h
diff --git a/lib/librte_eal/common/include/rte_option.h b/lib/librte_eal/include/rte_option.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_option.h
rename to lib/librte_eal/include/rte_option.h
diff --git a/lib/librte_eal/common/include/rte_pci_dev_feature_defs.h b/lib/librte_eal/include/rte_pci_dev_feature_defs.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_pci_dev_feature_defs.h
rename to lib/librte_eal/include/rte_pci_dev_feature_defs.h
diff --git a/lib/librte_eal/common/include/rte_pci_dev_features.h b/lib/librte_eal/include/rte_pci_dev_features.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_pci_dev_features.h
rename to lib/librte_eal/include/rte_pci_dev_features.h
diff --git a/lib/librte_eal/common/include/rte_per_lcore.h b/lib/librte_eal/include/rte_per_lcore.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_per_lcore.h
rename to lib/librte_eal/include/rte_per_lcore.h
diff --git a/lib/librte_eal/common/include/rte_random.h b/lib/librte_eal/include/rte_random.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_random.h
rename to lib/librte_eal/include/rte_random.h
diff --git a/lib/librte_eal/common/include/rte_reciprocal.h b/lib/librte_eal/include/rte_reciprocal.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_reciprocal.h
rename to lib/librte_eal/include/rte_reciprocal.h
diff --git a/lib/librte_eal/common/include/rte_service.h b/lib/librte_eal/include/rte_service.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_service.h
rename to lib/librte_eal/include/rte_service.h
diff --git a/lib/librte_eal/common/include/rte_service_component.h b/lib/librte_eal/include/rte_service_component.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_service_component.h
rename to lib/librte_eal/include/rte_service_component.h
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_eal/include/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_eal/include/rte_string_fns.h
diff --git a/lib/librte_eal/common/include/rte_tailq.h b/lib/librte_eal/include/rte_tailq.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_tailq.h
rename to lib/librte_eal/include/rte_tailq.h
diff --git a/lib/librte_eal/common/include/rte_test.h b/lib/librte_eal/include/rte_test.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_test.h
rename to lib/librte_eal/include/rte_test.h
diff --git a/lib/librte_eal/common/include/rte_time.h b/lib/librte_eal/include/rte_time.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_time.h
rename to lib/librte_eal/include/rte_time.h
diff --git a/lib/librte_eal/common/include/rte_uuid.h b/lib/librte_eal/include/rte_uuid.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_uuid.h
rename to lib/librte_eal/include/rte_uuid.h
diff --git a/lib/librte_eal/common/include/rte_version.h b/lib/librte_eal/include/rte_version.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_version.h
rename to lib/librte_eal/include/rte_version.h
diff --git a/lib/librte_eal/common/include/rte_vfio.h b/lib/librte_eal/include/rte_vfio.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_vfio.h
rename to lib/librte_eal/include/rte_vfio.h
diff --git a/lib/librte_eal/linux/Makefile b/lib/librte_eal/linux/Makefile
index 4c68bd61b8..0ed4dc3e10 100644
--- a/lib/librte_eal/linux/Makefile
+++ b/lib/librte_eal/linux/Makefile
@@ -1,11 +1,99 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2010-2019 Intel Corporation
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal
-DEPDIRS-kni := eal
+LIB = librte_eal.a
+
+ARCH_DIR ?= $(RTE_ARCH)
+VPATH += $(RTE_SDK)/lib/librte_eal/$(ARCH_DIR)
+VPATH += $(RTE_SDK)/lib/librte_eal/common
 
 CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(SRCDIR)/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
+CFLAGS += $(WERROR_FLAGS) -O3
 
-include $(RTE_SDK)/mk/rte.subdir.mk
+LDLIBS += -ldl
+LDLIBS += -lpthread
+LDLIBS += -lgcc_s
+LDLIBS += -lrt
+LDLIBS += -lrte_kvargs
+ifeq ($(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),y)
+LDLIBS += -lnuma
+endif
+
+EXPORT_MAP := ../rte_eal_version.map
+
+# specific to linux exec-env
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) := eal.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_cpuflags.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_hugepage_info.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_memory.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_thread.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_log.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_vfio.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_vfio_mp_sync.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_memalloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_debug.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_lcore.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_timer.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_interrupts.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_alarm.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_dev.c
+
+# from common dir
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_lcore.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_timer.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_memzone.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_log.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_launch.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_mcfg.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_memalloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_memory.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_tailqs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_errno.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_cpuflags.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_hypervisor.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_string_fns.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_hexdump.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_class.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_bus.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_dev.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_options.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_thread.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_proc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_fbarray.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_uuid.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_malloc.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += hotplug_mp.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += malloc_elem.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += malloc_heap.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += malloc_mp.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_keepalive.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_option.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_service.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_random.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_reciprocal.c
+
+# from arch dir
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_cpuflags.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_hypervisor.c
+SRCS-$(CONFIG_RTE_ARCH_X86) += rte_spinlock.c
+SRCS-y += rte_cycles.c
+
+CFLAGS_eal_common_cpuflags.o := $(CPUFLAGS_LIST)
+
+# workaround for a gcc bug with noreturn attribute
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+CFLAGS_eal_thread.o += -Wno-return-type
+endif
+
+INC := rte_kni_common.h
+INC += rte_os.h
+
+SYMLINK-$(CONFIG_RTE_EXEC_ENV_LINUX)-include := $(addprefix include/,$(INC))
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_eal/linux/eal/eal.c b/lib/librte_eal/linux/eal.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal.c
rename to lib/librte_eal/linux/eal.c
diff --git a/lib/librte_eal/linux/eal/Makefile b/lib/librte_eal/linux/eal/Makefile
deleted file mode 100644
index e70cf104a4..0000000000
--- a/lib/librte_eal/linux/eal/Makefile
+++ /dev/null
@@ -1,101 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2019 Intel Corporation
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-LIB = librte_eal.a
-
-ARCH_DIR ?= $(RTE_ARCH)
-
-EXPORT_MAP := ../../rte_eal_version.map
-VPATH += $(RTE_SDK)/lib/librte_eal/common/arch/$(ARCH_DIR)
-
-VPATH += $(RTE_SDK)/lib/librte_eal/common
-
-CFLAGS += -DALLOW_EXPERIMENTAL_API
-CFLAGS += -I$(SRCDIR)/include
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
-CFLAGS += $(WERROR_FLAGS) -O3
-
-LDLIBS += -ldl
-LDLIBS += -lpthread
-LDLIBS += -lgcc_s
-LDLIBS += -lrt
-LDLIBS += -lrte_kvargs
-ifeq ($(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),y)
-LDLIBS += -lnuma
-endif
-
-# specific to linux exec-env
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) := eal.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_cpuflags.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_hugepage_info.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_memory.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_thread.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_log.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_vfio.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_vfio_mp_sync.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_memalloc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_debug.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_lcore.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_timer.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_interrupts.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_alarm.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_dev.c
-
-# from common dir
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_lcore.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_timer.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_memzone.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_log.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_launch.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_mcfg.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_memalloc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_memory.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_tailqs.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_errno.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_cpuflags.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_hypervisor.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_string_fns.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_hexdump.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_devargs.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_class.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_bus.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_dev.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_options.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_thread.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_proc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_fbarray.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += eal_common_uuid.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_malloc.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += hotplug_mp.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += malloc_elem.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += malloc_heap.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += malloc_mp.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_keepalive.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_option.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_service.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_random.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_reciprocal.c
-
-# from arch dir
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_cpuflags.c
-SRCS-$(CONFIG_RTE_EXEC_ENV_LINUX) += rte_hypervisor.c
-SRCS-$(CONFIG_RTE_ARCH_X86) += rte_spinlock.c
-SRCS-y += rte_cycles.c
-
-CFLAGS_eal_common_cpuflags.o := $(CPUFLAGS_LIST)
-
-# workaround for a gcc bug with noreturn attribute
-# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
-ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
-CFLAGS_eal_thread.o += -Wno-return-type
-endif
-
-INC := rte_kni_common.h
-INC += rte_os.h
-
-SYMLINK-$(CONFIG_RTE_EXEC_ENV_LINUX)-include := $(addprefix include/,$(INC))
-
-include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_eal/linux/eal/eal_alarm.c b/lib/librte_eal/linux/eal_alarm.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_alarm.c
rename to lib/librte_eal/linux/eal_alarm.c
diff --git a/lib/librte_eal/linux/eal/eal_cpuflags.c b/lib/librte_eal/linux/eal_cpuflags.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_cpuflags.c
rename to lib/librte_eal/linux/eal_cpuflags.c
diff --git a/lib/librte_eal/linux/eal/eal_debug.c b/lib/librte_eal/linux/eal_debug.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_debug.c
rename to lib/librte_eal/linux/eal_debug.c
diff --git a/lib/librte_eal/linux/eal/eal_dev.c b/lib/librte_eal/linux/eal_dev.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_dev.c
rename to lib/librte_eal/linux/eal_dev.c
diff --git a/lib/librte_eal/linux/eal/eal_hugepage_info.c b/lib/librte_eal/linux/eal_hugepage_info.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_hugepage_info.c
rename to lib/librte_eal/linux/eal_hugepage_info.c
diff --git a/lib/librte_eal/linux/eal/eal_interrupts.c b/lib/librte_eal/linux/eal_interrupts.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_interrupts.c
rename to lib/librte_eal/linux/eal_interrupts.c
diff --git a/lib/librte_eal/linux/eal/eal_lcore.c b/lib/librte_eal/linux/eal_lcore.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_lcore.c
rename to lib/librte_eal/linux/eal_lcore.c
diff --git a/lib/librte_eal/linux/eal/eal_log.c b/lib/librte_eal/linux/eal_log.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_log.c
rename to lib/librte_eal/linux/eal_log.c
diff --git a/lib/librte_eal/linux/eal/eal_memalloc.c b/lib/librte_eal/linux/eal_memalloc.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_memalloc.c
rename to lib/librte_eal/linux/eal_memalloc.c
diff --git a/lib/librte_eal/linux/eal/eal_memory.c b/lib/librte_eal/linux/eal_memory.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_memory.c
rename to lib/librte_eal/linux/eal_memory.c
diff --git a/lib/librte_eal/linux/eal/eal_thread.c b/lib/librte_eal/linux/eal_thread.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_thread.c
rename to lib/librte_eal/linux/eal_thread.c
diff --git a/lib/librte_eal/linux/eal/eal_timer.c b/lib/librte_eal/linux/eal_timer.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_timer.c
rename to lib/librte_eal/linux/eal_timer.c
diff --git a/lib/librte_eal/linux/eal/eal_vfio.c b/lib/librte_eal/linux/eal_vfio.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_vfio.c
rename to lib/librte_eal/linux/eal_vfio.c
diff --git a/lib/librte_eal/linux/eal/eal_vfio.h b/lib/librte_eal/linux/eal_vfio.h
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_vfio.h
rename to lib/librte_eal/linux/eal_vfio.h
diff --git a/lib/librte_eal/linux/eal/eal_vfio_mp_sync.c b/lib/librte_eal/linux/eal_vfio_mp_sync.c
similarity index 100%
rename from lib/librte_eal/linux/eal/eal_vfio_mp_sync.c
rename to lib/librte_eal/linux/eal_vfio_mp_sync.c
diff --git a/lib/librte_eal/linux/eal/include/rte_kni_common.h b/lib/librte_eal/linux/include/rte_kni_common.h
similarity index 100%
rename from lib/librte_eal/linux/eal/include/rte_kni_common.h
rename to lib/librte_eal/linux/include/rte_kni_common.h
diff --git a/lib/librte_eal/linux/eal/include/rte_os.h b/lib/librte_eal/linux/include/rte_os.h
similarity index 100%
rename from lib/librte_eal/linux/eal/include/rte_os.h
rename to lib/librte_eal/linux/include/rte_os.h
diff --git a/lib/librte_eal/linux/eal/meson.build b/lib/librte_eal/linux/meson.build
similarity index 81%
rename from lib/librte_eal/linux/eal/meson.build
rename to lib/librte_eal/linux/meson.build
index b02b0695f5..209dd7c642 100644
--- a/lib/librte_eal/linux/eal/meson.build
+++ b/lib/librte_eal/linux/meson.build
@@ -1,14 +1,15 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-eal_inc += include_directories('include')
+includes += include_directories('include')
 
-env_objs = []
-env_headers = files(
+headers += files(
 		'include/rte_kni_common.h',
 		'include/rte_os.h',
 )
-env_sources = files('eal_alarm.c',
+
+sources += files(
+		'eal_alarm.c',
 		'eal_cpuflags.c',
 		'eal_debug.c',
 		'eal_hugepage_info.c',
diff --git a/lib/librte_eal/meson.build b/lib/librte_eal/meson.build
index 1730d603fc..516ef09a49 100644
--- a/lib/librte_eal/meson.build
+++ b/lib/librte_eal/meson.build
@@ -1,16 +1,16 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017-2019 Intel Corporation
 
-# Custom EAL processing. EAL is complicated enough that it can't just
-# have a straight list of headers and source files.
-# Initially pull in common settings
-eal_inc = [global_inc]
-subdir('common') # defines common_sources, common_objs, etc.
+includes += global_inc
+
+subdir('include')
+
+subdir('common')
 
-# Now do OS/exec-env specific settings, including building kernel modules
-# The <exec-env>/eal/meson.build file should define env_sources, etc.
 dpdk_conf.set('RTE_EXEC_ENV_' + exec_env.to_upper(), 1)
-subdir(exec_env + '/eal')
+subdir(exec_env)
+
+subdir(arch_subdir)
 
 allow_experimental_apis = true
 deps += 'kvargs'
@@ -23,7 +23,3 @@ endif
 if cc.has_header('getopt.h')
 	cflags += ['-DHAVE_GETOPT_H', '-DHAVE_GETOPT', '-DHAVE_GETOPT_LONG']
 endif
-sources = common_sources + env_sources
-objs = common_objs + env_objs
-headers = common_headers + env_headers
-includes = eal_inc
diff --git a/lib/librte_eal/common/include/arch/ppc_64/meson.build b/lib/librte_eal/ppc/include/meson.build
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/meson.build
rename to lib/librte_eal/ppc/include/meson.build
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_atomic.h b/lib/librte_eal/ppc/include/rte_atomic.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_atomic.h
rename to lib/librte_eal/ppc/include/rte_atomic.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_byteorder.h b/lib/librte_eal/ppc/include/rte_byteorder.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_byteorder.h
rename to lib/librte_eal/ppc/include/rte_byteorder.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_cpuflags.h b/lib/librte_eal/ppc/include/rte_cpuflags.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_cpuflags.h
rename to lib/librte_eal/ppc/include/rte_cpuflags.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_cycles.h b/lib/librte_eal/ppc/include/rte_cycles.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_cycles.h
rename to lib/librte_eal/ppc/include/rte_cycles.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_io.h b/lib/librte_eal/ppc/include/rte_io.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_io.h
rename to lib/librte_eal/ppc/include/rte_io.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_mcslock.h b/lib/librte_eal/ppc/include/rte_mcslock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_mcslock.h
rename to lib/librte_eal/ppc/include/rte_mcslock.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_memcpy.h b/lib/librte_eal/ppc/include/rte_memcpy.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_memcpy.h
rename to lib/librte_eal/ppc/include/rte_memcpy.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_pause.h b/lib/librte_eal/ppc/include/rte_pause.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_pause.h
rename to lib/librte_eal/ppc/include/rte_pause.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_prefetch.h b/lib/librte_eal/ppc/include/rte_prefetch.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_prefetch.h
rename to lib/librte_eal/ppc/include/rte_prefetch.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_rwlock.h b/lib/librte_eal/ppc/include/rte_rwlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_rwlock.h
rename to lib/librte_eal/ppc/include/rte_rwlock.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_spinlock.h b/lib/librte_eal/ppc/include/rte_spinlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_spinlock.h
rename to lib/librte_eal/ppc/include/rte_spinlock.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_ticketlock.h b/lib/librte_eal/ppc/include/rte_ticketlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_ticketlock.h
rename to lib/librte_eal/ppc/include/rte_ticketlock.h
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_vect.h b/lib/librte_eal/ppc/include/rte_vect.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/ppc_64/rte_vect.h
rename to lib/librte_eal/ppc/include/rte_vect.h
diff --git a/lib/librte_eal/ppc/meson.build b/lib/librte_eal/ppc/meson.build
new file mode 100644
index 0000000000..0f72bd3a36
--- /dev/null
+++ b/lib/librte_eal/ppc/meson.build
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Luca Boccassi <bluca@debian.org>
+
+includes += include_directories('include')
+
+headers += files(
+)
+
+sources += files(
+	'rte_cpuflags.c',
+	'rte_cycles.c',
+	'rte_hypervisor.c',
+)
diff --git a/lib/librte_eal/common/arch/ppc_64/rte_cpuflags.c b/lib/librte_eal/ppc/rte_cpuflags.c
similarity index 100%
rename from lib/librte_eal/common/arch/ppc_64/rte_cpuflags.c
rename to lib/librte_eal/ppc/rte_cpuflags.c
diff --git a/lib/librte_eal/common/arch/ppc_64/rte_cycles.c b/lib/librte_eal/ppc/rte_cycles.c
similarity index 100%
rename from lib/librte_eal/common/arch/ppc_64/rte_cycles.c
rename to lib/librte_eal/ppc/rte_cycles.c
diff --git a/lib/librte_eal/common/arch/ppc_64/rte_hypervisor.c b/lib/librte_eal/ppc/rte_hypervisor.c
similarity index 100%
rename from lib/librte_eal/common/arch/ppc_64/rte_hypervisor.c
rename to lib/librte_eal/ppc/rte_hypervisor.c
diff --git a/lib/librte_eal/windows/eal/eal.c b/lib/librte_eal/windows/eal.c
similarity index 100%
rename from lib/librte_eal/windows/eal/eal.c
rename to lib/librte_eal/windows/eal.c
diff --git a/lib/librte_eal/windows/eal/meson.build b/lib/librte_eal/windows/eal/meson.build
deleted file mode 100644
index 2a062c365e..0000000000
--- a/lib/librte_eal/windows/eal/meson.build
+++ /dev/null
@@ -1,27 +0,0 @@
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2019 Intel Corporation
-
-eal_inc += include_directories('include')
-
-env_objs = []
-env_headers = files(
-	'include/rte_os.h',
-)
-common_sources = files(
-	'../../common/eal_common_bus.c',
-	'../../common/eal_common_class.c',
-	'../../common/eal_common_devargs.c',
-	'../../common/eal_common_errno.c',
-	'../../common/eal_common_launch.c',
-	'../../common/eal_common_lcore.c',
-	'../../common/eal_common_log.c',
-	'../../common/eal_common_options.c',
-	'../../common/eal_common_thread.c',
-	'../../common/rte_option.c',
-)
-env_sources = files('eal.c',
-	'eal_debug.c',
-	'eal_lcore.c',
-	'eal_thread.c',
-	'getopt.c',
-)
diff --git a/lib/librte_eal/windows/eal/eal_debug.c b/lib/librte_eal/windows/eal_debug.c
similarity index 100%
rename from lib/librte_eal/windows/eal/eal_debug.c
rename to lib/librte_eal/windows/eal_debug.c
diff --git a/lib/librte_eal/windows/eal/eal_lcore.c b/lib/librte_eal/windows/eal_lcore.c
similarity index 100%
rename from lib/librte_eal/windows/eal/eal_lcore.c
rename to lib/librte_eal/windows/eal_lcore.c
diff --git a/lib/librte_eal/windows/eal/eal_thread.c b/lib/librte_eal/windows/eal_thread.c
similarity index 100%
rename from lib/librte_eal/windows/eal/eal_thread.c
rename to lib/librte_eal/windows/eal_thread.c
diff --git a/lib/librte_eal/windows/eal/getopt.c b/lib/librte_eal/windows/getopt.c
similarity index 100%
rename from lib/librte_eal/windows/eal/getopt.c
rename to lib/librte_eal/windows/getopt.c
diff --git a/lib/librte_eal/windows/eal/include/dirent.h b/lib/librte_eal/windows/include/dirent.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/dirent.h
rename to lib/librte_eal/windows/include/dirent.h
diff --git a/lib/librte_eal/windows/eal/include/fnmatch.h b/lib/librte_eal/windows/include/fnmatch.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/fnmatch.h
rename to lib/librte_eal/windows/include/fnmatch.h
diff --git a/lib/librte_eal/windows/eal/include/getopt.h b/lib/librte_eal/windows/include/getopt.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/getopt.h
rename to lib/librte_eal/windows/include/getopt.h
diff --git a/lib/librte_eal/windows/eal/include/pthread.h b/lib/librte_eal/windows/include/pthread.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/pthread.h
rename to lib/librte_eal/windows/include/pthread.h
diff --git a/lib/librte_eal/windows/eal/include/regex.h b/lib/librte_eal/windows/include/regex.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/regex.h
rename to lib/librte_eal/windows/include/regex.h
diff --git a/lib/librte_eal/windows/eal/include/rte_os.h b/lib/librte_eal/windows/include/rte_os.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/rte_os.h
rename to lib/librte_eal/windows/include/rte_os.h
diff --git a/lib/librte_eal/windows/eal/include/sched.h b/lib/librte_eal/windows/include/sched.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/sched.h
rename to lib/librte_eal/windows/include/sched.h
diff --git a/lib/librte_eal/windows/eal/include/sys/queue.h b/lib/librte_eal/windows/include/sys/queue.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/sys/queue.h
rename to lib/librte_eal/windows/include/sys/queue.h
diff --git a/lib/librte_eal/windows/eal/include/unistd.h b/lib/librte_eal/windows/include/unistd.h
similarity index 100%
rename from lib/librte_eal/windows/eal/include/unistd.h
rename to lib/librte_eal/windows/include/unistd.h
diff --git a/lib/librte_eal/windows/meson.build b/lib/librte_eal/windows/meson.build
new file mode 100644
index 0000000000..5fcaf4785a
--- /dev/null
+++ b/lib/librte_eal/windows/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Intel Corporation
+
+includes += include_directories('include')
+
+headers += files(
+	'include/rte_os.h',
+)
+
+sources += files(
+	'eal.c',
+	'eal_debug.c',
+	'eal_lcore.c',
+	'eal_thread.c',
+	'getopt.c',
+)
diff --git a/lib/librte_eal/common/include/arch/x86/meson.build b/lib/librte_eal/x86/include/meson.build
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/meson.build
rename to lib/librte_eal/x86/include/meson.build
diff --git a/lib/librte_eal/common/include/arch/x86/rte_atomic.h b/lib/librte_eal/x86/include/rte_atomic.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_atomic.h
rename to lib/librte_eal/x86/include/rte_atomic.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_atomic_32.h b/lib/librte_eal/x86/include/rte_atomic_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_atomic_32.h
rename to lib/librte_eal/x86/include/rte_atomic_32.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_atomic_64.h b/lib/librte_eal/x86/include/rte_atomic_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_atomic_64.h
rename to lib/librte_eal/x86/include/rte_atomic_64.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_byteorder.h b/lib/librte_eal/x86/include/rte_byteorder.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_byteorder.h
rename to lib/librte_eal/x86/include/rte_byteorder.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_byteorder_32.h b/lib/librte_eal/x86/include/rte_byteorder_32.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_byteorder_32.h
rename to lib/librte_eal/x86/include/rte_byteorder_32.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_byteorder_64.h b/lib/librte_eal/x86/include/rte_byteorder_64.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_byteorder_64.h
rename to lib/librte_eal/x86/include/rte_byteorder_64.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_cpuflags.h b/lib/librte_eal/x86/include/rte_cpuflags.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_cpuflags.h
rename to lib/librte_eal/x86/include/rte_cpuflags.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_cycles.h b/lib/librte_eal/x86/include/rte_cycles.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_cycles.h
rename to lib/librte_eal/x86/include/rte_cycles.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_io.h b/lib/librte_eal/x86/include/rte_io.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_io.h
rename to lib/librte_eal/x86/include/rte_io.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_mcslock.h b/lib/librte_eal/x86/include/rte_mcslock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_mcslock.h
rename to lib/librte_eal/x86/include/rte_mcslock.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_memcpy.h b/lib/librte_eal/x86/include/rte_memcpy.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_memcpy.h
rename to lib/librte_eal/x86/include/rte_memcpy.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_pause.h b/lib/librte_eal/x86/include/rte_pause.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_pause.h
rename to lib/librte_eal/x86/include/rte_pause.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_prefetch.h b/lib/librte_eal/x86/include/rte_prefetch.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_prefetch.h
rename to lib/librte_eal/x86/include/rte_prefetch.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_rtm.h b/lib/librte_eal/x86/include/rte_rtm.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_rtm.h
rename to lib/librte_eal/x86/include/rte_rtm.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_rwlock.h b/lib/librte_eal/x86/include/rte_rwlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_rwlock.h
rename to lib/librte_eal/x86/include/rte_rwlock.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_spinlock.h b/lib/librte_eal/x86/include/rte_spinlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_spinlock.h
rename to lib/librte_eal/x86/include/rte_spinlock.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_ticketlock.h b/lib/librte_eal/x86/include/rte_ticketlock.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_ticketlock.h
rename to lib/librte_eal/x86/include/rte_ticketlock.h
diff --git a/lib/librte_eal/common/include/arch/x86/rte_vect.h b/lib/librte_eal/x86/include/rte_vect.h
similarity index 100%
rename from lib/librte_eal/common/include/arch/x86/rte_vect.h
rename to lib/librte_eal/x86/include/rte_vect.h
diff --git a/lib/librte_eal/x86/meson.build b/lib/librte_eal/x86/meson.build
new file mode 100644
index 0000000000..305d16c01b
--- /dev/null
+++ b/lib/librte_eal/x86/meson.build
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+includes += include_directories('include')
+
+headers += files(
+)
+
+sources += files(
+	'rte_cpuflags.c',
+	'rte_cycles.c',
+	'rte_hypervisor.c',
+	'rte_spinlock.c',
+)
diff --git a/lib/librte_eal/common/arch/x86/rte_cpuflags.c b/lib/librte_eal/x86/rte_cpuflags.c
similarity index 100%
rename from lib/librte_eal/common/arch/x86/rte_cpuflags.c
rename to lib/librte_eal/x86/rte_cpuflags.c
diff --git a/lib/librte_eal/common/arch/x86/rte_cpuid.h b/lib/librte_eal/x86/rte_cpuid.h
similarity index 100%
rename from lib/librte_eal/common/arch/x86/rte_cpuid.h
rename to lib/librte_eal/x86/rte_cpuid.h
diff --git a/lib/librte_eal/common/arch/x86/rte_cycles.c b/lib/librte_eal/x86/rte_cycles.c
similarity index 100%
rename from lib/librte_eal/common/arch/x86/rte_cycles.c
rename to lib/librte_eal/x86/rte_cycles.c
diff --git a/lib/librte_eal/common/arch/x86/rte_hypervisor.c b/lib/librte_eal/x86/rte_hypervisor.c
similarity index 100%
rename from lib/librte_eal/common/arch/x86/rte_hypervisor.c
rename to lib/librte_eal/x86/rte_hypervisor.c
diff --git a/lib/librte_eal/common/arch/x86/rte_spinlock.c b/lib/librte_eal/x86/rte_spinlock.c
similarity index 100%
rename from lib/librte_eal/common/arch/x86/rte_spinlock.c
rename to lib/librte_eal/x86/rte_spinlock.c
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 419be8bd7c..24b1c3c5b9 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -7,7 +7,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
diff --git a/license/exceptions.txt b/license/exceptions.txt
index 1e21a863f1..c984764a02 100644
--- a/license/exceptions.txt
+++ b/license/exceptions.txt
@@ -12,9 +12,9 @@ Note that following licenses are not exceptions:-
 ---------------------------------------------------------------------------------------------------
 SPDX Identifier     TB Approval Date  GB Approval Date  File name
 ---------------------------------------------------------------------------------------------------
-1.MIT               10/23/2019        02/10/2020        lib/librte_eal/windows/eal/include/dirent.h
-2.BSD-2-Clause      10/23/2019        12/18/2019        lib/librte_eal/windows/eal/include/getopt.h
+1.MIT               10/23/2019        02/10/2020        lib/librte_eal/windows/include/dirent.h
+2.BSD-2-Clause      10/23/2019        12/18/2019        lib/librte_eal/windows/include/getopt.h
 3.ISC AND
-  BSD-2-Clause      10/23/2019        12/18/2019        lib/librte_eal/windows/eal/getopt.c
+  BSD-2-Clause      10/23/2019        12/18/2019        lib/librte_eal/windows/getopt.c
 4.GPL-2.0           09/25/2019        12/18/2019        buildtools/pmdinfogen/pmdinfogen.*
 ---------------------------------------------------------------------------------------------------
diff --git a/meson.build b/meson.build
index b7ae9c8d9a..d36580438e 100644
--- a/meson.build
+++ b/meson.build
@@ -28,8 +28,8 @@ abi_version_file = files('ABI_VERSION')
 # able to be included in any file. We also store a global array of include dirs
 # for passing to pmdinfogen scripts
 global_inc = include_directories('.', 'config',
-	'lib/librte_eal/common/include',
-	'lib/librte_eal/@0@/eal/include'.format(host_machine.system()),
+	'lib/librte_eal/include',
+	'lib/librte_eal/@0@/include'.format(host_machine.system()),
 )
 subdir('config')
 
diff --git a/mk/exec-env/freebsd/rte.vars.mk b/mk/exec-env/freebsd/rte.vars.mk
index 3608530d3f..630eb55f73 100644
--- a/mk/exec-env/freebsd/rte.vars.mk
+++ b/mk/exec-env/freebsd/rte.vars.mk
@@ -18,7 +18,7 @@ EXECENV_CFLAGS  = -pthread
 endif
 
 # include in every library to build
-EXECENV_CFLAGS += -I$(RTE_SDK)/lib/librte_eal/freebsd/eal/include
+EXECENV_CFLAGS += -I$(RTE_SDK)/lib/librte_eal/freebsd/include
 
 EXECENV_LDFLAGS =
 EXECENV_LDLIBS  = -lexecinfo
diff --git a/mk/exec-env/linux/rte.vars.mk b/mk/exec-env/linux/rte.vars.mk
index bea3f76577..41ef4195b0 100644
--- a/mk/exec-env/linux/rte.vars.mk
+++ b/mk/exec-env/linux/rte.vars.mk
@@ -18,7 +18,7 @@ EXECENV_CFLAGS  = -pthread
 endif
 
 # include in every library to build
-EXECENV_CFLAGS += -I$(RTE_SDK)/lib/librte_eal/linux/eal/include
+EXECENV_CFLAGS += -I$(RTE_SDK)/lib/librte_eal/linux/include
 
 EXECENV_LDLIBS  =
 EXECENV_ASFLAGS =
-- 
2.25.1


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [EXT] Re: [PATCH] devtools: fix check symbol change script
  2020-03-19 15:45  0%     ` [dpdk-dev] [EXT] " Nithin Dabilpuram
@ 2020-03-19 18:59  0%       ` Neil Horman
  0 siblings, 0 replies; 200+ results
From: Neil Horman @ 2020-03-19 18:59 UTC (permalink / raw)
  To: Nithin Dabilpuram
  Cc: David Marchand, Thomas Monjalon, dev, Jerin Jacob Kollanukkaran,
	dpdk stable, bingz

On Thu, Mar 19, 2020 at 09:15:50PM +0530, Nithin Dabilpuram wrote:
> On Thu, Mar 19, 2020 at 11:40:39AM -0400, Neil Horman wrote:
> > External Email
> > 
> > ----------------------------------------------------------------------
> > On Thu, Mar 19, 2020 at 03:56:03PM +0100, David Marchand wrote:
> > > On Thu, Mar 19, 2020 at 3:44 PM Nithin Dabilpuram
> > > <ndabilpuram@marvell.com> wrote:
> > > >
> > > > Fix check symbol change script to detect new diff file when
> > > > it is in between  "--- /dev/null" to "b/lib/...".
> > > > Current awk line expects line to start with "a/..."
> > > > which is not always true for all diffs.
> > > > As a result if in_map was '1' earlier, it will not be changed
> > > > to '0' and we get check patch errors which are not true as the non
> > > > version.map files get interpreted as version map file.
> > > >
> > > > Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
> > > > Cc: nhorman@tuxdriver.com
> > > > Cc: stable@dpdk.org
> > > 
> > > There was a previous attempt at fixing this that did not get a review.
> > > https://urldefense.proofpoint.com/v2/url?u=http-3A__patchwork.dpdk.org_patch_56303_&d=DwIBAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=FZ_tPCbgFOh18zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=HnuykZkNgy_2cx1i0_QuR-C_vdVYLTJ9rSUA1dCM7WI&s=TW-ZZ_dYy8x6EcvJHtYrv9vaIHSmd0GshvClMwiWPi4&e= 
> > > 
> > > I prefer the last submitted patch as it is simpler, but maybe I missed
> > > something in Bing patch.
> > > 
> > > Neil, wdyt?
> > > 
> > I'm not sure why I didn't review the previous patch you refrenced, apologies for
> > that.
> > 
> > That said, I'm not sure how this patch detects /dev/null patterns. It looks like
> > you still expect all lines to start with [+-] [ab]...
> 
> It doesn't detect /dev/null but the line following /dev/null will start with
> "b/...". So this checks for .map in that line as well.
> 
Ah, in that case, I'd really be fine with either fix.

Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > 
> > Neil
> > 
> > > 
> > > -- 
> > > David Marchand
> > > 
> > > 
> > > >
> > > > Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
> > > > ---
> > > > Note: We have two examples where checkpatch errors are because of this
> > > > because the version.map file change comes earlier in the diff. Because of
> > > > this bug, any new file change that comes after version.map file diff
> > > > as "/dev/null" to "b/.." gets misdetected as version.map file.
> > > > * https://urldefense.proofpoint.com/v2/url?u=http-3A__patches.dpdk.org_patch_66878_&d=DwIBAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=FZ_tPCbgFOh18zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=HnuykZkNgy_2cx1i0_QuR-C_vdVYLTJ9rSUA1dCM7WI&s=0szl1YpYLwfb1OF-R5H4_ci3f5XjBUHFrHVp-LdROFI&e= 
> > > > * https://urldefense.proofpoint.com/v2/url?u=https-3A__patchwork.dpdk.org_patch_66900_&d=DwIBAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=FZ_tPCbgFOh18zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=HnuykZkNgy_2cx1i0_QuR-C_vdVYLTJ9rSUA1dCM7WI&s=ugH7B1XKoFQEEopU0sJgqKGwjDJS9Kl9OsijSazmyRc&e= 
> > > >  devtools/check-symbol-change.sh | 4 ++--
> > > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/devtools/check-symbol-change.sh b/devtools/check-symbol-change.sh
> > > > index c5434f3..19ce82f 100755
> > > > --- a/devtools/check-symbol-change.sh
> > > > +++ b/devtools/check-symbol-change.sh
> > > > @@ -17,13 +17,13 @@ build_map_changes()
> > > >                 # map files are altered, and all section/symbol names
> > > >                 # appearing between a triggering of this rule and the
> > > >                 # next trigger of this rule are associated with this file
> > > > -               /[-+] a\/.*\.map/ {map=$2; in_map=1}
> > > > +               /[-+] [ab]\/.*\.map/ {map=$2; in_map=1}
> > > >
> > > >                 # Same pattern as above, only it matches on anything that
> > > >                 # does not end in 'map', indicating we have left the map chunk.
> > > >                 # When we hit this, turn off the in_map variable, which
> > > >                 # supresses the subordonate rules below
> > > > -               /[-+] a\/.*\.[^map]/ {in_map=0}
> > > > +               /[-+] [ab]\/.*\.[^map]/ {in_map=0}
> > > >
> > > >                 # Triggering this rule, which starts a line and ends it
> > > >                 # with a { identifies a versioned section.  The section name is
> > > > --
> > > > 2.8.4
> > > >
> > > 
> > > 
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v1] usertools/dpdk-setup.sh: fix dpdk-setup's behaviour on non-alphanumeric inputs
  @ 2020-03-19 18:20  3% ` Stephen Hemminger
  0 siblings, 0 replies; 200+ results
From: Stephen Hemminger @ 2020-03-19 18:20 UTC (permalink / raw)
  To: Sarosh Arif; +Cc: dev, stable

On Thu, 19 Mar 2020 22:44:23 +0500
Sarosh Arif <sarosh.arif@emumba.com> wrote:

> Bugzilla ID: 419
> Cc: stable@dpdk.org
> Signed-off-by: Sarosh Arif <sarosh.arif@emumba.com>
> ---
>  usertools/dpdk-setup.sh | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/usertools/dpdk-setup.sh b/usertools/dpdk-setup.sh
> index e5bbe9fee..bdacf5256 100755
> --- a/usertools/dpdk-setup.sh
> +++ b/usertools/dpdk-setup.sh
> @@ -595,8 +595,14 @@ while [ "$QUIT" == "0" ]; do
>  	echo -n "Option: "
>  	read our_entry
>  	echo ""
> -	${OPTIONS[our_entry]} ${our_entry}
> -
> +	echo $our_entry | grep "^[0-9]*$" > /dev/null
> +
> +	if  [ "$?" -eq 0 ] ; then
> +		${OPTIONS[our_entry]} ${our_entry}
> +	else
> +		echo "Wrong input format"
> +	fi
> +
>  	if [ "$QUIT" == "0" ] ; then
>  		echo
>  		echo -n "Press enter to continue ..."; read


Why not do it with regex (abi check has similar code) and
use the nice format.

Also handle EOF

diff --git a/usertools/dpdk-setup.sh b/usertools/dpdk-setup.sh
index e5bbe9feec49..f594769a4ef1 100755
--- a/usertools/dpdk-setup.sh
+++ b/usertools/dpdk-setup.sh
@@ -592,10 +592,16 @@ while [ "$QUIT" == "0" ]; do
        echo "[$OPTION_NUM] Exit Script"
        OPTIONS[$OPTION_NUM]="quit"
        echo ""
-       echo -n "Option: "
-       read our_entry
+       read -p "Option: " our_entry
+       [ $? -eq 0 ] || exit 0
+
        echo ""
-       ${OPTIONS[our_entry]} ${our_entry}
+       numeric="^[[:digit:]]+$"
+       if [[ "$our_entry" =~ $numeric ]]; then
+               ${OPTIONS[our_entry]} ${our_entry}
+       else
+               echo "Please enter a numeric value"
+       fi

        if [ "$QUIT" == "0" ] ; then
                echo
--

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] devtools: fix check symbol change script
  2020-03-19 15:40  0%   ` Neil Horman
  2020-03-19 15:45  0%     ` [dpdk-dev] [EXT] " Nithin Dabilpuram
@ 2020-03-19 15:49  0%     ` Bing Zhao
  1 sibling, 0 replies; 200+ results
From: Bing Zhao @ 2020-03-19 15:49 UTC (permalink / raw)
  To: Neil Horman, David Marchand
  Cc: Thomas Monjalon, dev, Jerin Jacob Kollanukkaran,
	Nithin Dabilpuram, dpdk stable

> -----Original Message-----
> From: Neil Horman <nhorman@tuxdriver.com>
> Sent: Thursday, March 19, 2020 11:41 PM
> To: David Marchand <david.marchand@redhat.com>
> Cc: Thomas Monjalon <thomas@monjalon.net>; dev <dev@dpdk.org>;
> Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Nithin Dabilpuram
> <ndabilpuram@marvell.com>; dpdk stable <stable@dpdk.org>; Bing
> Zhao <bingz@mellanox.com>
> Subject: Re: [PATCH] devtools: fix check symbol change script
> 
> On Thu, Mar 19, 2020 at 03:56:03PM +0100, David Marchand wrote:
> > On Thu, Mar 19, 2020 at 3:44 PM Nithin Dabilpuram
> > <ndabilpuram@marvell.com> wrote:
> > >
> > > Fix check symbol change script to detect new diff file when it is in
> > > between  "--- /dev/null" to "b/lib/...".
> > > Current awk line expects line to start with "a/..."
> > > which is not always true for all diffs.
> > > As a result if in_map was '1' earlier, it will not be changed to '0'
> > > and we get check patch errors which are not true as the non
> > > version.map files get interpreted as version map file.
> > >
> > > Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol
> addition")
> > > Cc: nhorman@tuxdriver.com
> > > Cc: stable@dpdk.org
> >
> > There was a previous attempt at fixing this that did not get a review.
> >
> https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2F
> patch
> >
> work.dpdk.org%2Fpatch%2F56303%2F&amp;data=02%7C01%7Cbingz
> %40mellanox.c
> >
> om%7C19a838a81f4f4649f40f08d7cc1be78a%7Ca652971c7d2e4d9ba6
> a4d149256f46
> >
> 1b%7C0%7C0%7C637202292556475544&amp;sdata=wgz8LssuucgrWlY
> xsf978%2ByRVg
> > 83btxZIm9aD56nekY%3D&amp;reserved=0
> >
> > I prefer the last submitted patch as it is simpler, but maybe I missed
> > something in Bing patch.
> >
> > Neil, wdyt?
> >
> I'm not sure why I didn't review the previous patch you refrenced,
> apologies for that.
> 
> That said, I'm not sure how this patch detects /dev/null patterns. It
> looks like you still expect all lines to start with [+-] [ab]...
> 
> Neil

Hi David & Neil,
The cause and the fixing are almost the same for the two patches.
Nithin's is simpler.
When matching on "/dev/null", it just needs to continue.

While in my patch, I think I also fix the [^map] matching even though it works.
The behavior of RE in awk does not work as expected, .c and .h files don't match on the
"NOT map" at the end of the line, but match on the signle letter not among the "m/a/p".
(Correct me if anything wrong). 

Thanks
Bing

> 
> >
> > --
> > David Marchand
> >
> >
> > >
> > > Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
> > > ---
> > > Note: We have two examples where checkpatch errors are because
> of
> > > this because the version.map file change comes earlier in the diff.
> > > Because of this bug, any new file change that comes after
> > > version.map file diff as "/dev/null" to "b/.." gets misdetected as
> version.map file.
> > > *
> > >
> https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2F
> pat
> > >
> ches.dpdk.org%2Fpatch%2F66878%2F&amp;data=02%7C01%7Cbingz%
> 40mellanox
> > > .com%7C19a838a81f4f4649f40f08d7cc1be78a%7Ca652971c7d2e4d
> 9ba6a4d14925
> > >
> 6f461b%7C0%7C0%7C637202292556475544&amp;sdata=ElLbgB9IJ7B6
> kuNTAjKAFr
> > > WpNy8Jdq5%2BmfoRTxN72tI%3D&amp;reserved=0
> > > *
> > >
> https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2F
> pa
> > >
> tchwork.dpdk.org%2Fpatch%2F66900%2F&amp;data=02%7C01%7Cbin
> gz%40mella
> > >
> nox.com%7C19a838a81f4f4649f40f08d7cc1be78a%7Ca652971c7d2e4d
> 9ba6a4d14
> > >
> 9256f461b%7C0%7C0%7C637202292556475544&amp;sdata=iT%2Ft9os
> A4HFTQ2kh3
> > > baWClvD3B%2FFdGzIrQgTvB5SfqU%3D&amp;reserved=0
> > >  devtools/check-symbol-change.sh | 4 ++--
> > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/devtools/check-symbol-change.sh
> > > b/devtools/check-symbol-change.sh index c5434f3..19ce82f 100755
> > > --- a/devtools/check-symbol-change.sh
> > > +++ b/devtools/check-symbol-change.sh
> > > @@ -17,13 +17,13 @@ build_map_changes()
> > >                 # map files are altered, and all section/symbol names
> > >                 # appearing between a triggering of this rule and the
> > >                 # next trigger of this rule are associated with this file
> > > -               /[-+] a\/.*\.map/ {map=$2; in_map=1}
> > > +               /[-+] [ab]\/.*\.map/ {map=$2; in_map=1}
> > >
> > >                 # Same pattern as above, only it matches on anything that
> > >                 # does not end in 'map', indicating we have left the map
> chunk.
> > >                 # When we hit this, turn off the in_map variable, which
> > >                 # supresses the subordonate rules below
> > > -               /[-+] a\/.*\.[^map]/ {in_map=0}
> > > +               /[-+] [ab]\/.*\.[^map]/ {in_map=0}
> > >
> > >                 # Triggering this rule, which starts a line and ends it
> > >                 # with a { identifies a versioned section.  The
> > > section name is
> > > --
> > > 2.8.4
> > >
> >
> >

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [EXT] Re: [PATCH] devtools: fix check symbol change script
  2020-03-19 15:40  0%   ` Neil Horman
@ 2020-03-19 15:45  0%     ` Nithin Dabilpuram
  2020-03-19 18:59  0%       ` Neil Horman
  2020-03-19 15:49  0%     ` [dpdk-dev] " Bing Zhao
  1 sibling, 1 reply; 200+ results
From: Nithin Dabilpuram @ 2020-03-19 15:45 UTC (permalink / raw)
  To: Neil Horman
  Cc: David Marchand, Thomas Monjalon, dev, Jerin Jacob Kollanukkaran,
	dpdk stable, bingz

On Thu, Mar 19, 2020 at 11:40:39AM -0400, Neil Horman wrote:
> External Email
> 
> ----------------------------------------------------------------------
> On Thu, Mar 19, 2020 at 03:56:03PM +0100, David Marchand wrote:
> > On Thu, Mar 19, 2020 at 3:44 PM Nithin Dabilpuram
> > <ndabilpuram@marvell.com> wrote:
> > >
> > > Fix check symbol change script to detect new diff file when
> > > it is in between  "--- /dev/null" to "b/lib/...".
> > > Current awk line expects line to start with "a/..."
> > > which is not always true for all diffs.
> > > As a result if in_map was '1' earlier, it will not be changed
> > > to '0' and we get check patch errors which are not true as the non
> > > version.map files get interpreted as version map file.
> > >
> > > Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
> > > Cc: nhorman@tuxdriver.com
> > > Cc: stable@dpdk.org
> > 
> > There was a previous attempt at fixing this that did not get a review.
> > https://urldefense.proofpoint.com/v2/url?u=http-3A__patchwork.dpdk.org_patch_56303_&d=DwIBAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=FZ_tPCbgFOh18zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=HnuykZkNgy_2cx1i0_QuR-C_vdVYLTJ9rSUA1dCM7WI&s=TW-ZZ_dYy8x6EcvJHtYrv9vaIHSmd0GshvClMwiWPi4&e= 
> > 
> > I prefer the last submitted patch as it is simpler, but maybe I missed
> > something in Bing patch.
> > 
> > Neil, wdyt?
> > 
> I'm not sure why I didn't review the previous patch you refrenced, apologies for
> that.
> 
> That said, I'm not sure how this patch detects /dev/null patterns. It looks like
> you still expect all lines to start with [+-] [ab]...

It doesn't detect /dev/null but the line following /dev/null will start with
"b/...". So this checks for .map in that line as well.

> 
> Neil
> 
> > 
> > -- 
> > David Marchand
> > 
> > 
> > >
> > > Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
> > > ---
> > > Note: We have two examples where checkpatch errors are because of this
> > > because the version.map file change comes earlier in the diff. Because of
> > > this bug, any new file change that comes after version.map file diff
> > > as "/dev/null" to "b/.." gets misdetected as version.map file.
> > > * https://urldefense.proofpoint.com/v2/url?u=http-3A__patches.dpdk.org_patch_66878_&d=DwIBAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=FZ_tPCbgFOh18zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=HnuykZkNgy_2cx1i0_QuR-C_vdVYLTJ9rSUA1dCM7WI&s=0szl1YpYLwfb1OF-R5H4_ci3f5XjBUHFrHVp-LdROFI&e= 
> > > * https://urldefense.proofpoint.com/v2/url?u=https-3A__patchwork.dpdk.org_patch_66900_&d=DwIBAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=FZ_tPCbgFOh18zwRPO9H0yDx8VW38vuapifdDfc8SFQ&m=HnuykZkNgy_2cx1i0_QuR-C_vdVYLTJ9rSUA1dCM7WI&s=ugH7B1XKoFQEEopU0sJgqKGwjDJS9Kl9OsijSazmyRc&e= 
> > >  devtools/check-symbol-change.sh | 4 ++--
> > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/devtools/check-symbol-change.sh b/devtools/check-symbol-change.sh
> > > index c5434f3..19ce82f 100755
> > > --- a/devtools/check-symbol-change.sh
> > > +++ b/devtools/check-symbol-change.sh
> > > @@ -17,13 +17,13 @@ build_map_changes()
> > >                 # map files are altered, and all section/symbol names
> > >                 # appearing between a triggering of this rule and the
> > >                 # next trigger of this rule are associated with this file
> > > -               /[-+] a\/.*\.map/ {map=$2; in_map=1}
> > > +               /[-+] [ab]\/.*\.map/ {map=$2; in_map=1}
> > >
> > >                 # Same pattern as above, only it matches on anything that
> > >                 # does not end in 'map', indicating we have left the map chunk.
> > >                 # When we hit this, turn off the in_map variable, which
> > >                 # supresses the subordonate rules below
> > > -               /[-+] a\/.*\.[^map]/ {in_map=0}
> > > +               /[-+] [ab]\/.*\.[^map]/ {in_map=0}
> > >
> > >                 # Triggering this rule, which starts a line and ends it
> > >                 # with a { identifies a versioned section.  The section name is
> > > --
> > > 2.8.4
> > >
> > 
> > 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] devtools: fix check symbol change script
  2020-03-19 14:56  0% ` David Marchand
@ 2020-03-19 15:40  0%   ` Neil Horman
  2020-03-19 15:45  0%     ` [dpdk-dev] [EXT] " Nithin Dabilpuram
  2020-03-19 15:49  0%     ` [dpdk-dev] " Bing Zhao
  0 siblings, 2 replies; 200+ results
From: Neil Horman @ 2020-03-19 15:40 UTC (permalink / raw)
  To: David Marchand
  Cc: Thomas Monjalon, dev, Jerin Jacob Kollanukkaran,
	Nithin Dabilpuram, dpdk stable, bingz

On Thu, Mar 19, 2020 at 03:56:03PM +0100, David Marchand wrote:
> On Thu, Mar 19, 2020 at 3:44 PM Nithin Dabilpuram
> <ndabilpuram@marvell.com> wrote:
> >
> > Fix check symbol change script to detect new diff file when
> > it is in between  "--- /dev/null" to "b/lib/...".
> > Current awk line expects line to start with "a/..."
> > which is not always true for all diffs.
> > As a result if in_map was '1' earlier, it will not be changed
> > to '0' and we get check patch errors which are not true as the non
> > version.map files get interpreted as version map file.
> >
> > Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
> > Cc: nhorman@tuxdriver.com
> > Cc: stable@dpdk.org
> 
> There was a previous attempt at fixing this that did not get a review.
> http://patchwork.dpdk.org/patch/56303/
> 
> I prefer the last submitted patch as it is simpler, but maybe I missed
> something in Bing patch.
> 
> Neil, wdyt?
> 
I'm not sure why I didn't review the previous patch you refrenced, apologies for
that.

That said, I'm not sure how this patch detects /dev/null patterns. It looks like
you still expect all lines to start with [+-] [ab]...

Neil

> 
> -- 
> David Marchand
> 
> 
> >
> > Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
> > ---
> > Note: We have two examples where checkpatch errors are because of this
> > because the version.map file change comes earlier in the diff. Because of
> > this bug, any new file change that comes after version.map file diff
> > as "/dev/null" to "b/.." gets misdetected as version.map file.
> > * http://patches.dpdk.org/patch/66878/
> > * https://patchwork.dpdk.org/patch/66900/
> >  devtools/check-symbol-change.sh | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/devtools/check-symbol-change.sh b/devtools/check-symbol-change.sh
> > index c5434f3..19ce82f 100755
> > --- a/devtools/check-symbol-change.sh
> > +++ b/devtools/check-symbol-change.sh
> > @@ -17,13 +17,13 @@ build_map_changes()
> >                 # map files are altered, and all section/symbol names
> >                 # appearing between a triggering of this rule and the
> >                 # next trigger of this rule are associated with this file
> > -               /[-+] a\/.*\.map/ {map=$2; in_map=1}
> > +               /[-+] [ab]\/.*\.map/ {map=$2; in_map=1}
> >
> >                 # Same pattern as above, only it matches on anything that
> >                 # does not end in 'map', indicating we have left the map chunk.
> >                 # When we hit this, turn off the in_map variable, which
> >                 # supresses the subordonate rules below
> > -               /[-+] a\/.*\.[^map]/ {in_map=0}
> > +               /[-+] [ab]\/.*\.[^map]/ {in_map=0}
> >
> >                 # Triggering this rule, which starts a line and ends it
> >                 # with a { identifies a versioned section.  The section name is
> > --
> > 2.8.4
> >
> 
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] devtools: fix check symbol change script
  2020-03-19 14:44  3% [dpdk-dev] [PATCH] devtools: fix check symbol change script Nithin Dabilpuram
@ 2020-03-19 14:56  0% ` David Marchand
  2020-03-19 15:40  0%   ` Neil Horman
  2020-03-22 14:37  0% ` Jerin Jacob
  2020-03-23 11:56  3% ` [dpdk-dev] [PATCH v2] " Nithin Dabilpuram
  2 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-03-19 14:56 UTC (permalink / raw)
  To: Neil Horman
  Cc: Thomas Monjalon, dev, Jerin Jacob Kollanukkaran,
	Nithin Dabilpuram, dpdk stable, bingz

On Thu, Mar 19, 2020 at 3:44 PM Nithin Dabilpuram
<ndabilpuram@marvell.com> wrote:
>
> Fix check symbol change script to detect new diff file when
> it is in between  "--- /dev/null" to "b/lib/...".
> Current awk line expects line to start with "a/..."
> which is not always true for all diffs.
> As a result if in_map was '1' earlier, it will not be changed
> to '0' and we get check patch errors which are not true as the non
> version.map files get interpreted as version map file.
>
> Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
> Cc: nhorman@tuxdriver.com
> Cc: stable@dpdk.org

There was a previous attempt at fixing this that did not get a review.
http://patchwork.dpdk.org/patch/56303/

I prefer the last submitted patch as it is simpler, but maybe I missed
something in Bing patch.

Neil, wdyt?


-- 
David Marchand


>
> Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
> ---
> Note: We have two examples where checkpatch errors are because of this
> because the version.map file change comes earlier in the diff. Because of
> this bug, any new file change that comes after version.map file diff
> as "/dev/null" to "b/.." gets misdetected as version.map file.
> * http://patches.dpdk.org/patch/66878/
> * https://patchwork.dpdk.org/patch/66900/
>  devtools/check-symbol-change.sh | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/devtools/check-symbol-change.sh b/devtools/check-symbol-change.sh
> index c5434f3..19ce82f 100755
> --- a/devtools/check-symbol-change.sh
> +++ b/devtools/check-symbol-change.sh
> @@ -17,13 +17,13 @@ build_map_changes()
>                 # map files are altered, and all section/symbol names
>                 # appearing between a triggering of this rule and the
>                 # next trigger of this rule are associated with this file
> -               /[-+] a\/.*\.map/ {map=$2; in_map=1}
> +               /[-+] [ab]\/.*\.map/ {map=$2; in_map=1}
>
>                 # Same pattern as above, only it matches on anything that
>                 # does not end in 'map', indicating we have left the map chunk.
>                 # When we hit this, turn off the in_map variable, which
>                 # supresses the subordonate rules below
> -               /[-+] a\/.*\.[^map]/ {in_map=0}
> +               /[-+] [ab]\/.*\.[^map]/ {in_map=0}
>
>                 # Triggering this rule, which starts a line and ends it
>                 # with a { identifies a versioned section.  The section name is
> --
> 2.8.4
>


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH] devtools: fix check symbol change script
@ 2020-03-19 14:44  3% Nithin Dabilpuram
  2020-03-19 14:56  0% ` David Marchand
                   ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Nithin Dabilpuram @ 2020-03-19 14:44 UTC (permalink / raw)
  To: thomas, david.marchand, Neil Horman
  Cc: dev, jerinj, Nithin Dabilpuram, stable

Fix check symbol change script to detect new diff file when
it is in between  "--- /dev/null" to "b/lib/...".
Current awk line expects line to start with "a/..."
which is not always true for all diffs.
As a result if in_map was '1' earlier, it will not be changed
to '0' and we get check patch errors which are not true as the non
version.map files get interpreted as version map file.

Fixes: 4bec48184e33 ("devtools: add checks for ABI symbol addition")
Cc: nhorman@tuxdriver.com
Cc: stable@dpdk.org

Signed-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
---
Note: We have two examples where checkpatch errors are because of this
because the version.map file change comes earlier in the diff. Because of 
this bug, any new file change that comes after version.map file diff
as "/dev/null" to "b/.." gets misdetected as version.map file.
* http://patches.dpdk.org/patch/66878/
* https://patchwork.dpdk.org/patch/66900/
 devtools/check-symbol-change.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/devtools/check-symbol-change.sh b/devtools/check-symbol-change.sh
index c5434f3..19ce82f 100755
--- a/devtools/check-symbol-change.sh
+++ b/devtools/check-symbol-change.sh
@@ -17,13 +17,13 @@ build_map_changes()
 		# map files are altered, and all section/symbol names
 		# appearing between a triggering of this rule and the
 		# next trigger of this rule are associated with this file
-		/[-+] a\/.*\.map/ {map=$2; in_map=1}
+		/[-+] [ab]\/.*\.map/ {map=$2; in_map=1}
 
 		# Same pattern as above, only it matches on anything that
 		# does not end in 'map', indicating we have left the map chunk.
 		# When we hit this, turn off the in_map variable, which
 		# supresses the subordonate rules below
-		/[-+] a\/.*\.[^map]/ {in_map=0}
+		/[-+] [ab]\/.*\.[^map]/ {in_map=0}
 
 		# Triggering this rule, which starts a line and ends it
 		# with a { identifies a versioned section.  The section name is
-- 
2.8.4


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v3 0/7] vfio/pci: SR-IOV support
  2020-03-19  6:32  0% ` Tian, Kevin
@ 2020-03-19 13:11  0%   ` Alex Williamson
  0 siblings, 0 replies; 200+ results
From: Alex Williamson @ 2020-03-19 13:11 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: kvm, linux-pci, linux-kernel, dev, mtosatti, thomas, bluca,
	jerinjacobk, Richardson, Bruce, cohuck

On Thu, 19 Mar 2020 06:32:25 +0000
"Tian, Kevin" <kevin.tian@intel.com> wrote:

> > From: Alex Williamson <alex.williamson@redhat.com>
> > Sent: Thursday, March 12, 2020 5:58 AM
> > 
> > Only minor tweaks since v2, GET and SET on VFIO_DEVICE_FEATURE are
> > enforced mutually exclusive except with the PROBE option as suggested
> > by Connie, the modinfo text has been expanded for the opt-in to enable
> > SR-IOV support in the vfio-pci driver per discussion with Kevin.
> > 
> > I have not incorporated runtime warnings attempting to detect misuse
> > of SR-IOV or imposed a session lifetime of a VF token, both of which
> > were significant portions of the discussion of the v2 series.  Both of
> > these also seem to impose a usage model or make assumptions about VF
> > resource usage or configuration requirements that don't seem necessary
> > except for the sake of generating a warning or requiring an otherwise
> > unnecessary and implicit token reinitialization.  If there are new
> > thoughts around these or other discussion points, please raise them.
> > 
> > Series overview (same as provided with v1):
> > 
> > The synopsis of this series is that we have an ongoing desire to drive
> > PCIe SR-IOV PFs from userspace with VFIO.  There's an immediate need
> > for this with DPDK drivers and potentially interesting future use
> > cases in virtualization.  We've been reluctant to add this support
> > previously due to the dependency and trust relationship between the
> > VF device and PF driver.  Minimally the PF driver can induce a denial
> > of service to the VF, but depending on the specific implementation,
> > the PF driver might also be responsible for moving data between VFs
> > or have direct access to the state of the VF, including data or state
> > otherwise private to the VF or VF driver.
> > 
> > To help resolve these concerns, we introduce a VF token into the VFIO
> > PCI ABI, which acts as a shared secret key between drivers.  The
> > userspace PF driver is required to set the VF token to a known value
> > and userspace VF drivers are required to provide the token to access
> > the VF device.  If a PF driver is restarted with VF drivers in use, it
> > must also provide the current token in order to prevent a rogue
> > untrusted PF driver from replacing a known driver.  The degree to
> > which this new token is considered secret is left to the userspace
> > drivers, the kernel intentionally provides no means to retrieve the
> > current token.
> > 
> > Note that the above token is only required for this new model where
> > both the PF and VF devices are usable through vfio-pci.  Existing
> > models of VFIO drivers where the PF is used without SR-IOV enabled
> > or the VF is bound to a userspace driver with an in-kernel, host PF
> > driver are unaffected.
> > 
> > The latter configuration above also highlights a new inverted scenario
> > that is now possible, a userspace PF driver with in-kernel VF drivers.
> > I believe this is a scenario that should be allowed, but should not be
> > enabled by default.  This series includes code to set a default
> > driver_override for VFs sourced from a vfio-pci user owned PF, such
> > that the VFs are also bound to vfio-pci.  This model is compatible
> > with tools like driverctl and allows the system administrator to
> > decide if other bindings should be enabled.  The VF token interface
> > above exists only between vfio-pci PF and VF drivers, once a VF is
> > bound to another driver, the administrator has effectively pronounced
> > the device as trusted.  The vfio-pci driver will note alternate
> > binding in dmesg for logging and debugging purposes.
> > 
> > Please review, comment, and test.  The example QEMU implementation
> > provided with the RFC is still current for this version.  Thanks,
> > 
> > Alex  
> 
> The whole series looks good to me:
> 	Reviewed-by: Kevin Tian <kevin.tian@intel.com>

Thanks!

> and confirm one understanding here, since it is not discussed anywhere. For
> VM live migration with assigned VF device, it is not necessary to migrate the
> VF token itself and actually we don't allow userspace to retrieve it. Instead,
> Qemu just follows whatever token requirement on the dest to open the new
> VF: could be same or different token as/from src, or even no token if PF
> driver runs in kernel on dest. I suppose either combination could work, correct?

That's correct.  Thanks,

Alex

> > RFC:
> > https://lore.kernel.org/lkml/158085337582.9445.17682266437583505502.stg
> > it@gimli.home/
> > v1:
> > https://lore.kernel.org/lkml/158145472604.16827.15751375540102298130.st
> > git@gimli.home/
> > v2:
> > https://lore.kernel.org/lkml/158213716959.17090.8399427017403507114.stg
> > it@gimli.home/
> > 
> > ---
> > 
> > Alex Williamson (7):
> >       vfio: Include optional device match in vfio_device_ops callbacks
> >       vfio/pci: Implement match ops
> >       vfio/pci: Introduce VF token
> >       vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user
> >       vfio/pci: Add sriov_configure support
> >       vfio/pci: Remove dev_fmt definition
> >       vfio/pci: Cleanup .probe() exit paths
> > 
> > 
> >  drivers/vfio/pci/vfio_pci.c         |  390
> > +++++++++++++++++++++++++++++++++--
> >  drivers/vfio/pci/vfio_pci_private.h |   10 +
> >  drivers/vfio/vfio.c                 |   20 +-
> >  include/linux/vfio.h                |    4
> >  include/uapi/linux/vfio.h           |   37 +++
> >  5 files changed, 433 insertions(+), 28 deletions(-)  
> 


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk-stable] [PATCH] doc: prefer https when pointing to dpdk.org
  2020-03-19  8:28  4% [dpdk-dev] [PATCH] doc: prefer https when pointing to dpdk.org David Marchand
@ 2020-03-19 10:46  0% ` Kevin Traynor
  0 siblings, 0 replies; 200+ results
From: Kevin Traynor @ 2020-03-19 10:46 UTC (permalink / raw)
  To: David Marchand, dev; +Cc: thomas, stable

On 19/03/2020 08:28, David Marchand wrote:
> for file in $(git grep -l http://.*dpdk.org doc/); do
>   sed -i -e 's#http://\(.*dpdk.org\)#https://\1#g' $file;
> done
> 
> Cc: stable@dpdk.org
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>

Acked-by: Kevin Traynor <ktraynor@redhat.com>

> ---
>  devtools/checkpatches.sh                         |  8 ++++++++
>  doc/guides/contributing/documentation.rst        | 12 ++++++------
>  doc/guides/contributing/patches.rst              | 16 ++++++++--------
>  doc/guides/contributing/stable.rst               |  8 ++++----
>  doc/guides/contributing/vulnerability.rst        |  6 +++---
>  doc/guides/freebsd_gsg/install_from_ports.rst    |  2 +-
>  doc/guides/howto/flow_bifurcation.rst            |  2 +-
>  doc/guides/linux_gsg/nic_perf_intel_platform.rst |  2 +-
>  doc/guides/nics/enic.rst                         |  2 +-
>  doc/guides/prog_guide/cryptodev_lib.rst          |  2 +-
>  doc/guides/rel_notes/deprecation.rst             |  2 +-
>  11 files changed, 35 insertions(+), 27 deletions(-)
> 
> diff --git a/devtools/checkpatches.sh b/devtools/checkpatches.sh
> index 1794468376..d3cf0e4c5d 100755
> --- a/devtools/checkpatches.sh
> +++ b/devtools/checkpatches.sh
> @@ -70,6 +70,14 @@ check_forbidden_additions() { # <patch>
>  		-f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \
>  		"$1" || res=1
>  
> +	# links must prefer https over http
> +	awk -v FOLDERS='doc' \
> +		-v EXPRESSIONS='http://.*dpdk.org' \
> +		-v RET_ON_FAIL=1 \
> +		-v MESSAGE='Using non https link to dpdk.org' \
> +		-f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \
> +		"$1" || res=1
> +
>  	return $res
>  }
>  
> diff --git a/doc/guides/contributing/documentation.rst b/doc/guides/contributing/documentation.rst
> index 550d8dec28..375ea64ba8 100644
> --- a/doc/guides/contributing/documentation.rst
> +++ b/doc/guides/contributing/documentation.rst
> @@ -82,7 +82,7 @@ added to by the developer.
>  * **API documentation**
>  
>    The API documentation explains how to use the public DPDK functions.
> -  The `API index page <http://doc.dpdk.org/api/>`_ shows the generated API documentation with related groups of functions.
> +  The `API index page <https://doc.dpdk.org/api/>`_ shows the generated API documentation with related groups of functions.
>  
>    The API documentation should be updated via Doxygen comments when new functions are added.
>  
> @@ -561,14 +561,14 @@ Hyperlinks
>  ~~~~~~~~~~
>  
>  * Links to external websites can be plain URLs.
> -  The following is rendered as http://dpdk.org::
> +  The following is rendered as https://dpdk.org::
>  
> -     http://dpdk.org
> +     https://dpdk.org
>  
>  * They can contain alternative text.
> -  The following is rendered as `Check out DPDK <http://dpdk.org>`_::
> +  The following is rendered as `Check out DPDK <https://dpdk.org>`_::
>  
> -     `Check out DPDK <http://dpdk.org>`_
> +     `Check out DPDK <https://dpdk.org>`_
>  
>  * An internal link can be generated by placing labels in the document with the format ``.. _label_name``.
>  
> @@ -666,7 +666,7 @@ The following are some guidelines for use of Doxygen in the DPDK API documentati
>         */
>  
>    In the API documentation the functions will be rendered as links, see the
> -  `online section of the rte_ethdev.h docs <http://doc.dpdk.org/api/rte__ethdev_8h.html>`_ that contains the above text.
> +  `online section of the rte_ethdev.h docs <https://doc.dpdk.org/api/rte__ethdev_8h.html>`_ that contains the above text.
>  
>  * The ``@see`` keyword can be used to create a *see also* link to another file or library.
>    This directive should be placed on one line at the bottom of the documentation section.
> diff --git a/doc/guides/contributing/patches.rst b/doc/guides/contributing/patches.rst
> index 59442824a1..2ec044891e 100644
> --- a/doc/guides/contributing/patches.rst
> +++ b/doc/guides/contributing/patches.rst
> @@ -28,9 +28,9 @@ The DPDK development process has the following features:
>  * All sub-repositories are merged into main repository for ``-rc1`` and ``-rc2`` versions of the release.
>  * After the ``-rc2`` release all patches should target the main repository.
>  
> -The mailing list for DPDK development is `dev@dpdk.org <http://mails.dpdk.org/archives/dev/>`_.
> -Contributors will need to `register for the mailing list <http://mails.dpdk.org/listinfo/dev>`_ in order to submit patches.
> -It is also worth registering for the DPDK `Patchwork <http://patches.dpdk.org/project/dpdk/list/>`_
> +The mailing list for DPDK development is `dev@dpdk.org <https://mails.dpdk.org/archives/dev/>`_.
> +Contributors will need to `register for the mailing list <https://mails.dpdk.org/listinfo/dev>`_ in order to submit patches.
> +It is also worth registering for the DPDK `Patchwork <https://patches.dpdk.org/project/dpdk/list/>`_
>  
>  If you are using the GitHub service, you can link your repository to
>  the ``travis-ci.org`` build service.  When you push patches to your GitHub
> @@ -130,12 +130,12 @@ The source code can be cloned using either of the following:
>  main repository::
>  
>      git clone git://dpdk.org/dpdk
> -    git clone http://dpdk.org/git/dpdk
> +    git clone https://dpdk.org/git/dpdk
>  
> -sub-repositories (`list <http://git.dpdk.org/next>`_)::
> +sub-repositories (`list <https://git.dpdk.org/next>`_)::
>  
>      git clone git://dpdk.org/next/dpdk-next-*
> -    git clone http://dpdk.org/git/next/dpdk-next-*
> +    git clone https://dpdk.org/git/next/dpdk-next-*
>  
>  Make your Changes
>  -----------------
> @@ -320,7 +320,7 @@ Patch for Stable Releases
>  ~~~~~~~~~~~~~~~~~~~~~~~~~
>  
>  All fix patches to the master branch that are candidates for backporting
> -should also be CCed to the `stable@dpdk.org <http://mails.dpdk.org/listinfo/stable>`_
> +should also be CCed to the `stable@dpdk.org <https://mails.dpdk.org/listinfo/stable>`_
>  mailing list.
>  In the commit message body the Cc: stable@dpdk.org should be inserted as follows::
>  
> @@ -563,7 +563,7 @@ If the patch is in relation to a previous email thread you can add it to the sam
>     git send-email --to dev@dpdk.org --in-reply-to <1234-foo@bar.com> 000*.patch
>  
>  The Message ID can be found in the raw text of emails or at the top of each Patchwork patch,
> -`for example <http://patches.dpdk.org/patch/7646/>`_.
> +`for example <https://patches.dpdk.org/patch/7646/>`_.
>  Shallow threading (``--thread --no-chain-reply-to``) is preferred for a patch series.
>  
>  Once submitted your patches will appear on the mailing list and in Patchwork.
> diff --git a/doc/guides/contributing/stable.rst b/doc/guides/contributing/stable.rst
> index 90b3d8e44f..2947f27c6a 100644
> --- a/doc/guides/contributing/stable.rst
> +++ b/doc/guides/contributing/stable.rst
> @@ -51,7 +51,7 @@ agreement and a commitment from a maintainer. The current policy is that each
>  year's November (X.11) release will be maintained as an LTS for 2 years.
>  
>  After the X.11 release, an LTS branch will be created for it at
> -http://git.dpdk.org/dpdk-stable where bugfixes will be backported to.
> +https://git.dpdk.org/dpdk-stable where bugfixes will be backported to.
>  
>  A LTS release may align with the declaration of a new major ABI version,
>  please read the :doc:`abi_policy` for more information.
> @@ -107,7 +107,7 @@ The Stable and LTS release are coordinated on the stable@dpdk.org mailing
>  list.
>  
>  All fix patches to the master branch that are candidates for backporting
> -should also be CCed to the `stable@dpdk.org <http://mails.dpdk.org/listinfo/stable>`_
> +should also be CCed to the `stable@dpdk.org <https://mails.dpdk.org/listinfo/stable>`_
>  mailing list.
>  
>  
> @@ -118,7 +118,7 @@ A Stable Release will be released by:
>  
>  * Tagging the release with YY.MM.n (year, month, number).
>  * Uploading a tarball of the release to dpdk.org.
> -* Sending an announcement to the `announce@dpdk.org <http://mails.dpdk.org/listinfo/announce>`_
> +* Sending an announcement to the `announce@dpdk.org <https://mails.dpdk.org/listinfo/announce>`_
>    list.
>  
> -Stable releases are available on the `dpdk.org download page <http://core.dpdk.org/download/>`_.
> +Stable releases are available on the `dpdk.org download page <https://core.dpdk.org/download/>`_.
> diff --git a/doc/guides/contributing/vulnerability.rst b/doc/guides/contributing/vulnerability.rst
> index 5484119d19..da00acd4f0 100644
> --- a/doc/guides/contributing/vulnerability.rst
> +++ b/doc/guides/contributing/vulnerability.rst
> @@ -36,11 +36,11 @@ Report
>  
>  Do not use Bugzilla (unsecured).
>  Instead, send GPG-encrypted emails
> -to `security@dpdk.org <http://core.dpdk.org/security#contact>`_.
> +to `security@dpdk.org <https://core.dpdk.org/security#contact>`_.
>  Anyone can post to this list.
>  In order to reduce the disclosure of a vulnerability in the early stages,
>  membership of this list is intentionally limited to a `small number of people
> -<http://mails.dpdk.org/roster/security>`_.
> +<https://mails.dpdk.org/roster/security>`_.
>  
>  It is additionally encouraged to GPG-sign one-on-one conversations
>  as part of the security process.
> @@ -188,7 +188,7 @@ Downstream stakeholders are expected not to deploy or disclose patches
>  until the embargo is passed, otherwise they will be removed from the list.
>  
>  Downstream stakeholders (in `security-prerelease list
> -<http://mails.dpdk.org/roster/security-prerelease>`_), are:
> +<https://mails.dpdk.org/roster/security-prerelease>`_), are:
>  
>  * Operating system vendors known to package DPDK
>  * Major DPDK users, considered trustworthy by the technical board, who
> diff --git a/doc/guides/freebsd_gsg/install_from_ports.rst b/doc/guides/freebsd_gsg/install_from_ports.rst
> index 36dc4a417b..d946f3f3b2 100644
> --- a/doc/guides/freebsd_gsg/install_from_ports.rst
> +++ b/doc/guides/freebsd_gsg/install_from_ports.rst
> @@ -72,7 +72,7 @@ These examples can be compiled and run as described in :ref:`compiling_sample_ap
>  .. note::
>  
>     To install a copy of the DPDK compiled using gcc, please download the
> -   official DPDK package from http://core.dpdk.org/download/ and install manually using
> +   official DPDK package from https://core.dpdk.org/download/ and install manually using
>     the instructions given in the next chapter, :ref:`building_from_source`
>  
>  An example application can therefore be copied to a user's home directory and
> diff --git a/doc/guides/howto/flow_bifurcation.rst b/doc/guides/howto/flow_bifurcation.rst
> index a36126472c..68ac913e7d 100644
> --- a/doc/guides/howto/flow_bifurcation.rst
> +++ b/doc/guides/howto/flow_bifurcation.rst
> @@ -294,4 +294,4 @@ The typical procedure to achieve this is as follows:
>       'not involved', while ``00`` or no mask means 'involved'.
>  
>     * For more details of the configuration, refer to the
> -     `cloud filter test plan <http://git.dpdk.org/tools/dts/tree/test_plans/cloud_filter_test_plan.rst>`_
> +     `cloud filter test plan <https://git.dpdk.org/tools/dts/tree/test_plans/cloud_filter_test_plan.rst>`_
> diff --git a/doc/guides/linux_gsg/nic_perf_intel_platform.rst b/doc/guides/linux_gsg/nic_perf_intel_platform.rst
> index c554c2159c..1dabbce244 100644
> --- a/doc/guides/linux_gsg/nic_perf_intel_platform.rst
> +++ b/doc/guides/linux_gsg/nic_perf_intel_platform.rst
> @@ -64,7 +64,7 @@ This aligns with the previous output which showed that each channel has one memo
>  Network Interface Card Requirements
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  
> -Use a `DPDK supported <http://core.dpdk.org/supported/>`_ high end NIC such as the Intel XL710 40GbE.
> +Use a `DPDK supported <https://core.dpdk.org/supported/>`_ high end NIC such as the Intel XL710 40GbE.
>  
>  Make sure each NIC has been flashed the latest version of NVM/firmware.
>  
> diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
> index 65e536d422..24d2b5713a 100644
> --- a/doc/guides/nics/enic.rst
> +++ b/doc/guides/nics/enic.rst
> @@ -14,7 +14,7 @@ How to obtain ENIC PMD integrated DPDK
>  --------------------------------------
>  
>  ENIC PMD support is integrated into the DPDK suite. dpdk-<version>.tar.gz
> -should be downloaded from http://core.dpdk.org/download/
> +should be downloaded from https://core.dpdk.org/download/
>  
>  
>  Configuration information
> diff --git a/doc/guides/prog_guide/cryptodev_lib.rst b/doc/guides/prog_guide/cryptodev_lib.rst
> index b91f7c8b7f..c14f750fa8 100644
> --- a/doc/guides/prog_guide/cryptodev_lib.rst
> +++ b/doc/guides/prog_guide/cryptodev_lib.rst
> @@ -1128,4 +1128,4 @@ Asymmetric Crypto Device API
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  
>  The cryptodev Library API is described in the
> -`DPDK API Reference <http://doc.dpdk.org/api/>`_
> +`DPDK API Reference <https://doc.dpdk.org/api/>`_
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 1339f54f5f..151a86460d 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -43,7 +43,7 @@ Deprecation Notices
>    kernel module to the dpdk-kmods repository in the /linux/igb_uio/ directory
>    in 20.11.
>    Minutes of Technical Board Meeting of `2019-11-06
> -  <http://mails.dpdk.org/archives/dev/2019-November/151763.html>`_.
> +  <https://mails.dpdk.org/archives/dev/2019-November/151763.html>`_.
>  
>  * lib: will fix extending some enum/define breaking the ABI. There are multiple
>    samples in DPDK that enum/define terminated with a ``.*MAX.*`` value which is
> 


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH] doc: prefer https when pointing to dpdk.org
@ 2020-03-19  8:28  4% David Marchand
  2020-03-19 10:46  0% ` [dpdk-dev] [dpdk-stable] " Kevin Traynor
  0 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-03-19  8:28 UTC (permalink / raw)
  To: dev; +Cc: thomas, stable

for file in $(git grep -l http://.*dpdk.org doc/); do
  sed -i -e 's#http://\(.*dpdk.org\)#https://\1#g' $file;
done

Cc: stable@dpdk.org

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 devtools/checkpatches.sh                         |  8 ++++++++
 doc/guides/contributing/documentation.rst        | 12 ++++++------
 doc/guides/contributing/patches.rst              | 16 ++++++++--------
 doc/guides/contributing/stable.rst               |  8 ++++----
 doc/guides/contributing/vulnerability.rst        |  6 +++---
 doc/guides/freebsd_gsg/install_from_ports.rst    |  2 +-
 doc/guides/howto/flow_bifurcation.rst            |  2 +-
 doc/guides/linux_gsg/nic_perf_intel_platform.rst |  2 +-
 doc/guides/nics/enic.rst                         |  2 +-
 doc/guides/prog_guide/cryptodev_lib.rst          |  2 +-
 doc/guides/rel_notes/deprecation.rst             |  2 +-
 11 files changed, 35 insertions(+), 27 deletions(-)

diff --git a/devtools/checkpatches.sh b/devtools/checkpatches.sh
index 1794468376..d3cf0e4c5d 100755
--- a/devtools/checkpatches.sh
+++ b/devtools/checkpatches.sh
@@ -70,6 +70,14 @@ check_forbidden_additions() { # <patch>
 		-f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \
 		"$1" || res=1
 
+	# links must prefer https over http
+	awk -v FOLDERS='doc' \
+		-v EXPRESSIONS='http://.*dpdk.org' \
+		-v RET_ON_FAIL=1 \
+		-v MESSAGE='Using non https link to dpdk.org' \
+		-f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \
+		"$1" || res=1
+
 	return $res
 }
 
diff --git a/doc/guides/contributing/documentation.rst b/doc/guides/contributing/documentation.rst
index 550d8dec28..375ea64ba8 100644
--- a/doc/guides/contributing/documentation.rst
+++ b/doc/guides/contributing/documentation.rst
@@ -82,7 +82,7 @@ added to by the developer.
 * **API documentation**
 
   The API documentation explains how to use the public DPDK functions.
-  The `API index page <http://doc.dpdk.org/api/>`_ shows the generated API documentation with related groups of functions.
+  The `API index page <https://doc.dpdk.org/api/>`_ shows the generated API documentation with related groups of functions.
 
   The API documentation should be updated via Doxygen comments when new functions are added.
 
@@ -561,14 +561,14 @@ Hyperlinks
 ~~~~~~~~~~
 
 * Links to external websites can be plain URLs.
-  The following is rendered as http://dpdk.org::
+  The following is rendered as https://dpdk.org::
 
-     http://dpdk.org
+     https://dpdk.org
 
 * They can contain alternative text.
-  The following is rendered as `Check out DPDK <http://dpdk.org>`_::
+  The following is rendered as `Check out DPDK <https://dpdk.org>`_::
 
-     `Check out DPDK <http://dpdk.org>`_
+     `Check out DPDK <https://dpdk.org>`_
 
 * An internal link can be generated by placing labels in the document with the format ``.. _label_name``.
 
@@ -666,7 +666,7 @@ The following are some guidelines for use of Doxygen in the DPDK API documentati
        */
 
   In the API documentation the functions will be rendered as links, see the
-  `online section of the rte_ethdev.h docs <http://doc.dpdk.org/api/rte__ethdev_8h.html>`_ that contains the above text.
+  `online section of the rte_ethdev.h docs <https://doc.dpdk.org/api/rte__ethdev_8h.html>`_ that contains the above text.
 
 * The ``@see`` keyword can be used to create a *see also* link to another file or library.
   This directive should be placed on one line at the bottom of the documentation section.
diff --git a/doc/guides/contributing/patches.rst b/doc/guides/contributing/patches.rst
index 59442824a1..2ec044891e 100644
--- a/doc/guides/contributing/patches.rst
+++ b/doc/guides/contributing/patches.rst
@@ -28,9 +28,9 @@ The DPDK development process has the following features:
 * All sub-repositories are merged into main repository for ``-rc1`` and ``-rc2`` versions of the release.
 * After the ``-rc2`` release all patches should target the main repository.
 
-The mailing list for DPDK development is `dev@dpdk.org <http://mails.dpdk.org/archives/dev/>`_.
-Contributors will need to `register for the mailing list <http://mails.dpdk.org/listinfo/dev>`_ in order to submit patches.
-It is also worth registering for the DPDK `Patchwork <http://patches.dpdk.org/project/dpdk/list/>`_
+The mailing list for DPDK development is `dev@dpdk.org <https://mails.dpdk.org/archives/dev/>`_.
+Contributors will need to `register for the mailing list <https://mails.dpdk.org/listinfo/dev>`_ in order to submit patches.
+It is also worth registering for the DPDK `Patchwork <https://patches.dpdk.org/project/dpdk/list/>`_
 
 If you are using the GitHub service, you can link your repository to
 the ``travis-ci.org`` build service.  When you push patches to your GitHub
@@ -130,12 +130,12 @@ The source code can be cloned using either of the following:
 main repository::
 
     git clone git://dpdk.org/dpdk
-    git clone http://dpdk.org/git/dpdk
+    git clone https://dpdk.org/git/dpdk
 
-sub-repositories (`list <http://git.dpdk.org/next>`_)::
+sub-repositories (`list <https://git.dpdk.org/next>`_)::
 
     git clone git://dpdk.org/next/dpdk-next-*
-    git clone http://dpdk.org/git/next/dpdk-next-*
+    git clone https://dpdk.org/git/next/dpdk-next-*
 
 Make your Changes
 -----------------
@@ -320,7 +320,7 @@ Patch for Stable Releases
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 All fix patches to the master branch that are candidates for backporting
-should also be CCed to the `stable@dpdk.org <http://mails.dpdk.org/listinfo/stable>`_
+should also be CCed to the `stable@dpdk.org <https://mails.dpdk.org/listinfo/stable>`_
 mailing list.
 In the commit message body the Cc: stable@dpdk.org should be inserted as follows::
 
@@ -563,7 +563,7 @@ If the patch is in relation to a previous email thread you can add it to the sam
    git send-email --to dev@dpdk.org --in-reply-to <1234-foo@bar.com> 000*.patch
 
 The Message ID can be found in the raw text of emails or at the top of each Patchwork patch,
-`for example <http://patches.dpdk.org/patch/7646/>`_.
+`for example <https://patches.dpdk.org/patch/7646/>`_.
 Shallow threading (``--thread --no-chain-reply-to``) is preferred for a patch series.
 
 Once submitted your patches will appear on the mailing list and in Patchwork.
diff --git a/doc/guides/contributing/stable.rst b/doc/guides/contributing/stable.rst
index 90b3d8e44f..2947f27c6a 100644
--- a/doc/guides/contributing/stable.rst
+++ b/doc/guides/contributing/stable.rst
@@ -51,7 +51,7 @@ agreement and a commitment from a maintainer. The current policy is that each
 year's November (X.11) release will be maintained as an LTS for 2 years.
 
 After the X.11 release, an LTS branch will be created for it at
-http://git.dpdk.org/dpdk-stable where bugfixes will be backported to.
+https://git.dpdk.org/dpdk-stable where bugfixes will be backported to.
 
 A LTS release may align with the declaration of a new major ABI version,
 please read the :doc:`abi_policy` for more information.
@@ -107,7 +107,7 @@ The Stable and LTS release are coordinated on the stable@dpdk.org mailing
 list.
 
 All fix patches to the master branch that are candidates for backporting
-should also be CCed to the `stable@dpdk.org <http://mails.dpdk.org/listinfo/stable>`_
+should also be CCed to the `stable@dpdk.org <https://mails.dpdk.org/listinfo/stable>`_
 mailing list.
 
 
@@ -118,7 +118,7 @@ A Stable Release will be released by:
 
 * Tagging the release with YY.MM.n (year, month, number).
 * Uploading a tarball of the release to dpdk.org.
-* Sending an announcement to the `announce@dpdk.org <http://mails.dpdk.org/listinfo/announce>`_
+* Sending an announcement to the `announce@dpdk.org <https://mails.dpdk.org/listinfo/announce>`_
   list.
 
-Stable releases are available on the `dpdk.org download page <http://core.dpdk.org/download/>`_.
+Stable releases are available on the `dpdk.org download page <https://core.dpdk.org/download/>`_.
diff --git a/doc/guides/contributing/vulnerability.rst b/doc/guides/contributing/vulnerability.rst
index 5484119d19..da00acd4f0 100644
--- a/doc/guides/contributing/vulnerability.rst
+++ b/doc/guides/contributing/vulnerability.rst
@@ -36,11 +36,11 @@ Report
 
 Do not use Bugzilla (unsecured).
 Instead, send GPG-encrypted emails
-to `security@dpdk.org <http://core.dpdk.org/security#contact>`_.
+to `security@dpdk.org <https://core.dpdk.org/security#contact>`_.
 Anyone can post to this list.
 In order to reduce the disclosure of a vulnerability in the early stages,
 membership of this list is intentionally limited to a `small number of people
-<http://mails.dpdk.org/roster/security>`_.
+<https://mails.dpdk.org/roster/security>`_.
 
 It is additionally encouraged to GPG-sign one-on-one conversations
 as part of the security process.
@@ -188,7 +188,7 @@ Downstream stakeholders are expected not to deploy or disclose patches
 until the embargo is passed, otherwise they will be removed from the list.
 
 Downstream stakeholders (in `security-prerelease list
-<http://mails.dpdk.org/roster/security-prerelease>`_), are:
+<https://mails.dpdk.org/roster/security-prerelease>`_), are:
 
 * Operating system vendors known to package DPDK
 * Major DPDK users, considered trustworthy by the technical board, who
diff --git a/doc/guides/freebsd_gsg/install_from_ports.rst b/doc/guides/freebsd_gsg/install_from_ports.rst
index 36dc4a417b..d946f3f3b2 100644
--- a/doc/guides/freebsd_gsg/install_from_ports.rst
+++ b/doc/guides/freebsd_gsg/install_from_ports.rst
@@ -72,7 +72,7 @@ These examples can be compiled and run as described in :ref:`compiling_sample_ap
 .. note::
 
    To install a copy of the DPDK compiled using gcc, please download the
-   official DPDK package from http://core.dpdk.org/download/ and install manually using
+   official DPDK package from https://core.dpdk.org/download/ and install manually using
    the instructions given in the next chapter, :ref:`building_from_source`
 
 An example application can therefore be copied to a user's home directory and
diff --git a/doc/guides/howto/flow_bifurcation.rst b/doc/guides/howto/flow_bifurcation.rst
index a36126472c..68ac913e7d 100644
--- a/doc/guides/howto/flow_bifurcation.rst
+++ b/doc/guides/howto/flow_bifurcation.rst
@@ -294,4 +294,4 @@ The typical procedure to achieve this is as follows:
      'not involved', while ``00`` or no mask means 'involved'.
 
    * For more details of the configuration, refer to the
-     `cloud filter test plan <http://git.dpdk.org/tools/dts/tree/test_plans/cloud_filter_test_plan.rst>`_
+     `cloud filter test plan <https://git.dpdk.org/tools/dts/tree/test_plans/cloud_filter_test_plan.rst>`_
diff --git a/doc/guides/linux_gsg/nic_perf_intel_platform.rst b/doc/guides/linux_gsg/nic_perf_intel_platform.rst
index c554c2159c..1dabbce244 100644
--- a/doc/guides/linux_gsg/nic_perf_intel_platform.rst
+++ b/doc/guides/linux_gsg/nic_perf_intel_platform.rst
@@ -64,7 +64,7 @@ This aligns with the previous output which showed that each channel has one memo
 Network Interface Card Requirements
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Use a `DPDK supported <http://core.dpdk.org/supported/>`_ high end NIC such as the Intel XL710 40GbE.
+Use a `DPDK supported <https://core.dpdk.org/supported/>`_ high end NIC such as the Intel XL710 40GbE.
 
 Make sure each NIC has been flashed the latest version of NVM/firmware.
 
diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 65e536d422..24d2b5713a 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -14,7 +14,7 @@ How to obtain ENIC PMD integrated DPDK
 --------------------------------------
 
 ENIC PMD support is integrated into the DPDK suite. dpdk-<version>.tar.gz
-should be downloaded from http://core.dpdk.org/download/
+should be downloaded from https://core.dpdk.org/download/
 
 
 Configuration information
diff --git a/doc/guides/prog_guide/cryptodev_lib.rst b/doc/guides/prog_guide/cryptodev_lib.rst
index b91f7c8b7f..c14f750fa8 100644
--- a/doc/guides/prog_guide/cryptodev_lib.rst
+++ b/doc/guides/prog_guide/cryptodev_lib.rst
@@ -1128,4 +1128,4 @@ Asymmetric Crypto Device API
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The cryptodev Library API is described in the
-`DPDK API Reference <http://doc.dpdk.org/api/>`_
+`DPDK API Reference <https://doc.dpdk.org/api/>`_
diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 1339f54f5f..151a86460d 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -43,7 +43,7 @@ Deprecation Notices
   kernel module to the dpdk-kmods repository in the /linux/igb_uio/ directory
   in 20.11.
   Minutes of Technical Board Meeting of `2019-11-06
-  <http://mails.dpdk.org/archives/dev/2019-November/151763.html>`_.
+  <https://mails.dpdk.org/archives/dev/2019-November/151763.html>`_.
 
 * lib: will fix extending some enum/define breaking the ABI. There are multiple
   samples in DPDK that enum/define terminated with a ``.*MAX.*`` value which is
-- 
2.23.0


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v3 0/7] vfio/pci: SR-IOV support
  2020-03-11 21:58  2% [dpdk-dev] [PATCH v3 0/7] vfio/pci: SR-IOV support Alex Williamson
@ 2020-03-19  6:32  0% ` Tian, Kevin
  2020-03-19 13:11  0%   ` Alex Williamson
  0 siblings, 1 reply; 200+ results
From: Tian, Kevin @ 2020-03-19  6:32 UTC (permalink / raw)
  To: Alex Williamson, kvm
  Cc: linux-pci, linux-kernel, dev, mtosatti, thomas, bluca,
	jerinjacobk, Richardson, Bruce, cohuck

> From: Alex Williamson <alex.williamson@redhat.com>
> Sent: Thursday, March 12, 2020 5:58 AM
> 
> Only minor tweaks since v2, GET and SET on VFIO_DEVICE_FEATURE are
> enforced mutually exclusive except with the PROBE option as suggested
> by Connie, the modinfo text has been expanded for the opt-in to enable
> SR-IOV support in the vfio-pci driver per discussion with Kevin.
> 
> I have not incorporated runtime warnings attempting to detect misuse
> of SR-IOV or imposed a session lifetime of a VF token, both of which
> were significant portions of the discussion of the v2 series.  Both of
> these also seem to impose a usage model or make assumptions about VF
> resource usage or configuration requirements that don't seem necessary
> except for the sake of generating a warning or requiring an otherwise
> unnecessary and implicit token reinitialization.  If there are new
> thoughts around these or other discussion points, please raise them.
> 
> Series overview (same as provided with v1):
> 
> The synopsis of this series is that we have an ongoing desire to drive
> PCIe SR-IOV PFs from userspace with VFIO.  There's an immediate need
> for this with DPDK drivers and potentially interesting future use
> cases in virtualization.  We've been reluctant to add this support
> previously due to the dependency and trust relationship between the
> VF device and PF driver.  Minimally the PF driver can induce a denial
> of service to the VF, but depending on the specific implementation,
> the PF driver might also be responsible for moving data between VFs
> or have direct access to the state of the VF, including data or state
> otherwise private to the VF or VF driver.
> 
> To help resolve these concerns, we introduce a VF token into the VFIO
> PCI ABI, which acts as a shared secret key between drivers.  The
> userspace PF driver is required to set the VF token to a known value
> and userspace VF drivers are required to provide the token to access
> the VF device.  If a PF driver is restarted with VF drivers in use, it
> must also provide the current token in order to prevent a rogue
> untrusted PF driver from replacing a known driver.  The degree to
> which this new token is considered secret is left to the userspace
> drivers, the kernel intentionally provides no means to retrieve the
> current token.
> 
> Note that the above token is only required for this new model where
> both the PF and VF devices are usable through vfio-pci.  Existing
> models of VFIO drivers where the PF is used without SR-IOV enabled
> or the VF is bound to a userspace driver with an in-kernel, host PF
> driver are unaffected.
> 
> The latter configuration above also highlights a new inverted scenario
> that is now possible, a userspace PF driver with in-kernel VF drivers.
> I believe this is a scenario that should be allowed, but should not be
> enabled by default.  This series includes code to set a default
> driver_override for VFs sourced from a vfio-pci user owned PF, such
> that the VFs are also bound to vfio-pci.  This model is compatible
> with tools like driverctl and allows the system administrator to
> decide if other bindings should be enabled.  The VF token interface
> above exists only between vfio-pci PF and VF drivers, once a VF is
> bound to another driver, the administrator has effectively pronounced
> the device as trusted.  The vfio-pci driver will note alternate
> binding in dmesg for logging and debugging purposes.
> 
> Please review, comment, and test.  The example QEMU implementation
> provided with the RFC is still current for this version.  Thanks,
> 
> Alex

The whole series looks good to me:
	Reviewed-by: Kevin Tian <kevin.tian@intel.com>

and confirm one understanding here, since it is not discussed anywhere. For
VM live migration with assigned VF device, it is not necessary to migrate the
VF token itself and actually we don't allow userspace to retrieve it. Instead,
Qemu just follows whatever token requirement on the dest to open the new
VF: could be same or different token as/from src, or even no token if PF
driver runs in kernel on dest. I suppose either combination could work, correct?

Thanks
Kevin

> 
> RFC:
> https://lore.kernel.org/lkml/158085337582.9445.17682266437583505502.stg
> it@gimli.home/
> v1:
> https://lore.kernel.org/lkml/158145472604.16827.15751375540102298130.st
> git@gimli.home/
> v2:
> https://lore.kernel.org/lkml/158213716959.17090.8399427017403507114.stg
> it@gimli.home/
> 
> ---
> 
> Alex Williamson (7):
>       vfio: Include optional device match in vfio_device_ops callbacks
>       vfio/pci: Implement match ops
>       vfio/pci: Introduce VF token
>       vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user
>       vfio/pci: Add sriov_configure support
>       vfio/pci: Remove dev_fmt definition
>       vfio/pci: Cleanup .probe() exit paths
> 
> 
>  drivers/vfio/pci/vfio_pci.c         |  390
> +++++++++++++++++++++++++++++++++--
>  drivers/vfio/pci/vfio_pci_private.h |   10 +
>  drivers/vfio/vfio.c                 |   20 +-
>  include/linux/vfio.h                |    4
>  include/uapi/linux/vfio.h           |   37 +++
>  5 files changed, 433 insertions(+), 28 deletions(-)


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH] cryptodev: version rte_cryptodev_info_get function
@ 2020-03-18 20:41  3% Arek Kusztal
  0 siblings, 0 replies; 200+ results
From: Arek Kusztal @ 2020-03-18 20:41 UTC (permalink / raw)
  To: dev; +Cc: akhil.goyal, fiona.trahe, thomas, Arek Kusztal

This patch adds versioned function rte_cryptodev_info_get.
Node 20.05 function works the same way it was working before.
Node 20.0 function strips capability added in 20.05 release
to prevent some issues with ABI policy. To do that new capability
array is allocated per device and returned to user instead of the
original array passed by PMD.

Signed-off-by: Arek Kusztal <arkadiuszx.kusztal@intel.com>
---
 lib/librte_cryptodev/rte_cryptodev.c           | 97 +++++++++++++++++++++++++-
 lib/librte_cryptodev/rte_cryptodev.h           | 12 +++-
 lib/librte_cryptodev/rte_cryptodev_version.map |  7 ++
 3 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 6d1d0e9..2d030ba 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -41,6 +41,9 @@
 #include "rte_cryptodev.h"
 #include "rte_cryptodev_pmd.h"
 
+#include <rte_compat.h>
+#include <rte_function_versioning.h>
+
 static uint8_t nb_drivers;
 
 static struct rte_cryptodev rte_crypto_devices[RTE_CRYPTO_MAX_DEVS];
@@ -56,6 +59,13 @@ static struct rte_cryptodev_global cryptodev_globals = {
 /* spinlock for crypto device callbacks */
 static rte_spinlock_t rte_cryptodev_cb_lock = RTE_SPINLOCK_INITIALIZER;
 
+static const struct rte_cryptodev_capabilities
+		cryptodev_undefined_capabilities[] = {
+		RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
+};
+
+struct rte_cryptodev_capabilities *capability_copies[RTE_CRYPTO_MAX_DEVS];
+uint8_t is_capability_checked[RTE_CRYPTO_MAX_DEVS];
 
 /**
  * The user application callback description.
@@ -999,6 +1009,13 @@ rte_cryptodev_close(uint8_t dev_id)
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -ENOTSUP);
 	retval = (*dev->dev_ops->dev_close)(dev);
 
+
+	if (capability_copies[dev_id]) {
+		free(capability_copies[dev_id]);
+		capability_copies[dev_id] = NULL;
+	}
+	is_capability_checked[dev_id] = 0;
+
 	if (retval < 0)
 		return retval;
 
@@ -1111,11 +1128,12 @@ rte_cryptodev_stats_reset(uint8_t dev_id)
 	(*dev->dev_ops->stats_reset)(dev);
 }
 
-
 void
-rte_cryptodev_info_get(uint8_t dev_id, struct rte_cryptodev_info *dev_info)
+rte_cryptodev_info_get_v20(uint8_t dev_id, struct rte_cryptodev_info *dev_info)
 {
 	struct rte_cryptodev *dev;
+	const struct rte_cryptodev_capabilities *capability;
+	uint8_t counter = 0;
 
 	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
 		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
@@ -1129,10 +1147,85 @@ rte_cryptodev_info_get(uint8_t dev_id, struct rte_cryptodev_info *dev_info)
 	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_infos_get);
 	(*dev->dev_ops->dev_infos_get)(dev, dev_info);
 
+	if (capability_copies[dev_id] == NULL) {
+		if (!is_capability_checked[dev_id]) {
+			uint8_t found_invalid_capa = 0;
+
+			for (capability = dev_info->capabilities;
+					capability->op != RTE_CRYPTO_OP_TYPE_UNDEFINED;
+					++capability, ++counter) {
+				if (capability->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
+						capability->sym.xform_type ==
+							RTE_CRYPTO_SYM_XFORM_AEAD
+						&& capability->sym.aead.algo >=
+						RTE_CRYPTO_AEAD_CHACHA20_POLY1305) {
+					found_invalid_capa = 1;
+					counter--;
+				}
+			}
+			is_capability_checked[dev_id] = 1;
+			if (found_invalid_capa) {
+				capability_copies[dev_id] = malloc(counter *
+					sizeof(struct rte_cryptodev_capabilities));
+				if (capability_copies[dev_id] == NULL) {
+					 /*
+					  * error case - no memory to store the trimmed list,
+					  * so have to return an empty list
+					  */
+					dev_info->capabilities =
+						cryptodev_undefined_capabilities;
+					is_capability_checked[dev_id] = 0;
+				} else {
+					counter = 0;
+					for (capability = dev_info->capabilities;
+							capability->op !=
+							RTE_CRYPTO_OP_TYPE_UNDEFINED;
+							capability++) {
+						if (!(capability->op ==
+								RTE_CRYPTO_OP_TYPE_SYMMETRIC
+								&& capability->sym.xform_type ==
+								RTE_CRYPTO_SYM_XFORM_AEAD
+								&& capability->sym.aead.algo >=
+								RTE_CRYPTO_AEAD_CHACHA20_POLY1305)) {
+							capability_copies[dev_id][counter++] =
+									*capability;
+						}
+					}
+					dev_info->capabilities =
+							capability_copies[dev_id];
+				}
+			}
+		}
+	} else
+		dev_info->capabilities = capability_copies[dev_id];
+
 	dev_info->driver_name = dev->device->driver->name;
 	dev_info->device = dev->device;
 }
+VERSION_SYMBOL(rte_cryptodev_info_get, _v20, 20.0);
+
+void
+rte_cryptodev_info_get_v2005(uint8_t dev_id, struct rte_cryptodev_info *dev_info)
+{
+	struct rte_cryptodev *dev;
 
+	if (!rte_cryptodev_pmd_is_valid_dev(dev_id)) {
+		CDEV_LOG_ERR("Invalid dev_id=%d", dev_id);
+		return;
+	}
+
+	dev = &rte_crypto_devices[dev_id];
+
+	memset(dev_info, 0, sizeof(struct rte_cryptodev_info));
+
+	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_infos_get);
+	(*dev->dev_ops->dev_infos_get)(dev, dev_info);
+
+	dev_info->driver_name = dev->device->driver->name;
+	dev_info->device = dev->device;
+}
+MAP_STATIC_SYMBOL(void rte_cryptodev_info_get(uint8_t dev_id,
+		struct rte_cryptodev_info *dev_info), rte_cryptodev_info_get_v2005);
 
 int
 rte_cryptodev_callback_register(uint8_t dev_id,
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 437b8a9..06ce2f2 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -24,6 +24,9 @@ extern "C" {
 #include <rte_common.h>
 #include <rte_config.h>
 
+#include <rte_compat.h>
+#include <rte_function_versioning.h>
+
 extern const char **rte_cyptodev_names;
 
 /* Logging Macros */
@@ -758,7 +761,14 @@ rte_cryptodev_stats_reset(uint8_t dev_id);
  * the last valid element has it's op field set to
  * RTE_CRYPTO_OP_TYPE_UNDEFINED.
  */
-extern void
+void
+rte_cryptodev_info_get_v20(uint8_t dev_id, struct rte_cryptodev_info *dev_info);
+
+void
+rte_cryptodev_info_get_v2005(uint8_t dev_id, struct rte_cryptodev_info *dev_info);
+BIND_DEFAULT_SYMBOL(rte_cryptodev_info_get, _v2005, 20.05);
+
+void
 rte_cryptodev_info_get(uint8_t dev_id, struct rte_cryptodev_info *dev_info);
 
 
diff --git a/lib/librte_cryptodev/rte_cryptodev_version.map b/lib/librte_cryptodev/rte_cryptodev_version.map
index 6e41b4b..d6c945a 100644
--- a/lib/librte_cryptodev/rte_cryptodev_version.map
+++ b/lib/librte_cryptodev/rte_cryptodev_version.map
@@ -58,6 +58,13 @@ DPDK_20.0 {
 	local: *;
 };
 
+
+DPDK_20.05 {
+	global:
+	rte_cryptodev_info_get;
+} DPDK_20.0;
+
+
 EXPERIMENTAL {
 	global:
 
-- 
2.1.0


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
  2020-03-17 15:10  4%                 ` Thomas Monjalon
@ 2020-03-17 19:10  4%                   ` Kusztal, ArkadiuszX
  0 siblings, 0 replies; 200+ results
From: Kusztal, ArkadiuszX @ 2020-03-17 19:10 UTC (permalink / raw)
  To: Thomas Monjalon, Trahe, Fiona
  Cc: David Marchand, nhorman, bluca, ktraynor, Ray Kinsella, dev,
	Akhil Goyal, Yigit, Ferruh, Ananyev, Konstantin, dev,
	Anoob Joseph, Richardson, Bruce, Mcnamara, John, dodji,
	Andrew Rybchenko, aconole, Trahe, Fiona



> -----Original Message-----
> From: Thomas Monjalon <thomas@monjalon.net>
> Sent: Tuesday, March 17, 2020 4:10 PM
> To: Trahe, Fiona <fiona.trahe@intel.com>; Kusztal, ArkadiuszX
> <arkadiuszx.kusztal@intel.com>
> Cc: David Marchand <david.marchand@redhat.com>;
> nhorman@tuxdriver.com; bluca@debian.org; ktraynor@redhat.com; Ray
> Kinsella <mdr@ashroe.eu>; dev@dpdk.org; Akhil Goyal
> <akhil.goyal@nxp.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev,
> Konstantin <konstantin.ananyev@intel.com>; dev@dpdk.org; Anoob Joseph
> <anoobj@marvell.com>; Richardson, Bruce <bruce.richardson@intel.com>;
> Mcnamara, John <john.mcnamara@intel.com>; dodji@seketeli.net; Andrew
> Rybchenko <arybchenko@solarflare.com>; aconole@redhat.com; Trahe,
> Fiona <fiona.trahe@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
> 
> 17/03/2020 14:27, Kusztal, ArkadiuszX:
> > Hi Thomas,
> >
> > > -----Original Message-----
> > > From: Thomas Monjalon <thomas@monjalon.net>
> > > Sent: Monday, March 16, 2020 2:09 PM
> > > To: Trahe, Fiona <fiona.trahe@intel.com>
> > > Cc: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>; David
> > > Marchand <david.marchand@redhat.com>; nhorman@tuxdriver.com;
> > > bluca@debian.org; ktraynor@redhat.com; Ray Kinsella
> <mdr@ashroe.eu>;
> > > dev@dpdk.org; Akhil Goyal <akhil.goyal@nxp.com>; Yigit, Ferruh
> > > <ferruh.yigit@intel.com>; Ananyev, Konstantin
> > > <konstantin.ananyev@intel.com>; dev@dpdk.org; Anoob Joseph
> > > <anoobj@marvell.com>; Richardson, Bruce
> > > <bruce.richardson@intel.com>; Mcnamara, John
> > > <john.mcnamara@intel.com>; dodji@seketeli.net; Andrew Rybchenko
> > > <arybchenko@solarflare.com>; aconole@redhat.com; Trahe, Fiona
> > > <fiona.trahe@intel.com>
> > > Subject: Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
> > >
> > > 16/03/2020 13:57, Trahe, Fiona:
> > > > From: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>
> > > > > > > > The patch we're working on will provide two versions of
> > > > > > > > rte_cryptodev_info_get(), both call the same PMD function
> > > > > > > > from the
> > > > > > dev_ops info_get fn ptr.
> > > > > > > > The default version operates s as normal, the 19.11
> > > > > > > > version searches through the list returned by the PMD,
> > > > > > > > looking for sym.aead.algo = ChaChaPoly, it needs to strip
> > > > > > > > it from
> > > > > > > the list.
> > > > > > > > As PMDs just pass a ptr to their capabilities list ( it
> > > > > > > > isn't a linked list, but an array with an end marker  =
> > > > > > > > RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST) if the API layer
> > > > > > > > detects Chacha it must allocate some space and store a
> > > > > > > > local copy of the trimmed
> > > > > > list. This must be stored only once per device.
> > > > >
> > > > > [Arek] The problem with this solution is that we need to allocate
> memory.
> > > > > So the question is how to handle unlikely case of malloc error
> > > > > when we operate inside void function rte_cryptodev_info_get?
> > > > > And even if we would pass somehow error condition to the caller
> > > > > then
> > > what to do is another question.
> > > >
> > > > [Fiona] Quick recap: To avoid breaking ABI, we must return a set
> > > > of capabilities with/without ChaChaPoly depending on the appl
> > > > version. To resolve this, within the rte_cryptodev layer, we
> > > > propose to inspect the
> > > capabilities returned by PMD and strip ChaCha if it exists.
> > > > In that case memory for the new trimmed capabilities array has to
> > > > be
> > > malloced by the lib.
> > >
> > > What happens if the capability is removed from the original
> > > capabilities input?
> > >
> > > > All good, except how to handle a malloc fail is yet another API
> > > > breakage as
> > > rte_cryptodev_get_info() returns void.
> > > > We propose to return an empty capability list, i.e. a list with
> > > > only the END element (which can be done without malloc) in this
> > > > corner case of
> > > a corner case.
> > > > Anyone see any issue with this?
> > >
> > > How can we use the feature if it is not advertised in capabilities?
> > What Fiona meant is that empty capability would indicate error condition in
> this case. That's why she asked if you ok with this API breakage.
> 
> Sorry I'm lost.
> Please could you show what would be the usage?
> 
So this case looks more or less like that:
There are two versions of `rte_cryptodev_info_get`

rte_cryptodev_info_get_v20 (versioned)
rte_cryptodev_info_get_v2005 (new default symbol)

Default version works normally as it will be called only by app build with 20.05 version.

When prior to 20.05 app calls `rte_cryptodev_info_get` version v20 is called. This function will remove Chacha Poly from capabilities, but to achieve this we need to get some memory to store `new` set of capabilities per device (without Chacha). So:
new_capability[dev_id] = malloc( (num_of_capabilies - 1 (chacha)) * sizeof(struct rte_cryptodev_capabilities))
The small problem is how to handle malloc error:
If (new_capability[dev_id] == NULL) {
	/* What to do now as rte_cryptodev_info_get is void function, and API does not say anything about error condition */
/*So Fiona suggestion above is to inform user of an error by doing this: */
	dev_info->capabilities = cryptodev_undefined_capabilities;

/* Where 
static const struct rte_cryptodev_capabilities cryptodev_undefined_capabilities[] = {
		RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()

}; */
}
Sizeof rte_cryptodev_capabilities is 38 bytes, padded to 40. So properly constructed capabilities can take at most 1920 bytes.  No system should ever fail doing that though iam not an expert. Other option could probably be to preallocate this memory. This is how I understand that.

Another question is can something like that be done if API comments of `rte_cryptodev_info_get` function does not say anything about any potential error?

Regards,
Arek







^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
  2020-03-17 13:27  4%               ` Kusztal, ArkadiuszX
@ 2020-03-17 15:10  4%                 ` Thomas Monjalon
  2020-03-17 19:10  4%                   ` Kusztal, ArkadiuszX
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-03-17 15:10 UTC (permalink / raw)
  To: Trahe, Fiona, Kusztal, ArkadiuszX
  Cc: David Marchand, nhorman, bluca, ktraynor, Ray Kinsella, dev,
	Akhil Goyal, Yigit, Ferruh, Ananyev, Konstantin, dev,
	Anoob Joseph, Richardson, Bruce, Mcnamara, John, dodji,
	Andrew Rybchenko, aconole, Trahe, Fiona

17/03/2020 14:27, Kusztal, ArkadiuszX:
> Hi Thomas,
> 
> > -----Original Message-----
> > From: Thomas Monjalon <thomas@monjalon.net>
> > Sent: Monday, March 16, 2020 2:09 PM
> > To: Trahe, Fiona <fiona.trahe@intel.com>
> > Cc: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>; David Marchand
> > <david.marchand@redhat.com>; nhorman@tuxdriver.com;
> > bluca@debian.org; ktraynor@redhat.com; Ray Kinsella <mdr@ashroe.eu>;
> > dev@dpdk.org; Akhil Goyal <akhil.goyal@nxp.com>; Yigit, Ferruh
> > <ferruh.yigit@intel.com>; Ananyev, Konstantin
> > <konstantin.ananyev@intel.com>; dev@dpdk.org; Anoob Joseph
> > <anoobj@marvell.com>; Richardson, Bruce <bruce.richardson@intel.com>;
> > Mcnamara, John <john.mcnamara@intel.com>; dodji@seketeli.net; Andrew
> > Rybchenko <arybchenko@solarflare.com>; aconole@redhat.com; Trahe,
> > Fiona <fiona.trahe@intel.com>
> > Subject: Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
> > 
> > 16/03/2020 13:57, Trahe, Fiona:
> > > From: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>
> > > > > > > The patch we're working on will provide two versions of
> > > > > > > rte_cryptodev_info_get(), both call the same PMD function from
> > > > > > > the
> > > > > dev_ops info_get fn ptr.
> > > > > > > The default version operates s as normal, the 19.11 version
> > > > > > > searches through the list returned by the PMD, looking for
> > > > > > > sym.aead.algo = ChaChaPoly, it needs to strip it from
> > > > > > the list.
> > > > > > > As PMDs just pass a ptr to their capabilities list ( it isn't
> > > > > > > a linked list, but an array with an end marker  =
> > > > > > > RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST) if the API layer
> > > > > > > detects Chacha it must allocate some space and store a local
> > > > > > > copy of the trimmed
> > > > > list. This must be stored only once per device.
> > > >
> > > > [Arek] The problem with this solution is that we need to allocate memory.
> > > > So the question is how to handle unlikely case of malloc error when
> > > > we operate inside void function rte_cryptodev_info_get?
> > > > And even if we would pass somehow error condition to the caller then
> > what to do is another question.
> > >
> > > [Fiona] Quick recap: To avoid breaking ABI, we must return a set of
> > > capabilities with/without ChaChaPoly depending on the appl version. To
> > > resolve this, within the rte_cryptodev layer, we propose to inspect the
> > capabilities returned by PMD and strip ChaCha if it exists.
> > > In that case memory for the new trimmed capabilities array has to be
> > malloced by the lib.
> > 
> > What happens if the capability is removed from the original capabilities
> > input?
> > 
> > > All good, except how to handle a malloc fail is yet another API breakage as
> > rte_cryptodev_get_info() returns void.
> > > We propose to return an empty capability list, i.e. a list with only
> > > the END element (which can be done without malloc) in this corner case of
> > a corner case.
> > > Anyone see any issue with this?
> > 
> > How can we use the feature if it is not advertised in capabilities?
> What Fiona meant is that empty capability would indicate error condition in this case. That's why she asked if you ok with this API breakage.

Sorry I'm lost.
Please could you show what would be the usage?



^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
  2020-03-16 13:09  4%             ` Thomas Monjalon
@ 2020-03-17 13:27  4%               ` Kusztal, ArkadiuszX
  2020-03-17 15:10  4%                 ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Kusztal, ArkadiuszX @ 2020-03-17 13:27 UTC (permalink / raw)
  To: Thomas Monjalon, Trahe, Fiona
  Cc: David Marchand, nhorman, bluca, ktraynor, Ray Kinsella, dev,
	Akhil Goyal, Yigit, Ferruh, Ananyev, Konstantin, dev,
	Anoob Joseph, Richardson, Bruce, Mcnamara, John, dodji,
	Andrew Rybchenko, aconole, Trahe, Fiona

Hi Thomas,

> -----Original Message-----
> From: Thomas Monjalon <thomas@monjalon.net>
> Sent: Monday, March 16, 2020 2:09 PM
> To: Trahe, Fiona <fiona.trahe@intel.com>
> Cc: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>; David Marchand
> <david.marchand@redhat.com>; nhorman@tuxdriver.com;
> bluca@debian.org; ktraynor@redhat.com; Ray Kinsella <mdr@ashroe.eu>;
> dev@dpdk.org; Akhil Goyal <akhil.goyal@nxp.com>; Yigit, Ferruh
> <ferruh.yigit@intel.com>; Ananyev, Konstantin
> <konstantin.ananyev@intel.com>; dev@dpdk.org; Anoob Joseph
> <anoobj@marvell.com>; Richardson, Bruce <bruce.richardson@intel.com>;
> Mcnamara, John <john.mcnamara@intel.com>; dodji@seketeli.net; Andrew
> Rybchenko <arybchenko@solarflare.com>; aconole@redhat.com; Trahe,
> Fiona <fiona.trahe@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
> 
> 16/03/2020 13:57, Trahe, Fiona:
> > From: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>
> > > > > > The patch we're working on will provide two versions of
> > > > > > rte_cryptodev_info_get(), both call the same PMD function from
> > > > > > the
> > > > dev_ops info_get fn ptr.
> > > > > > The default version operates s as normal, the 19.11 version
> > > > > > searches through the list returned by the PMD, looking for
> > > > > > sym.aead.algo = ChaChaPoly, it needs to strip it from
> > > > > the list.
> > > > > > As PMDs just pass a ptr to their capabilities list ( it isn't
> > > > > > a linked list, but an array with an end marker  =
> > > > > > RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST) if the API layer
> > > > > > detects Chacha it must allocate some space and store a local
> > > > > > copy of the trimmed
> > > > list. This must be stored only once per device.
> > >
> > > [Arek] The problem with this solution is that we need to allocate memory.
> > > So the question is how to handle unlikely case of malloc error when
> > > we operate inside void function rte_cryptodev_info_get?
> > > And even if we would pass somehow error condition to the caller then
> what to do is another question.
> >
> > [Fiona] Quick recap: To avoid breaking ABI, we must return a set of
> > capabilities with/without ChaChaPoly depending on the appl version. To
> > resolve this, within the rte_cryptodev layer, we propose to inspect the
> capabilities returned by PMD and strip ChaCha if it exists.
> > In that case memory for the new trimmed capabilities array has to be
> malloced by the lib.
> 
> What happens if the capability is removed from the original capabilities
> input?
> 
> > All good, except how to handle a malloc fail is yet another API breakage as
> rte_cryptodev_get_info() returns void.
> > We propose to return an empty capability list, i.e. a list with only
> > the END element (which can be done without malloc) in this corner case of
> a corner case.
> > Anyone see any issue with this?
> 
> How can we use the feature if it is not advertised in capabilities?
What Fiona meant is that empty capability would indicate error condition in this case. That's why she asked if you ok with this API breakage.
> 
> 


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
  2020-03-16 12:57  8%           ` Trahe, Fiona
@ 2020-03-16 13:09  4%             ` Thomas Monjalon
  2020-03-17 13:27  4%               ` Kusztal, ArkadiuszX
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-03-16 13:09 UTC (permalink / raw)
  To: Trahe, Fiona
  Cc: Kusztal, ArkadiuszX, David Marchand, nhorman, bluca, ktraynor,
	Ray Kinsella, dev, Akhil Goyal, Yigit, Ferruh, Ananyev,
	Konstantin, dev, Anoob Joseph, Richardson, Bruce, Mcnamara, John,
	dodji, Andrew Rybchenko, aconole, Trahe, Fiona

16/03/2020 13:57, Trahe, Fiona:
> From: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>
> > > > > The patch we're working on will provide two versions of
> > > > > rte_cryptodev_info_get(), both call the same PMD function from the
> > > dev_ops info_get fn ptr.
> > > > > The default version operates s as normal, the 19.11 version searches
> > > > > through the list returned by the PMD, looking for sym.aead.algo =
> > > > > ChaChaPoly, it needs to strip it from
> > > > the list.
> > > > > As PMDs just pass a ptr to their capabilities list ( it isn't a
> > > > > linked list, but an array with an end marker  =
> > > > > RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST) if the API layer detects
> > > > > Chacha it must allocate some space and store a local copy of the trimmed
> > > list. This must be stored only once per device.
> > 
> > [Arek] The problem with this solution is that we need to allocate memory.
> > So the question is how to handle unlikely case of malloc error when we operate inside void function
> > rte_cryptodev_info_get?
> > And even if we would pass somehow error condition to the caller then what to do is another question.
> 
> [Fiona] Quick recap: To avoid breaking ABI, we must return a set of capabilities with/without ChaChaPoly
> depending on the appl version. To resolve this, within the rte_cryptodev layer, we propose to 
> inspect the capabilities returned by PMD and strip ChaCha if it exists.
> In that case memory for the new trimmed capabilities array has to be malloced by the lib.

What happens if the capability is removed from the original capabilities input?

> All good, except how to handle a malloc fail is yet another API breakage as rte_cryptodev_get_info() returns void.
> We propose to return an empty capability list, i.e. a list with only the END element (which can be done without malloc) 
> in this corner case of a corner case.
> Anyone see any issue with this?

How can we use the feature if it is not advertised in capabilities?




^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 4/4] add ABI checks
  @ 2020-03-16 12:57  8%           ` Trahe, Fiona
  2020-03-16 13:09  4%             ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Trahe, Fiona @ 2020-03-16 12:57 UTC (permalink / raw)
  To: Kusztal, ArkadiuszX, Thomas Monjalon
  Cc: David Marchand, nhorman, bluca, ktraynor, Ray Kinsella, dev,
	Akhil Goyal, Yigit, Ferruh, Ananyev, Konstantin, dev,
	Anoob Joseph, Richardson, Bruce, Mcnamara, John, dodji,
	Andrew Rybchenko, aconole, Trahe, Fiona

Hi,

> -----Original Message-----
> From: Kusztal, ArkadiuszX <arkadiuszx.kusztal@intel.com>
> Sent: Thursday, February 13, 2020 2:51 PM
> To: Trahe, Fiona <fiona.trahe@intel.com>; Thomas Monjalon <thomas@monjalon.net>
> Cc: David Marchand <david.marchand@redhat.com>; nhorman@tuxdriver.com; bluca@debian.org;
> ktraynor@redhat.com; Ray Kinsella <mdr@ashroe.eu>; dev@dpdk.org; Akhil Goyal
> <akhil.goyal@nxp.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin
> <konstantin.ananyev@intel.com>; dev@dpdk.org; Anoob Joseph <anoobj@marvell.com>;
> Richardson, Bruce <bruce.richardson@intel.com>; Mcnamara, John <john.mcnamara@intel.com>;
> dodji@seketeli.net; Andrew Rybchenko <arybchenko@solarflare.com>; aconole@redhat.com
> Subject: RE: [dpdk-dev] [PATCH v2 4/4] add ABI checks
> 
> Hi,
> 
> Two comments from me,
> 
> > > > The patch we're working on will provide two versions of
> > > > rte_cryptodev_info_get(), both call the same PMD function from the
> > dev_ops info_get fn ptr.
> > > > The default version operates s as normal, the 19.11 version searches
> > > > through the list returned by the PMD, looking for sym.aead.algo =
> > > > ChaChaPoly, it needs to strip it from
> > > the list.
> > > > As PMDs just pass a ptr to their capabilities list ( it isn't a
> > > > linked list, but an array with an end marker  =
> > > > RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST) if the API layer detects
> > > > Chacha it must allocate some space and store a local copy of the trimmed
> > list. This must be stored only once per device.
> [Arek] The problem with this solution is that we need to allocate memory.
> So the question is how to handle unlikely case of malloc error when we operate inside void function
> rte_cryptodev_info_get?
> And even if we would pass somehow error condition to the caller then what to do is another question.
[Fiona] Quick recap: To avoid breaking ABI, we must return a set of capabilities with/without ChaChaPoly
depending on the appl version. To resolve this, within the rte_cryptodev layer, we propose to 
inspect the capabilities returned by PMD and strip ChaCha if it exists.
In that case memory for the new trimmed capabilities array has to be malloced by the lib.
All good, except how to handle a malloc fail is yet another API breakage as rte_cryptodev_get_info() returns void.
We propose to return an empty capability list, i.e. a list with only the END element (which can be done without malloc) 
in this corner case of a corner case.
Anyone see any issue with this?

> 
> > >
> > > I don't understand what you have to store.
> > > Can't you just set the algo to 0 if it is ChaCha?
> > [Fiona] it returns a pointer to data in the PMD domain, which the API couldn't
> > and shouldn't overwrite, e.g.
> > static const struct rte_cryptodev_capabilities qat_gen3_sym_capabilities[]
> Should we print user some information
> >
> > >
> > > > This versioning will apply to any PMD which wants to take advantage
> > > > of the new API between now and
> > > 20.11.
> > > >
> > > > Note, I expect the ABI checker tools will still complain of ABI
> > > > breakage as the LIST_END value will still
> > > change.
> > >
> > > Right, you need to update the ignore list for the tool.
> > >
> > > > We are also reviewing all other cryptodev APIs in case there is any other
> > API which needs versioning.
> > > >
> > > > Anyone see any problem with this approach?
> > >
> > > The other issue is with all other functions accepting this enum as input.
> > > We should continue returning an error if getting Chacha as input with
> > > 19.11 version of these functions.
> > > But I would tend to consider this small ABI breakage can be ignored as
> > > it is in the error path.
> > [Fiona] The QAT PMD tests for and handles this error. I expect other PMDs
> > do too.
> [Arek] - Yes, it is error path but on the other hand we explicitly specify what value we will return when
> calling
> rte_cryptodev_sym_session_init so caller may expect EINVAL when wrong algorithm value selected
> (usually it probably will be ENOTSUP).
> In this case when setting 3 (LIST_END) on 19.11 app and linking against 20.02 (assuming with Chacha)
> shared build, caller would get success on return and fully set chacha session,
> which will probably result in undefined behavior.
> So shouldn't this function be versioned as well then?
[Fiona] I would agree with Tomas to ignore this small ABI break, as it is already an error case
if a appl is passing in a bad value for the algorithm. Even if it does return SUCCESS, instead of ENOTSUP,
 what behaviour could the application be expecting with a session using LIST_END as an algo?



> 
> Regards,
> Arek
> 
> 


^ permalink raw reply	[relevance 8%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  2020-03-16  7:43  0%                 ` Tonghao Zhang
@ 2020-03-16  7:55  0%                   ` Olivier Matz
  0 siblings, 0 replies; 200+ results
From: Olivier Matz @ 2020-03-16  7:55 UTC (permalink / raw)
  To: Tonghao Zhang
  Cc: David Marchand, Andrew Rybchenko, Jerin Jacob, dpdk-dev,
	Gage Eads, Artem V. Andreev, Jerin Jacob, Nithin Dabilpuram,
	Vamsi Attunuru, Hemant Agrawal, Burakov, Anatoly,
	Bruce Richardson

Hi Tonghao,

On Mon, Mar 16, 2020 at 03:43:40PM +0800, Tonghao Zhang wrote:
> On Mon, Mar 9, 2020 at 9:15 PM David Marchand <david.marchand@redhat.com> wrote:
> >
> > On Mon, Mar 9, 2020 at 9:56 AM Tonghao Zhang <xiangxia.m.yue@gmail.com> wrote:
> > > On Mon, Mar 9, 2020 at 4:27 PM Olivier Matz <olivier.matz@6wind.com> wrote:
> > > > The fact that the ops index changes during mempool driver lifetime is
> > > > indeed frightening, especially knowning that this is a dynamic
> > > > registration that could happen at any moment in the life of the
> > > > application. Also, breaking the ABI is not desirable.
> > > That solution is better.
> > >
> > > > Let me try to propose something else to solve your issue:
> > > >
> > > > 1/ At init, the primary process allocates a struct in shared memory
> > > >    (named memzone):
> > > >
> > > >    struct rte_mempool_shared_ops {
> > > >      size_t num_mempool_ops;
> > > >      struct {
> > > >        char name[RTE_MEMPOOL_OPS_NAMESIZE];
> > > >      } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];
> > > >      char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];
> > > >      rte_spinlock_t mempool;
> > > >    }
> > > >
> > > > 2/ When we register a mempool ops, we first get a name and id from the
> > > >    shared struct: with the lock held, lookup for the registered name and
> > > >    return its index, else get the last id and copy the name in the struct.
> > > >
> > > > 3/ Then do as before (in the per-process global table), except that we
> > > >    reuse the registered id.
> > > >
> > > > We can remove the num_ops field from rte_mempool_ops_table.
> > > >
> > > > Thoughts?
> >
> > It seems better, just adding Anatoly and Bruce who know more about multiprocess.
> >
> > Tonghao, could you add a unit test to exhibit the issue as part of this work?
> >
> > Thanks.
> Hi Olivier
> any progress?will apply this patch or wait your patch?

Sorry if it wasn't clear, but my proposition was just an idea, I have no
time yet to work on it. Feel free to implement it by yourself, and I'll
help to review the patches.

Thanks,
Olivier

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  2020-03-09 13:15  0%               ` David Marchand
@ 2020-03-16  7:43  0%                 ` Tonghao Zhang
  2020-03-16  7:55  0%                   ` Olivier Matz
  0 siblings, 1 reply; 200+ results
From: Tonghao Zhang @ 2020-03-16  7:43 UTC (permalink / raw)
  To: David Marchand
  Cc: Olivier Matz, Andrew Rybchenko, Jerin Jacob, dpdk-dev, Gage Eads,
	Artem V. Andreev, Jerin Jacob, Nithin Dabilpuram, Vamsi Attunuru,
	Hemant Agrawal, Burakov, Anatoly, Bruce Richardson

On Mon, Mar 9, 2020 at 9:15 PM David Marchand <david.marchand@redhat.com> wrote:
>
> On Mon, Mar 9, 2020 at 9:56 AM Tonghao Zhang <xiangxia.m.yue@gmail.com> wrote:
> > On Mon, Mar 9, 2020 at 4:27 PM Olivier Matz <olivier.matz@6wind.com> wrote:
> > > The fact that the ops index changes during mempool driver lifetime is
> > > indeed frightening, especially knowning that this is a dynamic
> > > registration that could happen at any moment in the life of the
> > > application. Also, breaking the ABI is not desirable.
> > That solution is better.
> >
> > > Let me try to propose something else to solve your issue:
> > >
> > > 1/ At init, the primary process allocates a struct in shared memory
> > >    (named memzone):
> > >
> > >    struct rte_mempool_shared_ops {
> > >      size_t num_mempool_ops;
> > >      struct {
> > >        char name[RTE_MEMPOOL_OPS_NAMESIZE];
> > >      } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];
> > >      char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];
> > >      rte_spinlock_t mempool;
> > >    }
> > >
> > > 2/ When we register a mempool ops, we first get a name and id from the
> > >    shared struct: with the lock held, lookup for the registered name and
> > >    return its index, else get the last id and copy the name in the struct.
> > >
> > > 3/ Then do as before (in the per-process global table), except that we
> > >    reuse the registered id.
> > >
> > > We can remove the num_ops field from rte_mempool_ops_table.
> > >
> > > Thoughts?
>
> It seems better, just adding Anatoly and Bruce who know more about multiprocess.
>
> Tonghao, could you add a unit test to exhibit the issue as part of this work?
>
> Thanks.
Hi Olivier
any progress?will apply this patch or wait your patch?

>
> --
> David Marchand
>


-- 
Thanks,
Tonghao

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v3 2/7] net/ice: add the DCF hardware initialization
  @ 2020-03-16  5:52  1%   ` Haiyue Wang
  0 siblings, 0 replies; 200+ results
From: Haiyue Wang @ 2020-03-16  5:52 UTC (permalink / raw)
  To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
  Cc: wei.zhao1, Haiyue Wang

Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.

Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
 doc/guides/nics/ice.rst                |  47 +++
 doc/guides/nics/img/ice_dcf.png        | Bin 0 -> 39168 bytes
 doc/guides/rel_notes/release_20_05.rst |   5 +
 drivers/common/Makefile                |   1 +
 drivers/net/ice/Makefile               |   5 +
 drivers/net/ice/ice_dcf.c              | 474 +++++++++++++++++++++++++
 drivers/net/ice/ice_dcf.h              |  52 +++
 drivers/net/ice/ice_dcf_ethdev.c       | 317 +++++++++++++++++
 drivers/net/ice/ice_dcf_ethdev.h       |  24 ++
 drivers/net/ice/meson.build            |   7 +-
 mk/rte.app.mk                          |   1 +
 11 files changed, 931 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 drivers/net/ice/ice_dcf.c
 create mode 100644 drivers/net/ice/ice_dcf.h
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.h

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
 
 The APPs based on DPDK should avoid providing such packets.
 
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+   DCF Communication flow.
+
+#. Create the VFs::
+
+      echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+      ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0,  and run testpmd with 'cap=dcf' devarg::
+
+      testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+      tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+      flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+      dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+      sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+      192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+      iface="enp24s0f0", count=10)
+
 Sample Application Notes
 ------------------------
 
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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

literal 0
HcmV?d00001

diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
 
   * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
 
+* **Updated the Intel ice driver.**
+
+  Updated the Intel ice driver with new features and improvements, including:
+
+  * Added support for DCF (Device Config Function) feature.
 
 Removed Items
 -------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
 endif
 
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifneq (,$(findstring y,$(IAVF-y)))
 DIRS-y += iavf
 endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
 LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
 
 EXPORT_MAP := rte_pmd_ice_version.map
 
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
 
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
 
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN     32
+#define ICE_DCF_AQ_BUF_SZ  4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME  2   /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ	\
+	(sizeof(struct virtchnl_vf_resource) +	\
+		IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *req_msg, uint16_t req_msglen)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+				      req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+			    uint16_t *rsp_msglen)
+{
+	struct iavf_arq_event_info event;
+	enum virtchnl_ops v_op;
+	int i = 0;
+	int err;
+
+	event.buf_len = rsp_buflen;
+	event.msg_buf = rsp_msgbuf;
+
+	do {
+		err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+		if (err != IAVF_SUCCESS)
+			goto again;
+
+		v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+		if (v_op != op)
+			goto again;
+
+		if (rsp_msglen != NULL)
+			*rsp_msglen = event.msg_len;
+		return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	cmd->v_ret = IAVF_ERR_NOT_READY;
+	cmd->rsp_msglen = 0;
+	cmd->pending = 1;
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf,
+				      cmd->v_op, IAVF_SUCCESS,
+				      cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+	struct dcf_virtchnl_cmd *cmd;
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+	uint16_t aq_op;
+
+	aq_op = rte_le_to_cpu_16(info->desc.opcode);
+	if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+		PMD_DRV_LOG(ERR,
+			    "Request %u is not supported yet", aq_op);
+		return;
+	}
+
+	v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+	if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+		return;
+
+	v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+		if (cmd->v_op == v_op && cmd->pending) {
+			cmd->v_ret = v_ret;
+			cmd->rsp_msglen = RTE_MIN(info->msg_len,
+						  cmd->rsp_buflen);
+			if (likely(cmd->rsp_msglen != 0))
+				rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+					   cmd->rsp_msglen);
+
+			/* prevent compiler reordering */
+			rte_compiler_barrier();
+			cmd->pending = 0;
+			break;
+		}
+	}
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+	struct iavf_arq_event_info info;
+	uint16_t pending = 1;
+	int ret;
+
+	info.buf_len = ICE_DCF_AQ_BUF_SZ;
+	info.msg_buf = hw->arq_buf;
+
+	while (pending) {
+		ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+		if (ret != IAVF_SUCCESS)
+			break;
+
+		ice_dcf_aq_cmd_handle(hw, &info);
+	}
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START	1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START	1
+	struct virtchnl_version_info version, *pver;
+	int err;
+
+	version.major = VIRTCHNL_VERSION_MAJOR;
+	version.minor = VIRTCHNL_VERSION_MINOR;
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)&version, sizeof(version));
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+		return err;
+	}
+
+	pver = &hw->virtchnl_version;
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)pver, sizeof(*pver), NULL);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG,
+		     "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+	if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+	    (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+	     pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+		PMD_INIT_LOG(ERR,
+			     "VIRTCHNL API version should not be lower than (%u.%u)",
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+		return -1;
+	} else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+		   (pver->major == VIRTCHNL_VERSION_MAJOR &&
+		    pver->minor > VIRTCHNL_VERSION_MINOR)) {
+		PMD_INIT_LOG(ERR,
+			     "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+			     pver->major, pver->minor,
+			     VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+	return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+	uint32_t caps;
+	int err, i;
+
+	caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+	       VF_BASE_MODE_OFFLOADS;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)&caps, sizeof(caps));
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)hw->vf_res,
+					  ICE_DCF_VF_RES_BUF_SZ, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+		return -1;
+	}
+
+	iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+	hw->vsi_res = NULL;
+	for (i = 0; i < hw->vf_res->num_vsis; i++) {
+		if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+			hw->vsi_res = &hw->vf_res->vsi_res[i];
+	}
+
+	if (!hw->vsi_res) {
+		PMD_DRV_LOG(ERR, "no LAN VSI found");
+		return -1;
+	}
+
+	hw->vsi_id = hw->vsi_res->vsi_id;
+	PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+	return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT       50
+	struct iavf_hw *avf = &hw->avf;
+	int i, reset;
+
+	for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+		reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+					IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+		reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+		if (reset == VIRTCHNL_VFR_VFACTIVE ||
+		    reset == VIRTCHNL_VFR_COMPLETED)
+			break;
+
+		rte_delay_ms(20);
+	}
+
+	if (i >= ICE_DCF_RESET_WAIT_CNT)
+		return -1;
+
+	return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+	struct ice_dcf_hw *hw = param;
+
+	ice_dcf_disable_irq0(hw);
+
+	ice_dcf_handle_virtchnl_msg(hw);
+
+	ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+			     struct dcf_virtchnl_cmd *cmd)
+{
+	int i = 0;
+	int err;
+
+	if ((cmd->req_msg && !cmd->req_msglen) ||
+	    (!cmd->req_msg && cmd->req_msglen) ||
+	    (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+	    (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+		return -EINVAL;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_vc_cmd_set(hw, cmd);
+
+	err = ice_dcf_vc_cmd_send(hw, cmd);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+		goto ret;
+	}
+
+	do {
+		if (!cmd->pending)
+			break;
+
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	if (cmd->v_ret != IAVF_SUCCESS) {
+		err = -1;
+		PMD_DRV_LOG(ERR,
+			    "No response (%d times) or return failure (%d) for cmd %d",
+			    i, cmd->v_ret, cmd->v_op);
+	}
+
+ret:
+	ice_dcf_aq_cmd_clear(hw, cmd);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+	return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	int ret;
+
+	hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+	hw->avf.back = hw;
+
+	hw->avf.bus.bus_id = pci_dev->addr.bus;
+	hw->avf.bus.device = pci_dev->addr.devid;
+	hw->avf.bus.func = pci_dev->addr.function;
+
+	hw->avf.device_id = pci_dev->id.device_id;
+	hw->avf.vendor_id = pci_dev->id.vendor_id;
+	hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+	hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+	hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+	rte_spinlock_init(&hw->vc_cmd_send_lock);
+	rte_spinlock_init(&hw->vc_cmd_queue_lock);
+	TAILQ_INIT(&hw->vc_cmd_queue);
+
+	hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+	if (hw->arq_buf == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+		goto err;
+	}
+
+	ret = iavf_set_mac_type(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+		goto err;
+	}
+
+	ret = ice_dcf_check_reset_done(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "VF is still resetting");
+		goto err;
+	}
+
+	ret = iavf_init_adminq(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+		goto err;
+	}
+
+	if (ice_dcf_init_check_api_version(hw)) {
+		PMD_INIT_LOG(ERR, "check_api version failed");
+		goto err_api;
+	}
+
+	hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+	if (hw->vf_res == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+		goto err_api;
+	}
+
+	if (ice_dcf_get_vf_resource(hw)) {
+		PMD_INIT_LOG(ERR, "Failed to get VF resource");
+		goto err_alloc;
+	}
+
+	rte_intr_callback_register(&pci_dev->intr_handle,
+				   ice_dcf_dev_interrupt_handler, hw);
+	rte_intr_enable(&pci_dev->intr_handle);
+	ice_dcf_enable_irq0(hw);
+
+	return 0;
+
+err_alloc:
+	rte_free(hw->vf_res);
+err_api:
+	iavf_shutdown_adminq(&hw->avf);
+err:
+	rte_free(hw->arq_buf);
+
+	return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+	ice_dcf_disable_irq0(hw);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     ice_dcf_dev_interrupt_handler, hw);
+
+	iavf_shutdown_adminq(&hw->avf);
+
+	rte_free(hw->arq_buf);
+	rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+	TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+
+	uint16_t req_msglen;
+	uint8_t *req_msg;
+
+	uint16_t rsp_msglen;
+	uint16_t rsp_buflen;
+	uint8_t *rsp_msgbuf;
+
+	volatile int pending;
+};
+
+struct ice_dcf_hw {
+	struct iavf_hw avf;
+
+	rte_spinlock_t vc_cmd_send_lock;
+	rte_spinlock_t vc_cmd_queue_lock;
+	TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+	uint8_t *arq_buf;
+
+	struct virtchnl_version_info virtchnl_version;
+	struct virtchnl_vf_resource *vf_res; /* VF resource */
+	struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+				 struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+		     struct rte_eth_dev_info *dev_info)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+	dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+	return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+		  __rte_unused struct rte_eth_stats *igb_stats)
+{
+	return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+			enum rte_filter_type filter_type,
+			__rte_unused enum rte_filter_op filter_op,
+			__rte_unused void *arg)
+{
+	int ret = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	switch (filter_type) {
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+			    filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return;
+
+	dev->dev_ops = NULL;
+	dev->rx_pkt_burst = NULL;
+	dev->tx_pkt_burst = NULL;
+	dev->data->mac_addrs = NULL;
+
+	ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+		    __rte_unused int wait_to_complete)
+{
+	return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t rx_queue_id,
+		       __rte_unused uint16_t nb_rx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_rxconf *rx_conf,
+		       __rte_unused struct rte_mempool *mb_pool)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+	return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t tx_queue_id,
+		       __rte_unused uint16_t nb_tx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+	return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+	.dev_start               = ice_dcf_dev_start,
+	.dev_stop                = ice_dcf_dev_stop,
+	.dev_close               = ice_dcf_dev_close,
+	.dev_configure           = ice_dcf_dev_configure,
+	.dev_infos_get           = ice_dcf_dev_info_get,
+	.rx_queue_setup          = ice_dcf_rx_queue_setup,
+	.tx_queue_setup          = ice_dcf_tx_queue_setup,
+	.rx_queue_release        = ice_dcf_queue_release,
+	.tx_queue_release        = ice_dcf_queue_release,
+	.link_update             = ice_dcf_link_update,
+	.stats_get               = ice_dcf_stats_get,
+	.stats_reset             = ice_dcf_stats_reset,
+	.promiscuous_enable      = ice_dcf_dev_promiscuous_enable,
+	.promiscuous_disable     = ice_dcf_dev_promiscuous_disable,
+	.allmulticast_enable     = ice_dcf_dev_allmulticast_enable,
+	.allmulticast_disable    = ice_dcf_dev_allmulticast_disable,
+	.filter_ctrl             = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+	eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+	eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+	eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+	if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+		PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+		return -1;
+	}
+
+	rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+	eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+	return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+	ice_dcf_dev_close(eth_dev);
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+			  const char *value, __rte_unused void *opaque)
+{
+	if (strcmp(value, "dcf"))
+		return -1;
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	const char *key = "cap";
+	int ret = 0;
+
+	if (devargs == NULL)
+		return 0;
+
+	kvlist = rte_kvargs_parse(devargs->args, NULL);
+	if (kvlist == NULL)
+		return 0;
+
+	if (!rte_kvargs_count(kvlist, key))
+		goto exit;
+
+	/* dcf capability selected when there's a key-value pair: cap=dcf */
+	if (rte_kvargs_process(kvlist, key,
+			       ice_dcf_cap_check_handler, NULL) < 0)
+		goto exit;
+
+	ret = 1;
+
+exit:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+			     struct rte_pci_device *pci_dev)
+{
+	if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+		return 1;
+
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+					     sizeof(struct ice_dcf_adapter),
+					     ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+	{ RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+	.id_table = pci_id_ice_dcf_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+	.probe = eth_ice_dcf_pci_probe,
+	.remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS  1
+
+struct ice_dcf_queue {
+	uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+	struct ice_dcf_hw real_hw;
+	struct rte_ether_addr mac_addr;
+	struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+	struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
 	'ice_hash.c'
 	)
 
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
 
 if arch_subdir == 'x86'
 	sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
 	endif
 endif
 
+sources += files('ice_dcf.c',
+		 'ice_dcf_ethdev.c')
+
 install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD)       += -lrte_pmd_iavf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD)        += -lrte_pmd_ice
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifeq ($(findstring y,$(IAVF-y)),y)
 _LDLIBS-y += -lrte_common_iavf
 endif
-- 
2.25.1


^ permalink raw reply	[relevance 1%]

* [dpdk-dev] [PATCH v3 0/7] vfio/pci: SR-IOV support
@ 2020-03-11 21:58  2% Alex Williamson
  2020-03-19  6:32  0% ` Tian, Kevin
  0 siblings, 1 reply; 200+ results
From: Alex Williamson @ 2020-03-11 21:58 UTC (permalink / raw)
  To: kvm
  Cc: linux-pci, linux-kernel, dev, mtosatti, thomas, bluca,
	jerinjacobk, bruce.richardson, cohuck, kevin.tian

Only minor tweaks since v2, GET and SET on VFIO_DEVICE_FEATURE are
enforced mutually exclusive except with the PROBE option as suggested
by Connie, the modinfo text has been expanded for the opt-in to enable
SR-IOV support in the vfio-pci driver per discussion with Kevin.

I have not incorporated runtime warnings attempting to detect misuse
of SR-IOV or imposed a session lifetime of a VF token, both of which
were significant portions of the discussion of the v2 series.  Both of
these also seem to impose a usage model or make assumptions about VF
resource usage or configuration requirements that don't seem necessary
except for the sake of generating a warning or requiring an otherwise
unnecessary and implicit token reinitialization.  If there are new
thoughts around these or other discussion points, please raise them.

Series overview (same as provided with v1):

The synopsis of this series is that we have an ongoing desire to drive
PCIe SR-IOV PFs from userspace with VFIO.  There's an immediate need
for this with DPDK drivers and potentially interesting future use
cases in virtualization.  We've been reluctant to add this support
previously due to the dependency and trust relationship between the
VF device and PF driver.  Minimally the PF driver can induce a denial
of service to the VF, but depending on the specific implementation,
the PF driver might also be responsible for moving data between VFs
or have direct access to the state of the VF, including data or state
otherwise private to the VF or VF driver.

To help resolve these concerns, we introduce a VF token into the VFIO
PCI ABI, which acts as a shared secret key between drivers.  The
userspace PF driver is required to set the VF token to a known value
and userspace VF drivers are required to provide the token to access
the VF device.  If a PF driver is restarted with VF drivers in use, it
must also provide the current token in order to prevent a rogue
untrusted PF driver from replacing a known driver.  The degree to
which this new token is considered secret is left to the userspace
drivers, the kernel intentionally provides no means to retrieve the
current token.

Note that the above token is only required for this new model where
both the PF and VF devices are usable through vfio-pci.  Existing
models of VFIO drivers where the PF is used without SR-IOV enabled
or the VF is bound to a userspace driver with an in-kernel, host PF
driver are unaffected.

The latter configuration above also highlights a new inverted scenario
that is now possible, a userspace PF driver with in-kernel VF drivers.
I believe this is a scenario that should be allowed, but should not be
enabled by default.  This series includes code to set a default
driver_override for VFs sourced from a vfio-pci user owned PF, such
that the VFs are also bound to vfio-pci.  This model is compatible
with tools like driverctl and allows the system administrator to
decide if other bindings should be enabled.  The VF token interface
above exists only between vfio-pci PF and VF drivers, once a VF is
bound to another driver, the administrator has effectively pronounced
the device as trusted.  The vfio-pci driver will note alternate
binding in dmesg for logging and debugging purposes.

Please review, comment, and test.  The example QEMU implementation
provided with the RFC is still current for this version.  Thanks,

Alex

RFC: https://lore.kernel.org/lkml/158085337582.9445.17682266437583505502.stgit@gimli.home/
v1: https://lore.kernel.org/lkml/158145472604.16827.15751375540102298130.stgit@gimli.home/
v2: https://lore.kernel.org/lkml/158213716959.17090.8399427017403507114.stgit@gimli.home/

---

Alex Williamson (7):
      vfio: Include optional device match in vfio_device_ops callbacks
      vfio/pci: Implement match ops
      vfio/pci: Introduce VF token
      vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user
      vfio/pci: Add sriov_configure support
      vfio/pci: Remove dev_fmt definition
      vfio/pci: Cleanup .probe() exit paths


 drivers/vfio/pci/vfio_pci.c         |  390 +++++++++++++++++++++++++++++++++--
 drivers/vfio/pci/vfio_pci_private.h |   10 +
 drivers/vfio/vfio.c                 |   20 +-
 include/linux/vfio.h                |    4 
 include/uapi/linux/vfio.h           |   37 +++
 5 files changed, 433 insertions(+), 28 deletions(-)


^ permalink raw reply	[relevance 2%]

* Re: [dpdk-dev] [PATCH] lib/librte_net/rte_ether.h:changed RTE_ETHER_MAX_LEN
  @ 2020-03-10 15:18  3% ` Stephen Hemminger
  0 siblings, 0 replies; 200+ results
From: Stephen Hemminger @ 2020-03-10 15:18 UTC (permalink / raw)
  To: Muhammad Ahmad; +Cc: olivier.matz, dev, stable

On Tue, 10 Mar 2020 11:50:36 +0500
Muhammad Ahmad <muhammad.ahmad@emumba.com> wrote:

> Change the RTE_ETHER_MAX_LEN from 1518 to 1526
> 
> Bugzilla ID: 296
> 
> Fixes: c5b2d13 (net: add rte prefix to ether defines)
> 
> Cc: stable@dpdk.org
> Cc: Oliver Matz <olivier.matz@6wind.com>
> 
> Reported-by: LAVA <lavaraj@gmail.com>
> Suggested-by: LAVA <lavaraj@gmail.com>
> Signed-off-by: Muhammad Ahmad <muhammad.ahmad@emumba.com>
> ---
>  lib/librte_net/rte_ether.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/librte_net/rte_ether.h b/lib/librte_net/rte_ether.h
> index e069dc7fe..8953107f3 100644
> --- a/lib/librte_net/rte_ether.h
> +++ b/lib/librte_net/rte_ether.h
> @@ -30,7 +30,7 @@ extern "C" {
>  	(RTE_ETHER_ADDR_LEN * 2 + \
>  		RTE_ETHER_TYPE_LEN) /**< Length of Ethernet header. */
>  #define RTE_ETHER_MIN_LEN   64    /**< Minimum frame len, including CRC. */
> -#define RTE_ETHER_MAX_LEN   1518  /**< Maximum frame len, including CRC. */
> +#define RTE_ETHER_MAX_LEN   1526  /**< Maximum frame len, including CRC. */
>  #define RTE_ETHER_MTU       \
>  	(RTE_ETHER_MAX_LEN - RTE_ETHER_HDR_LEN - \
>  		RTE_ETHER_CRC_LEN) /**< Ethernet MTU. */

No that is abi change would impact a lot of code and drivers.
The problem is the comment is wrong, not the value.

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-03-06 10:12  3%         ` David Marchand
@ 2020-03-10 10:36  3%           ` Dodji Seketeli
  2020-04-07 10:25  3%             ` Hemant Agrawal
  0 siblings, 1 reply; 200+ results
From: Dodji Seketeli @ 2020-03-10 10:36 UTC (permalink / raw)
  To: David Marchand
  Cc: Hemant Agrawal (OSS), Yigit, Ferruh, dev, Neil Horman, Thomas Monjalon

Hello,

David Marchand <david.marchand@redhat.com> writes:

> On Thu, Mar 5, 2020 at 10:19 AM Hemant Agrawal (OSS)
> <hemant.agrawal@oss.nxp.com> wrote:
>> > On Thu, Mar 5, 2020 at 10:06 AM Hemant Agrawal (OSS)
>> > <hemant.agrawal@oss.nxp.com> wrote:
>> > >
>> > > Hi David,
>> > > > On Mon, Mar 2, 2020 at 10:26 AM Hemant Agrawal
>> > > > <hemant.agrawal@nxp.com> wrote:
>> > > > >
>> > > > > This patch series add various patches for enhancing and fixing NXP
>> > > > > fslmc bus, dpaa bus, and dpaax.
>> > > > >
>> > > > > - the main change is support to allow thread migration across
>> > > > > lcores
>> > > > > - improving the multi-process support
>> > > >
>> > > > This series triggers an ABI warning that must be investigated.
>> > > >https://travis-ci.com/ovsrobot/dpdk/jobs/292904119#L2233
>> > >
>> > > [Hemant]
>> > > As per the logs:
>> > >
>> > > Variables changes summary: 1 Removed, 2 Changed, 0 Added variables
>> > > 1 Removed variable:
>> > >   'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'
>> > {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
>> > > 2 Changed variables:
>> > >   [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at
>> > dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
>> > >   [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at
>> > > dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16
>> > >
>> > > Error: ABI issue reported for 'abidiff --suppr devtools/libabigail.abignore --
>> > no-added-syms --headers-dir1 reference/usr/local/include --headers-dir2
>> > install/usr/local/include reference/dump/librte_bus_fslmc.dump
>> > install/dump/librte_bus_fslmc.dump'
>> > >
>> > > ---------------
>> > >
>> > > These changes are w.r.t modifications in internal structures and variables.
>> > They may be ignored.
>> >
>> > The ABI check considers symbol exposed in headers available to final users.
>> > If those are internal, why are the headers public?
>> >
>>
>> [Hemant] These symbols are not part of any public header files, but
>> they are part of *.map files to share them between different driver
>> libs i.e bus_fslmc and net_dpaa2
>
> I would expect libabigail to skip those symbols, so there is something
> I have missed in how --headers-dirX work.

In libabigail speak, we make a difference between *ELF symbols* and
types.

--header-dirX is about telling the tool what the public *types* are.  As
you rightfully implied, types that are defined in files that are not
found in the directories specified by --header-dirX are considered to be
private types and are thus not shown in the ABI change report.

ELF symbols however are a different matter.  Header files don't usually
define ELF symbols, be they variable of function symbols.  Header files
can at most declare variables or functions that would be actually
defined elsewhere in source code, leading to the definition of ELF
variable or function symbols in the final binary.  At this point, we
aren't talking about types anymore, as the ELF format doesn't know what
types (in C or any other language) are.  So --header-dirX don't deal with
ELF symbols.

And from what I understand from the message quoted above, the changes we
are talking about have to do with EFL variable symbols which size have
changed.  So in practise, these are global arrays (exposed by at the
binary level as an ELF variable symbol of a given size) with public
visibility which size have changed.

So my guess would be that if you guys don't want these arrays to be part
the binary interface of this library, they should probably be declared
static at the C level and accessed through some accessor function or
something like that.  At least, that's my humble uninformed opinion.

In the mean time, the tooling can be tought to ignore changes to these
ELF symbols, as you you guys all know already.


> Anyway, all of those symbols in dpaa are part of the driver ABI.
> We are still missing a way to mark internal symbols.
> Neil had posted a framework for this
> http://patchwork.dpdk.org/project/dpdk/list/?series=5004.
>
> In order to get this series passing the checks, I recommend NXP
> rebasing Neil scripts (I will help reviewing this part), then mark all
> those symbols as internal in its drivers.
> Other vendor will convert their drivers later, as there is no need at
> the moment.
>
> Thanks.

Cheers,

-- 
		Dodji


^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v2 2/7] net/ice: add the DCF hardware initialization
  @ 2020-03-10  6:50  1%   ` Haiyue Wang
  0 siblings, 0 replies; 200+ results
From: Haiyue Wang @ 2020-03-10  6:50 UTC (permalink / raw)
  To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
  Cc: wei.zhao1, Haiyue Wang

Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.

Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
 doc/guides/nics/ice.rst                |  47 +++
 doc/guides/nics/img/ice_dcf.png        | Bin 0 -> 39168 bytes
 doc/guides/rel_notes/release_20_05.rst |   5 +
 drivers/common/Makefile                |   1 +
 drivers/net/ice/Makefile               |   5 +
 drivers/net/ice/ice_dcf.c              | 474 +++++++++++++++++++++++++
 drivers/net/ice/ice_dcf.h              |  52 +++
 drivers/net/ice/ice_dcf_ethdev.c       | 317 +++++++++++++++++
 drivers/net/ice/ice_dcf_ethdev.h       |  24 ++
 drivers/net/ice/meson.build            |   7 +-
 mk/rte.app.mk                          |   1 +
 11 files changed, 931 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 drivers/net/ice/ice_dcf.c
 create mode 100644 drivers/net/ice/ice_dcf.h
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.h

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
 
 The APPs based on DPDK should avoid providing such packets.
 
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+   DCF Communication flow.
+
+#. Create the VFs::
+
+      echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+      ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0,  and run testpmd with 'cap=dcf' devarg::
+
+      testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+      tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+      flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+      dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+      sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+      192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+      iface="enp24s0f0", count=10)
+
 Sample Application Notes
 ------------------------
 
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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

literal 0
HcmV?d00001

diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
 
   * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
 
+* **Updated the Intel ice driver.**
+
+  Updated the Intel ice driver with new features and improvements, including:
+
+  * Added support for DCF (Device Config Function) feature.
 
 Removed Items
 -------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
 endif
 
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifneq (,$(findstring y,$(IAVF-y)))
 DIRS-y += iavf
 endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
 LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
 
 EXPORT_MAP := rte_pmd_ice_version.map
 
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
 
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
 
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..efb258a5a
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN     32
+#define ICE_DCF_AQ_BUF_SZ  4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME  2   /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ	\
+	(sizeof(struct virtchnl_vf_resource) +	\
+		IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *req_msg, uint16_t req_msglen)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+				      req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+			    uint16_t *rsp_msglen)
+{
+	struct iavf_arq_event_info event;
+	enum virtchnl_ops v_op;
+	int i = 0;
+	int err;
+
+	event.buf_len = rsp_buflen;
+	event.msg_buf = rsp_msgbuf;
+
+	do {
+		err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+		if (err != IAVF_SUCCESS)
+			goto again;
+
+		v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+		if (v_op != op)
+			goto again;
+
+		if (rsp_msglen != NULL)
+			*rsp_msglen = event.msg_len;
+		return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	cmd->v_ret = IAVF_ERR_NOT_READY;
+	cmd->rsp_msglen = 0;
+	cmd->pending = 1;
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf,
+				      cmd->v_op, IAVF_SUCCESS,
+				      cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+	struct dcf_virtchnl_cmd *cmd;
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+	uint16_t aq_op;
+
+	aq_op = rte_le_to_cpu_16(info->desc.opcode);
+	if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+		PMD_DRV_LOG(ERR,
+			    "Request %u is not supported yet", aq_op);
+		return;
+	}
+
+	v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+	if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+		return;
+
+	v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+		if (cmd->v_op == v_op && cmd->pending) {
+			cmd->v_ret = v_ret;
+			cmd->rsp_msglen = RTE_MIN(info->msg_len,
+						  cmd->rsp_buflen);
+			if (likely(cmd->rsp_msglen != 0))
+				rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+					   cmd->rsp_msglen);
+
+			/* prevent compiler reordering */
+			rte_compiler_barrier();
+			cmd->pending = 0;
+			break;
+		}
+	}
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+	struct iavf_arq_event_info info;
+	uint16_t pending = 1;
+	int ret;
+
+	info.buf_len = ICE_DCF_AQ_BUF_SZ;
+	info.msg_buf = hw->arq_buf;
+
+	while (pending) {
+		ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+		if (ret != IAVF_SUCCESS)
+			break;
+
+		ice_dcf_aq_cmd_handle(hw, &info);
+	}
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START	1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START	1
+	struct virtchnl_version_info version, *pver;
+	int err;
+
+	version.major = VIRTCHNL_VERSION_MAJOR;
+	version.minor = VIRTCHNL_VERSION_MINOR;
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)&version, sizeof(version));
+	if (err) {
+		PMD_INIT_LOG(ERR, "Fail to send OP_VERSION");
+		return err;
+	}
+
+	pver = &hw->virtchnl_version;
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)pver, sizeof(*pver), NULL);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Fail to get response of OP_VERSION");
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG,
+		     "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+	if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+	    (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+	     pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+		PMD_INIT_LOG(ERR,
+			     "VIRTCHNL API version should not be lower than (%u.%u)",
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+		return -1;
+	} else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+		   (pver->major == VIRTCHNL_VERSION_MAJOR &&
+		    pver->minor > VIRTCHNL_VERSION_MINOR)) {
+		PMD_INIT_LOG(ERR,
+			     "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+			     pver->major, pver->minor,
+			     VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+		return -1;
+	}
+
+	PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+	return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+	uint32_t caps;
+	int err, i;
+
+	caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+	       VF_BASE_MODE_OFFLOADS;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)&caps, sizeof(caps));
+	if (err) {
+		PMD_DRV_LOG(ERR, "Fail to send msg OP_GET_VF_RESOURCE");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)hw->vf_res,
+					  ICE_DCF_VF_RES_BUF_SZ, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Fail to get response of OP_GET_VF_RESOURCE");
+		return -1;
+	}
+
+	iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+	hw->vsi_res = NULL;
+	for (i = 0; i < hw->vf_res->num_vsis; i++) {
+		if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+			hw->vsi_res = &hw->vf_res->vsi_res[i];
+	}
+
+	if (!hw->vsi_res) {
+		PMD_DRV_LOG(ERR, "no LAN VSI found");
+		return -1;
+	}
+
+	hw->vsi_id = hw->vsi_res->vsi_id;
+	PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+	return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT       50
+	struct iavf_hw *avf = &hw->avf;
+	int i, reset;
+
+	for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+		reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+					IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+		reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+		if (reset == VIRTCHNL_VFR_VFACTIVE ||
+		    reset == VIRTCHNL_VFR_COMPLETED)
+			break;
+
+		rte_delay_ms(20);
+	}
+
+	if (i >= ICE_DCF_RESET_WAIT_CNT)
+		return -1;
+
+	return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+	struct ice_dcf_hw *hw = param;
+
+	ice_dcf_disable_irq0(hw);
+
+	ice_dcf_handle_virtchnl_msg(hw);
+
+	ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+			     struct dcf_virtchnl_cmd *cmd)
+{
+	int i = 0;
+	int err;
+
+	if ((cmd->req_msg && !cmd->req_msglen) ||
+	    (!cmd->req_msg && cmd->req_msglen) ||
+	    (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+	    (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+		return -EINVAL;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_vc_cmd_set(hw, cmd);
+
+	err = ice_dcf_vc_cmd_send(hw, cmd);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+		goto ret;
+	}
+
+	do {
+		if (!cmd->pending)
+			break;
+
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	if (cmd->v_ret != IAVF_SUCCESS) {
+		err = -1;
+		PMD_DRV_LOG(ERR,
+			    "No response (%d times) or return failure (%d) for cmd %d",
+			    i, cmd->v_ret, cmd->v_op);
+	}
+
+ret:
+	ice_dcf_aq_cmd_clear(hw, cmd);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+	return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	int ret;
+
+	hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+	hw->avf.back = hw;
+
+	hw->avf.bus.bus_id = pci_dev->addr.bus;
+	hw->avf.bus.device = pci_dev->addr.devid;
+	hw->avf.bus.func = pci_dev->addr.function;
+
+	hw->avf.device_id = pci_dev->id.device_id;
+	hw->avf.vendor_id = pci_dev->id.vendor_id;
+	hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+	hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+	hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+	rte_spinlock_init(&hw->vc_cmd_send_lock);
+	rte_spinlock_init(&hw->vc_cmd_queue_lock);
+	TAILQ_INIT(&hw->vc_cmd_queue);
+
+	hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+	if (hw->arq_buf == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+		goto err;
+	}
+
+	ret = iavf_set_mac_type(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+		goto err;
+	}
+
+	ret = ice_dcf_check_reset_done(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "VF is still resetting");
+		goto err;
+	}
+
+	ret = iavf_init_adminq(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+		goto err;
+	}
+
+	if (ice_dcf_init_check_api_version(hw)) {
+		PMD_INIT_LOG(ERR, "check_api version failed");
+		goto err_api;
+	}
+
+	hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+	if (hw->vf_res == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+		goto err_api;
+	}
+
+	if (ice_dcf_get_vf_resource(hw)) {
+		PMD_INIT_LOG(ERR, "Failed to get VF resource");
+		goto err_alloc;
+	}
+
+	rte_intr_callback_register(&pci_dev->intr_handle,
+				   ice_dcf_dev_interrupt_handler, hw);
+	rte_intr_enable(&pci_dev->intr_handle);
+	ice_dcf_enable_irq0(hw);
+
+	return 0;
+
+err_alloc:
+	rte_free(hw->vf_res);
+err_api:
+	iavf_shutdown_adminq(&hw->avf);
+err:
+	rte_free(hw->arq_buf);
+
+	return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+	ice_dcf_disable_irq0(hw);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     ice_dcf_dev_interrupt_handler, hw);
+
+	iavf_shutdown_adminq(&hw->avf);
+
+	rte_free(hw->arq_buf);
+	rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+	TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+
+	uint16_t req_msglen;
+	uint8_t *req_msg;
+
+	uint16_t rsp_msglen;
+	uint16_t rsp_buflen;
+	uint8_t *rsp_msgbuf;
+
+	volatile int pending;
+};
+
+struct ice_dcf_hw {
+	struct iavf_hw avf;
+
+	rte_spinlock_t vc_cmd_send_lock;
+	rte_spinlock_t vc_cmd_queue_lock;
+	TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+	uint8_t *arq_buf;
+
+	struct virtchnl_version_info virtchnl_version;
+	struct virtchnl_vf_resource *vf_res; /* VF resource */
+	struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+				 struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+		     struct rte_eth_dev_info *dev_info)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+	dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+	return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+		  __rte_unused struct rte_eth_stats *igb_stats)
+{
+	return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+			enum rte_filter_type filter_type,
+			__rte_unused enum rte_filter_op filter_op,
+			__rte_unused void *arg)
+{
+	int ret = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	switch (filter_type) {
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+			    filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return;
+
+	dev->dev_ops = NULL;
+	dev->rx_pkt_burst = NULL;
+	dev->tx_pkt_burst = NULL;
+	dev->data->mac_addrs = NULL;
+
+	ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+		    __rte_unused int wait_to_complete)
+{
+	return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t rx_queue_id,
+		       __rte_unused uint16_t nb_rx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_rxconf *rx_conf,
+		       __rte_unused struct rte_mempool *mb_pool)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+	return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t tx_queue_id,
+		       __rte_unused uint16_t nb_tx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+	return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+	.dev_start               = ice_dcf_dev_start,
+	.dev_stop                = ice_dcf_dev_stop,
+	.dev_close               = ice_dcf_dev_close,
+	.dev_configure           = ice_dcf_dev_configure,
+	.dev_infos_get           = ice_dcf_dev_info_get,
+	.rx_queue_setup          = ice_dcf_rx_queue_setup,
+	.tx_queue_setup          = ice_dcf_tx_queue_setup,
+	.rx_queue_release        = ice_dcf_queue_release,
+	.tx_queue_release        = ice_dcf_queue_release,
+	.link_update             = ice_dcf_link_update,
+	.stats_get               = ice_dcf_stats_get,
+	.stats_reset             = ice_dcf_stats_reset,
+	.promiscuous_enable      = ice_dcf_dev_promiscuous_enable,
+	.promiscuous_disable     = ice_dcf_dev_promiscuous_disable,
+	.allmulticast_enable     = ice_dcf_dev_allmulticast_enable,
+	.allmulticast_disable    = ice_dcf_dev_allmulticast_disable,
+	.filter_ctrl             = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+	eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+	eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+	eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+	if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+		PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+		return -1;
+	}
+
+	rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+	eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+	return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+	ice_dcf_dev_close(eth_dev);
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+			  const char *value, __rte_unused void *opaque)
+{
+	if (strcmp(value, "dcf"))
+		return -1;
+
+	return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	const char *key = "cap";
+	int ret = 0;
+
+	if (devargs == NULL)
+		return 0;
+
+	kvlist = rte_kvargs_parse(devargs->args, NULL);
+	if (kvlist == NULL)
+		return 0;
+
+	if (!rte_kvargs_count(kvlist, key))
+		goto exit;
+
+	/* dcf capability selected when there's a key-value pair: cap=dcf */
+	if (rte_kvargs_process(kvlist, key,
+			       ice_dcf_cap_check_handler, NULL) < 0)
+		goto exit;
+
+	ret = 1;
+
+exit:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+			     struct rte_pci_device *pci_dev)
+{
+	if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+		return 1;
+
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+					     sizeof(struct ice_dcf_adapter),
+					     ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+	{ RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+	.id_table = pci_id_ice_dcf_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+	.probe = eth_ice_dcf_pci_probe,
+	.remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS  1
+
+struct ice_dcf_queue {
+	uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+	struct ice_dcf_hw real_hw;
+	struct rte_ether_addr mac_addr;
+	struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+	struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
 	'ice_hash.c'
 	)
 
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
 
 if arch_subdir == 'x86'
 	sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
 	endif
 endif
 
+sources += files('ice_dcf.c',
+		 'ice_dcf_ethdev.c')
+
 install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD)       += -lrte_pmd_iavf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD)        += -lrte_pmd_ice
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifeq ($(findstring y,$(IAVF-y)),y)
 _LDLIBS-y += -lrte_common_iavf
 endif
-- 
2.25.1


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] dev Digest, Vol 288, Issue 27
       [not found]     ` <d8993cb75592406a993e3119d45e906a@intel.com>
@ 2020-03-10  2:55  0%   ` Zhang, XiX
  0 siblings, 0 replies; 200+ results
From: Zhang, XiX @ 2020-03-10  2:55 UTC (permalink / raw)
  To: dev

[PATCH] vfio: map contiguous areas in one go
Test-by : xix.zhang@intel.com
Thanks

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of dev- 
> request@dpdk.org
> Sent: February 25, 2020 21:50
> To: dev@dpdk.org
> Subject: dev Digest, Vol 288, Issue 27
> 
> Send dev mailing list submissions to
> 	dev@dpdk.org
> 
> To subscribe or unsubscribe via the World Wide Web, visit
> 	https://mails.dpdk.org/listinfo/dev
> or, via email, send a message with subject or body 'help' to
> 	dev-request@dpdk.org
> 
> You can reach the person managing the list at
> 	dev-owner@dpdk.org
> 
> When replying, please edit your Subject line so it is more specific than "Re:
> Contents of dev digest..."
> 
> 
> Today's Topics:
> 
>    1. Re: [PATCH] doc/mlx5: update mlx5 guide (Thomas Monjalon)
>    2. Re: [PATCH] doc: describe the pktmbuf pool with pinned
>       extarnal memory (Thomas Monjalon)
>    3. [PATCH] vfio: map contiguous areas in one go (Anatoly Burakov)
>    4. Re: [RFC 0/6] New sync modes for ring (Ananyev, Konstantin)
>    5. Re: [PATCH] vfio: map contiguous areas in one go (Ray Kinsella)
> 
> 
> ----------------------------------------------------------------------
> 
> Message: 1
> Date: Tue, 25 Feb 2020 14:19:10 +0100
> From: Thomas Monjalon <thomas@monjalon.net>
> To: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH] doc/mlx5: update mlx5 guide
> Message-ID: <2125420.IFkqi6BYcA@xps>
> Content-Type: text/plain; charset="us-ascii"
> 
> 24/02/2020 18:57, Viacheslav Ovsiienko:
> > - metadata limitation is described
> > - no inline hint flag is described
> >
> > Signed-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> > ---
> 
> Split in 2 patches and applied, thanks
> 
> 
> 
> 
> 
> ------------------------------
> 
> Message: 2
> Date: Tue, 25 Feb 2020 14:22:13 +0100
> From: Thomas Monjalon <thomas@monjalon.net>
> To: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> Cc: dev@dpdk.org, olivier.matz@6wind.com
> Subject: Re: [dpdk-dev] [PATCH] doc: describe the pktmbuf pool with
> 	pinned	extarnal memory
> Message-ID: <13189717.lVVuGzaMjS@xps>
> Content-Type: text/plain; charset="us-ascii"
> 
> 24/02/2020 18:58, Viacheslav Ovsiienko:
> > Document the new mbuf pools with external pinned buffers.
> >
> > Signed-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> > ---
> >  doc/guides/prog_guide/mbuf_lib.rst     | 34
> ++++++++++++++++++++++++++++++++++
> 
> Please submit this documentation separately for review by Olivier.
> 
> >  doc/guides/rel_notes/release_20_02.rst |  5 +++++
> 
> Applying only the release notes in 20.02, thanks
> 
> 
> 
> 
> 
> ------------------------------
> 
> Message: 3
> Date: Tue, 25 Feb 2020 13:24:48 +0000
> From: Anatoly Burakov <anatoly.burakov@intel.com>
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH] vfio: map contiguous areas in one go
> Message-ID:
> 	<c6550c8e66dbc7a54a0b495ecda58b0eb79c07ca.1582637079.git.anat
> oly.burakov@intel.com>
> 
> 
> Currently, when we are creating DMA mappings for memory that's either 
> external or is backed by hugepages in IOVA as PA mode, we assume that 
> each page is necessarily discontiguous. This may not actually be the 
> case, especially for external memory, where the user is able to create 
> their own IOVA table and make it contiguous. This is a problem because 
> VFIO has a limited number of DMA mappings, and it does not appear to 
> concatenate them and treats each mapping as separate, even when they 
> cover adjacent areas.
> 
> Fix this so that we always map contiguous memory in a single chunk, as 
> opposed to mapping each segment separately.
> 
> Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
> ---
>  lib/librte_eal/linux/eal/eal_vfio.c | 59 
> +++++++++++++++++++++++++----
>  1 file changed, 51 insertions(+), 8 deletions(-)
> 
> diff --git a/lib/librte_eal/linux/eal/eal_vfio.c
> b/lib/librte_eal/linux/eal/eal_vfio.c
> index 01b5ef3f42..4502aefed3 100644
> --- a/lib/librte_eal/linux/eal/eal_vfio.c
> +++ b/lib/librte_eal/linux/eal/eal_vfio.c
> @@ -514,9 +514,11 @@ static void
>  vfio_mem_event_callback(enum rte_mem_event type, const void *addr, 
> size_t len,
>  		void *arg __rte_unused)
>  {
> +	rte_iova_t iova_start, iova_expected;
>  	struct rte_memseg_list *msl;
>  	struct rte_memseg *ms;
>  	size_t cur_len = 0;
> +	uint64_t va_start;
> 
>  	msl = rte_mem_virt2memseg_list(addr);
> 
> @@ -545,22 +547,63 @@ vfio_mem_event_callback(enum rte_mem_event type, 
> const void *addr, size_t len,  #endif
>  	/* memsegs are contiguous in memory */
>  	ms = rte_mem_virt2memseg(addr, msl);
> +
> +	/*
> +	 * This memory is not guaranteed to be contiguous, but it still could
> +	 * be, or it could have some small contiguous chunks. Since the
> number
> +	 * of VFIO mappings is limited, and VFIO appears to not concatenate
> +	 * adjacent mappings, we have to do this ourselves.
> +	 *
> +	 * So, find contiguous chunks, then map them.
> +	 */
> +	va_start = ms->addr_64;
> +	iova_start = iova_expected = ms->iova;
>  	while (cur_len < len) {
> +		bool new_contig_area = ms->iova != iova_expected;
> +		bool last_seg = (len - cur_len) == ms->len;
> +		bool skip_last = false;
> +
> +		/* only do mappings when current contiguous area ends */
> +		if (new_contig_area) {
> +			if (type == RTE_MEM_EVENT_ALLOC)
> +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> +						iova_start,
> +						iova_expected - iova_start, 1);
> +			else
> +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> +						iova_start,
> +						iova_expected - iova_start, 0);
> +			va_start = ms->addr_64;
> +			iova_start = ms->iova;
> +		}
>  		/* some memory segments may have invalid IOVA */
>  		if (ms->iova == RTE_BAD_IOVA) {
>  			RTE_LOG(DEBUG, EAL, "Memory segment at %p has bad IOVA, 
> skipping\n",
>  					ms->addr);
> -			goto next;
> +			skip_last = true;
>  		}
> -		if (type == RTE_MEM_EVENT_ALLOC)
> -			vfio_dma_mem_map(default_vfio_cfg, ms-
> >addr_64,
> -					ms->iova, ms->len, 1);
> -		else
> -			vfio_dma_mem_map(default_vfio_cfg, ms-
> >addr_64,
> -					ms->iova, ms->len, 0);
> -next:
> +		iova_expected = ms->iova + ms->len;
>  		cur_len += ms->len;
>  		++ms;
> +
> +		/*
> +		 * don't count previous segment, and don't attempt to
> +		 * dereference a potentially invalid pointer.
> +		 */
> +		if (skip_last && !last_seg) {
> +			iova_expected = iova_start = ms->iova;
> +			va_start = ms->addr_64;
> +		} else if (!skip_last && last_seg) {
> +			/* this is the last segment and we're not skipping */
> +			if (type == RTE_MEM_EVENT_ALLOC)
> +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> +						iova_start,
> +						iova_expected - iova_start, 1);
> +			else
> +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> +						iova_start,
> +						iova_expected - iova_start, 0);
> +		}
>  	}
>  #ifdef RTE_ARCH_PPC_64
>  	cur_len = 0;
> --
> 2.17.1
> 
> 
> ------------------------------
> 
> Message: 4
> Date: Tue, 25 Feb 2020 13:41:14 +0000
> From: "Ananyev, Konstantin" <konstantin.ananyev@intel.com>
> To: Stephen Hemminger <stephen@networkplumber.org>, Jerin Jacob
> 	<jerinjacobk@gmail.com>
> Cc: dpdk-dev <dev@dpdk.org>, Olivier Matz <olivier.matz@6wind.com>,
> 	"drc@linux.vnet.ibm.com" <drc@linux.vnet.ibm.com>
> Subject: Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
> Message-ID:
> 	<SN6PR11MB255845FB6665C2A2D5D76D229AED0@SN6PR11MB2558.
> namprd11.prod.outlook.com>
> 
> Content-Type: text/plain; charset="us-ascii"
> 
> > > > > Upfront note - that RFC is not a complete patch.
> > > > > It introduces an ABI breakage, plus it doesn't update 
> > > > > ring_elem code properly, etc.
> > > > > I plan to deal with all these things in later versions.
> > > > > Right now I seek an initial feedback about proposed ideas.
> > > > > Would also ask people to repeat performance tests (see below) 
> > > > > on their platforms to confirm the impact.
> > > > >
> > > > > More and more customers use(/try to use) DPDK based apps 
> > > > > within overcommitted systems (multiple acttive threads over 
> > > > > same pysical
> cores):
> > > > > VM, container deployments, etc.
> > > > > One quite common problem they hit: Lock-Holder-Preemption with
> rte_ring.
> > > > > LHP is quite a common problem for spin-based sync primitives 
> > > > > (spin-locks, etc.) on overcommitted systems.
> > > > > The situation gets much worse when some sort of fair-locking 
> > > > > technique is used (ticket-lock, etc.).
> > > > > As now not only lock-owner but also lock-waiters scheduling 
> > > > > order matters a lot.
> > > > > This is a well-known problem for kernel within VMs:
> > > > > http://www-
> archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > > > https://www.cs.hs-
> rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > > > > The problem with rte_ring is that while head accusion is sort 
> > > > > of un-fair locking, waiting on tail is very similar to ticket 
> > > > > lock schema - tail has to be updated in particular order.
> > > > > That makes current rte_ring implementation to perform really 
> > > > > pure on some overcommited scenarios.
> > > >
> > > > Rather than reform rte_ring to fit this scenario, it would make 
> > > > more sense to me to introduce another primitive.
> 
> I don't see much advantages it will bring us.
> As a disadvantages, for developers and maintainers - code duplication, 
> for end users - extra code churn and removed ability to mix and match 
> different sync modes in one ring.
> 
> > The current lockless
> > > > ring performs very well for the isolated thread model that DPDK 
> > > > was built around. This looks like a case of customers violating 
> > > > the usage model of the DPDK and then being surprised at the fallout.
> 
> For customers using isolated thread model - nothing should change 
> (both in terms of API and performance).
> Existing sync modes MP/MC,SP/SC kept untouched, set up in the same way 
> (via flags and _init_), and MP/MC remains as default one.
> >From other side I don't see why we should ignore customers that want 
> >to
> use
> their DPDK apps in different deployment scenarios.
> 
> > >
> > > I agree with Stephen here.
> > >
> > > I think, adding more runtime check in the enqueue() and dequeue() 
> > > will have a bad effect on the low-end cores too.
> 
> We do have a run-time check in our current enqueue()/dequeue 
> implementation.
> In fact we support both modes: we have generic
> rte_ring_enqueue(/dequeue)_bulk(/burst)
> where sync behaviour is determined at runtime by value of 
> prod(/cons).single.
> Or user can call  rte_ring_(mp/sp)_enqueue_* functions directly.
> This RFC follows exactly the same paradigm:
> rte_ring_enqueue(/dequeue)_bulk(/burst) kept generic and it's 
> behaviour is determined at runtime, by value of prod(/cons).sync_type.
> Or user can call enqueue/dequeue with particular sync mode directly:
> rte_ring_(mp/sp/rts/hts)_enqueue_(bulk/burst)*.
> The only thing that changed:
>  Format of prod/cons now could differ depending on mode selected at _init_.
>  So you can't create a ring for let say SP mode and then in the middle 
> of data- path  change your mind and start using MP_RTS mode.
>  For existing modes (SP/MP, SC/MC)  format remains the same and user 
> can still  use them interchangeably, though of course that is an error 
> prone practice.
> 
> > > But I agree with the problem statement that in the virtualization 
> > > use case, It may be possible to have N virtual cores runs on a 
> > > physical core.
> > >
> > > IMO, The best solution would be keeping the ring API same and have 
> > > a different flavor in "compile-time". Something like liburcu did 
> > > for accommodating different flavors.
> > >
> > > i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. 
> > > The application can simply include ONE header file in a C file 
> > > based on the flavor.
> 
> I don't think it is a flexible enough approach.
> In one app user might need to have several rings with different sync modes.
> Or even user might need a ring with different sync modes for 
> enqueue/dequeue.
> 
> > > If need both at runtime. Need to have function pointer or so in 
> > > the application and define the function in different c file by 
> > > including the approaite flavor in C file.
> 
> Big issue with function pointers here would be DPDK MP model.
> AFAIK,  rte_ring is quite popular mechanism for IPC between DPDK apps.
> To support such model, we'll need to split rte_ring data into 'shared'
> and 'private' and initialize private one for every process that is going to use it.
> That sounds like a massive change, and I am not sure the required 
> effort will worth it.
> BTW, if user just calls API functions without trying to access 
> structure internals directly, I don't think it would be a big 
> difference for him what is inside:
> indirect function call or inlined switch(...) {}.
> 
> > This would also be a good time to consider the tradeoffs of the 
> > heavy use of inlining that is done in rte_ring vs the impact that 
> > has on API/ABI stability.
> 
> Yes, hiding rte_ring implementation inside .c would help a lot in 
> terms of ABI maintenance and would make our future life easier.
> The question is what is the price for it in terms of performance, and 
> are we ready to pay it. Not to mention that it would cause changes in 
> many other libs/apps...
> So I think it should be a subject for a separate discussion.
> But, agree it would be good at least to measure the performance impact 
> of such change.
> If I'll have some spare cycles, will give it a try.
> Meanwhile, can I ask Jerin and other guys to repeat tests from this 
> RFC on their HW? Before continuing discussion would probably be good 
> to know does the suggested patch work as expected across different platforms.
> Thanks
> Konstantin
> 
> 
> ------------------------------
> 
> Message: 5
> Date: Tue, 25 Feb 2020 13:49:38 +0000
> From: Ray Kinsella <mdr@ashroe.eu>
> To: Anatoly Burakov <anatoly.burakov@intel.com>, dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH] vfio: map contiguous areas in one go
> Message-ID: <276c85ed-ac2f-52c9-dffc-18ce41ab0f35@ashroe.eu>
> Content-Type: text/plain; charset=utf-8
> 
> Hi Anatoly,
> 
> On 25/02/2020 13:24, Anatoly Burakov wrote:
> > Currently, when we are creating DMA mappings for memory that's 
> > either external or is backed by hugepages in IOVA as PA mode, we 
> > assume that each page is necessarily discontiguous. This may not 
> > actually be the case, especially for external memory, where the user 
> > is able to create their own IOVA table and make it contiguous. This 
> > is a problem because VFIO has a limited number of DMA mappings, and 
> > it does not appear to concatenate them and treats each mapping as 
> > separate, even when they cover adjacent areas.
> > > Fix this so that we always map contiguous memory in a single
> > chunk, as opposed to mapping each segment separately.
> 
> Can I confirm my understanding.
> 
> We are essentially correcting user errant behavior, trading off 
> startup/mapping time to save IOMMU resources?
> 
> >
> > Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
> > ---
> >  lib/librte_eal/linux/eal/eal_vfio.c | 59 
> > +++++++++++++++++++++++++----
> >  1 file changed, 51 insertions(+), 8 deletions(-)
> >
> > diff --git a/lib/librte_eal/linux/eal/eal_vfio.c
> b/lib/librte_eal/linux/eal/eal_vfio.c
> > index 01b5ef3f42..4502aefed3 100644
> > --- a/lib/librte_eal/linux/eal/eal_vfio.c
> > +++ b/lib/librte_eal/linux/eal/eal_vfio.c
> > @@ -514,9 +514,11 @@ static void
> >  vfio_mem_event_callback(enum rte_mem_event type, const void *addr,
> size_t len,
> >  		void *arg __rte_unused)
> >  {
> > +	rte_iova_t iova_start, iova_expected;
> >  	struct rte_memseg_list *msl;
> >  	struct rte_memseg *ms;
> >  	size_t cur_len = 0;
> > +	uint64_t va_start;
> >
> >  	msl = rte_mem_virt2memseg_list(addr);
> >
> > @@ -545,22 +547,63 @@ vfio_mem_event_callback(enum
> rte_mem_event type, const void *addr, size_t len,
> >  #endif
> >  	/* memsegs are contiguous in memory */
> >  	ms = rte_mem_virt2memseg(addr, msl);
> > +
> > +	/*
> > +	 * This memory is not guaranteed to be contiguous, but it still could
> > +	 * be, or it could have some small contiguous chunks. Since the
> number
> > +	 * of VFIO mappings is limited, and VFIO appears to not concatenate
> > +	 * adjacent mappings, we have to do this ourselves.
> > +	 *
> > +	 * So, find contiguous chunks, then map them.
> > +	 */
> > +	va_start = ms->addr_64;
> > +	iova_start = iova_expected = ms->iova;
> >  	while (cur_len < len) {
> > +		bool new_contig_area = ms->iova != iova_expected;
> > +		bool last_seg = (len - cur_len) == ms->len;
> > +		bool skip_last = false;
> > +
> > +		/* only do mappings when current contiguous area ends */
> > +		if (new_contig_area) {
> > +			if (type == RTE_MEM_EVENT_ALLOC)
> > +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> > +						iova_start,
> > +						iova_expected - iova_start, 1);
> > +			else
> > +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> > +						iova_start,
> > +						iova_expected - iova_start, 0);
> > +			va_start = ms->addr_64;
> > +			iova_start = ms->iova;
> > +		}
> >  		/* some memory segments may have invalid IOVA */
> >  		if (ms->iova == RTE_BAD_IOVA) {
> >  			RTE_LOG(DEBUG, EAL, "Memory segment at %p has
> bad IOVA, skipping\n",
> >  					ms->addr);
> > -			goto next;
> > +			skip_last = true;
> >  		}
> > -		if (type == RTE_MEM_EVENT_ALLOC)
> > -			vfio_dma_mem_map(default_vfio_cfg, ms-
> >addr_64,
> > -					ms->iova, ms->len, 1);
> > -		else
> > -			vfio_dma_mem_map(default_vfio_cfg, ms-
> >addr_64,
> > -					ms->iova, ms->len, 0);
> > -next:
> > +		iova_expected = ms->iova + ms->len;
> >  		cur_len += ms->len;
> >  		++ms;
> > +
> > +		/*
> > +		 * don't count previous segment, and don't attempt to
> > +		 * dereference a potentially invalid pointer.
> > +		 */
> > +		if (skip_last && !last_seg) {
> > +			iova_expected = iova_start = ms->iova;
> > +			va_start = ms->addr_64;
> > +		} else if (!skip_last && last_seg) {
> > +			/* this is the last segment and we're not skipping */
> > +			if (type == RTE_MEM_EVENT_ALLOC)
> > +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> > +						iova_start,
> > +						iova_expected - iova_start, 1);
> > +			else
> > +				vfio_dma_mem_map(default_vfio_cfg,
> va_start,
> > +						iova_start,
> > +						iova_expected - iova_start, 0);
> > +		}
> >  	}
> >  #ifdef RTE_ARCH_PPC_64
> >  	cur_len = 0;
> >
> 
> 
> End of dev Digest, Vol 288, Issue 27
> ************************************

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework
  @ 2020-03-09 14:14  1% ` Haiyue Wang
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 200+ results
From: Haiyue Wang @ 2020-03-09 14:14 UTC (permalink / raw)
  To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
  Cc: wei.zhao1, Haiyue Wang

The DCF (Device Config Function) feature works as a standalone PMD, its
hardware entity is the trusted VF with ID 0, and the software function
is to control the flow setting of other VFs by the mailbox with PF.

It doesn't handle packet Rx/Tx related things. This PMD needs the iAVF
virtchnl to send the ICE PF's AdminQ command.

Also for security, it needs to acquire the DCF capability from PF. The
flow related things will be added later, it shares most of the ICE flow
function. This mainly handles hardware initialization etc.

                               .-------------.
                             .-|             |
                           .-| |             |
                           | | |  iAVF PMD   |
                           | | |             |
                           | | |             |
                           | | '-------------'
                           | '-------------'
                           '-------------'
                          ^   Other VFs
                         /
                        / Flow Distribution
  .------------------. /
  |                  |/  DCF cap req   .-------------.
  |      CVL         .  <----------    |             |
  |     Kernel       |  ---------->    |             |
  .                  .   DCF cap rsp   |   DCF PMD   |
  |                  |                 |             |
  '------------------'  <-----------   |             |
                          rte_flow     '-------------'
                                             VF0

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
 doc/guides/nics/ice.rst          |  47 +++
 doc/guides/nics/img/ice_dcf.png  | Bin 0 -> 39168 bytes
 drivers/common/Makefile          |   1 +
 drivers/net/ice/Makefile         |   6 +
 drivers/net/ice/ice_dcf.c        | 651 +++++++++++++++++++++++++++++++
 drivers/net/ice/ice_dcf.h        |  61 +++
 drivers/net/ice/ice_dcf_ethdev.c | 319 +++++++++++++++
 drivers/net/ice/ice_dcf_ethdev.h |  33 ++
 drivers/net/ice/ice_dcf_parent.c | 348 +++++++++++++++++
 drivers/net/ice/meson.build      |   8 +-
 mk/rte.app.mk                    |   1 +
 11 files changed, 1473 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/nics/img/ice_dcf.png
 create mode 100644 drivers/net/ice/ice_dcf.c
 create mode 100644 drivers/net/ice/ice_dcf.h
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
 create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
 create mode 100644 drivers/net/ice/ice_dcf_parent.c

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
 
 The APPs based on DPDK should avoid providing such packets.
 
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+   DCF Communication flow.
+
+#. Create the VFs::
+
+      echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+      ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0,  and run testpmd with 'cap=dcf' devarg::
+
+      testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+      tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+      flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+      dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+      sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+      192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+      iface="enp24s0f0", count=10)
+
 Sample Application Notes
 ------------------------
 
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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

literal 0
HcmV?d00001

diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
 endif
 
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifneq (,$(findstring y,$(IAVF-y)))
 DIRS-y += iavf
 endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..643639a50 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
 LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
 
 EXPORT_MAP := rte_pmd_ice_version.map
 
@@ -84,6 +86,10 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
 
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
 
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..669122331
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,651 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN     32
+#define ICE_DCF_AQ_BUF_SZ  4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME  2   /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ	\
+	(sizeof(struct virtchnl_vf_resource) +	\
+		IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *req_msg, uint16_t req_msglen)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+				      req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+			    uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+			    uint16_t *rsp_msglen)
+{
+	struct iavf_arq_event_info event;
+	enum virtchnl_ops v_op;
+	int i = 0;
+	int err;
+
+	event.buf_len = rsp_buflen;
+	event.msg_buf = rsp_msgbuf;
+
+	do {
+		err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+		if (err != IAVF_SUCCESS)
+			goto again;
+
+		v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+		if (v_op != op)
+			goto again;
+
+		if (rsp_msglen != NULL)
+			*rsp_msglen = event.msg_len;
+		return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	cmd->v_ret = IAVF_ERR_NOT_READY;
+	cmd->rsp_msglen = 0;
+	cmd->pending = 1;
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+	return iavf_aq_send_msg_to_pf(&hw->avf,
+				      cmd->v_op, IAVF_SUCCESS,
+				      cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+	struct dcf_virtchnl_cmd *cmd;
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+	uint16_t aq_op;
+
+	aq_op = rte_le_to_cpu_16(info->desc.opcode);
+	if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+		PMD_DRV_LOG(ERR,
+			    "Request %u is not supported yet", aq_op);
+		return;
+	}
+
+	v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+	if (unlikely(v_op == VIRTCHNL_OP_EVENT)) {
+		if (hw->vc_event_msg_cb != NULL)
+			hw->vc_event_msg_cb(hw,
+					    info->msg_buf,
+					    info->msg_len);
+		return;
+	}
+
+	v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+	rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+	TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+		if (cmd->v_op == v_op && cmd->pending) {
+			cmd->v_ret = v_ret;
+			cmd->rsp_msglen = RTE_MIN(info->msg_len,
+						  cmd->rsp_buflen);
+			if (likely(cmd->rsp_msglen != 0))
+				rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+					   cmd->rsp_msglen);
+
+			/* prevent compiler reordering */
+			rte_compiler_barrier();
+			cmd->pending = 0;
+			break;
+		}
+	}
+
+	rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+	struct iavf_arq_event_info info;
+	uint16_t pending = 1;
+	int ret;
+
+	info.buf_len = ICE_DCF_AQ_BUF_SZ;
+	info.msg_buf = hw->arq_buf;
+
+	while (pending) {
+		ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+		if (ret != IAVF_SUCCESS)
+			break;
+
+		ice_dcf_aq_cmd_handle(hw, &info);
+	}
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START	1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START	1
+	struct virtchnl_version_info version, *pver;
+	int err;
+
+	version.major = VIRTCHNL_VERSION_MAJOR;
+	version.minor = VIRTCHNL_VERSION_MINOR;
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)&version, sizeof(version));
+	if (err) {
+		PMD_INIT_LOG(ERR, "Fail to send OP_VERSION");
+		return err;
+	}
+
+	pver = &hw->virtchnl_version;
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+					  (uint8_t *)pver, sizeof(*pver), NULL);
+	if (err) {
+		PMD_INIT_LOG(ERR, "Fail to get response of OP_VERSION");
+		return -1;
+	}
+
+	PMD_DRV_LOG(DEBUG,
+		    "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+	if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+	    (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+	     pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+		PMD_INIT_LOG(ERR,
+			     "VIRTCHNL API version should not be lower than (%u.%u)",
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+			     ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+		return -1;
+	} else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+		   (pver->major == VIRTCHNL_VERSION_MAJOR &&
+		    pver->minor > VIRTCHNL_VERSION_MINOR)) {
+		PMD_INIT_LOG(ERR,
+			     "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+			     pver->major, pver->minor,
+			     VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+		return -1;
+	}
+
+	PMD_DRV_LOG(DEBUG, "Peer is supported PF host");
+
+	return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+	uint32_t caps;
+	int err, i;
+
+	caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+	       VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
+	       VF_BASE_MODE_OFFLOADS;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)&caps, sizeof(caps));
+	if (err) {
+		PMD_DRV_LOG(ERR, "Fail to send msg OP_GET_VF_RESOURCE");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+					  (uint8_t *)hw->vf_res,
+					  ICE_DCF_VF_RES_BUF_SZ, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Fail to get response of OP_GET_VF_RESOURCE");
+		return -1;
+	}
+
+	iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+	hw->vsi_res = NULL;
+	for (i = 0; i < hw->vf_res->num_vsis; i++) {
+		if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+			hw->vsi_res = &hw->vf_res->vsi_res[i];
+	}
+
+	if (!hw->vsi_res) {
+		PMD_DRV_LOG(ERR, "no LAN VSI found");
+		return -1;
+	}
+
+	hw->vsi_id = hw->vsi_res->vsi_id;
+	PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+	return 0;
+}
+
+static int
+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
+{
+	struct virtchnl_dcf_vsi_map *vsi_map;
+	uint16_t len;
+	int err;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+					  NULL, 0);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_GET_VSI_MAP");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+					  hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
+					  &len);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Fail to get response of OP_DCF_GET_VSI_MAP");
+		return err;
+	}
+
+	vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
+	if (len < sizeof(*vsi_map) || !vsi_map->num_vfs ||
+	    len < sizeof(*vsi_map) +
+			(vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0])) {
+		PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
+			    len);
+		return -EINVAL;
+	}
+
+	if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
+		PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
+			    vsi_map->num_vfs, hw->num_vfs);
+		return -EINVAL;
+	}
+
+	len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
+	if (!hw->vf_vsi_map) {
+		hw->num_vfs = vsi_map->num_vfs;
+		hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
+	}
+
+	if (!hw->vf_vsi_map) {
+		PMD_DRV_LOG(ERR, "Fail to alloc memory for VSI context");
+		return -ENOMEM;
+	}
+
+	if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
+		PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
+		return 1;
+	}
+
+	rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
+	return 0;
+}
+
+static int
+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
+{
+	int err;
+
+	err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+					  NULL, 0);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
+		return err;
+	}
+
+	err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+					  (uint8_t *)hw->arq_buf,
+					  ICE_DCF_AQ_BUF_SZ, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR,
+			    "Fail to get response of OP_DCF_DISABLE %d",
+			    err);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT       50
+	struct iavf_hw *avf = &hw->avf;
+	int i, reset;
+
+	for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+		reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+					IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+		reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+		if (reset == VIRTCHNL_VFR_VFACTIVE ||
+		    reset == VIRTCHNL_VFR_COMPLETED)
+			break;
+
+		rte_delay_ms(20);
+	}
+
+	if (i >= ICE_DCF_RESET_WAIT_CNT)
+		return -1;
+
+	return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Enable admin queue interrupt trigger */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+		       IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+		       IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+	struct iavf_hw *avf = &hw->avf;
+
+	/* Disable all interrupt types */
+	IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+	IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+		       IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+	IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+	struct ice_dcf_hw *hw = param;
+
+	ice_dcf_disable_irq0(hw);
+
+	ice_dcf_handle_virtchnl_msg(hw);
+
+	ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+			     struct dcf_virtchnl_cmd *cmd)
+{
+	int i = 0;
+	int err;
+
+	if ((cmd->req_msg && !cmd->req_msglen) ||
+	    (!cmd->req_msg && cmd->req_msglen) ||
+	    (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+	    (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+		return -EINVAL;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_vc_cmd_set(hw, cmd);
+
+	err = ice_dcf_vc_cmd_send(hw, cmd);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+		goto ret;
+	}
+
+	do {
+		if (!cmd->pending)
+			break;
+
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	if (cmd->v_ret != IAVF_SUCCESS) {
+		err = -1;
+		PMD_DRV_LOG(ERR,
+			    "No response (%d times) or return failure (%d) for cmd %d",
+			    i, cmd->v_ret, cmd->v_op);
+	}
+
+ret:
+	ice_dcf_aq_cmd_clear(hw, cmd);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+	return err;
+}
+
+int
+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+		    void *buf, uint16_t buf_size)
+{
+	struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
+	struct ice_dcf_hw *hw = dcf_hw;
+	int err = 0;
+	int i = 0;
+
+	if ((buf && !buf_size) || (!buf && buf_size) ||
+	    buf_size > ICE_DCF_AQ_BUF_SZ)
+		return -EINVAL;
+
+	desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
+	desc_cmd.req_msglen = sizeof(*desc);
+	desc_cmd.req_msg = (uint8_t *)desc;
+	desc_cmd.rsp_buflen = sizeof(*desc);
+	desc_cmd.rsp_msgbuf = (uint8_t *)desc;
+
+	if (buf == NULL)
+		return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
+
+	desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
+
+	buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
+	buff_cmd.req_msglen = buf_size;
+	buff_cmd.req_msg = buf;
+	buff_cmd.rsp_buflen = buf_size;
+	buff_cmd.rsp_msgbuf = buf;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_vc_cmd_set(hw, &desc_cmd);
+	ice_dcf_vc_cmd_set(hw, &buff_cmd);
+
+	if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
+	    ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
+		err = -1;
+		PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
+		goto ret;
+	}
+
+	do {
+		if ((!desc_cmd.pending && !buff_cmd.pending) ||
+		    (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
+		    (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
+			break;
+
+		rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+	} while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+	if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
+		err = -1;
+		PMD_DRV_LOG(ERR,
+			    "No response (%d times) or return failure (desc: %d / buff: %d)",
+			    i, desc_cmd.v_ret, buff_cmd.v_ret);
+	}
+
+ret:
+	ice_dcf_aq_cmd_clear(hw, &desc_cmd);
+	ice_dcf_aq_cmd_clear(hw, &buff_cmd);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+	return err;
+}
+
+int
+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
+{
+	int err = 0;
+
+	rte_spinlock_lock(&hw->vc_cmd_send_lock);
+	ice_dcf_disable_irq0(hw);
+
+	if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
+		err = -1;
+
+	ice_dcf_enable_irq0(hw);
+	rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+	return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	int ret;
+
+	hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+	hw->avf.back = hw;
+
+	hw->avf.bus.bus_id = pci_dev->addr.bus;
+	hw->avf.bus.device = pci_dev->addr.devid;
+	hw->avf.bus.func = pci_dev->addr.function;
+
+	hw->avf.device_id = pci_dev->id.device_id;
+	hw->avf.vendor_id = pci_dev->id.vendor_id;
+	hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+	hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+	hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+	hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+	rte_spinlock_init(&hw->vc_cmd_send_lock);
+	rte_spinlock_init(&hw->vc_cmd_queue_lock);
+	TAILQ_INIT(&hw->vc_cmd_queue);
+
+	hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+	if (hw->arq_buf == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+		goto err;
+	}
+
+	ret = iavf_set_mac_type(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+		goto err;
+	}
+
+	ret = ice_dcf_check_reset_done(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "VF is still resetting");
+		goto err;
+	}
+
+	ret = iavf_init_adminq(&hw->avf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+		goto err;
+	}
+
+	if (ice_dcf_init_check_api_version(hw)) {
+		PMD_INIT_LOG(ERR, "check_api version failed");
+		goto err_api;
+	}
+
+	hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+	if (hw->vf_res == NULL) {
+		PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+		goto err_api;
+	}
+
+	if (ice_dcf_get_vf_resource(hw)) {
+		PMD_INIT_LOG(ERR, "Failed to get VF resource");
+		goto err_alloc;
+	}
+
+	if (ice_dcf_get_vf_vsi_map(hw) < 0) {
+		PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
+		ice_dcf_mode_disable(hw);
+		goto err_alloc;
+	}
+
+	rte_intr_callback_register(&pci_dev->intr_handle,
+				   ice_dcf_dev_interrupt_handler, hw);
+	rte_intr_enable(&pci_dev->intr_handle);
+	ice_dcf_enable_irq0(hw);
+
+	return 0;
+
+err_alloc:
+	rte_free(hw->vf_res);
+err_api:
+	iavf_shutdown_adminq(&hw->avf);
+err:
+	rte_free(hw->arq_buf);
+
+	return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+	ice_dcf_disable_irq0(hw);
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     ice_dcf_dev_interrupt_handler, hw);
+
+	ice_dcf_mode_disable(hw);
+	iavf_shutdown_adminq(&hw->avf);
+
+	rte_free(hw->arq_buf);
+	rte_free(hw->vf_vsi_map);
+	rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..58647d87f
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "base/ice_type.h"
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+	TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+	enum virtchnl_ops v_op;
+	enum iavf_status v_ret;
+
+	uint16_t req_msglen;
+	uint8_t *req_msg;
+
+	uint16_t rsp_msglen;
+	uint16_t rsp_buflen;
+	uint8_t *rsp_msgbuf;
+
+	volatile int pending;
+};
+
+struct ice_dcf_hw {
+	struct iavf_hw avf;
+
+	rte_spinlock_t vc_cmd_send_lock;
+	rte_spinlock_t vc_cmd_queue_lock;
+	TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+	void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
+				uint8_t *msg, uint16_t msglen);
+
+	uint8_t *arq_buf;
+
+	uint16_t num_vfs;
+	uint16_t *vf_vsi_map;
+
+	struct virtchnl_version_info virtchnl_version;
+	struct virtchnl_vf_resource *vf_res; /* VF resource */
+	struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+				 struct dcf_virtchnl_cmd *cmd);
+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+			void *buf, uint16_t buf_size);
+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..f65b962d4
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+		  __rte_unused struct rte_mbuf **bufs,
+		  __rte_unused uint16_t nb_pkts)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+		     struct rte_eth_dev_info *dev_info)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)-1;
+	dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+	dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+	return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+		  __rte_unused struct rte_eth_stats *igb_stats)
+{
+	return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+			enum rte_filter_type filter_type,
+			__rte_unused enum rte_filter_op filter_op,
+			__rte_unused void *arg)
+{
+	int ret = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	switch (filter_type) {
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+			    filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return;
+
+	dev->dev_ops = NULL;
+	dev->rx_pkt_burst = NULL;
+	dev->tx_pkt_burst = NULL;
+
+	ice_dcf_uninit_parent_adapter(dev);
+	ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+		    __rte_unused int wait_to_complete)
+{
+	return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t rx_queue_id,
+		       __rte_unused uint16_t nb_rx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_rxconf *rx_conf,
+		       __rte_unused struct rte_mempool *mb_pool)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+	return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+		       uint16_t tx_queue_id,
+		       __rte_unused uint16_t nb_tx_desc,
+		       __rte_unused unsigned int socket_id,
+		       __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+	struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+	dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+	return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+	.dev_start               = ice_dcf_dev_start,
+	.dev_stop                = ice_dcf_dev_stop,
+	.dev_close               = ice_dcf_dev_close,
+	.dev_configure           = ice_dcf_dev_configure,
+	.dev_infos_get           = ice_dcf_dev_info_get,
+	.rx_queue_setup          = ice_dcf_rx_queue_setup,
+	.tx_queue_setup          = ice_dcf_tx_queue_setup,
+	.rx_queue_release        = ice_dcf_queue_release,
+	.tx_queue_release        = ice_dcf_queue_release,
+	.link_update             = ice_dcf_link_update,
+	.stats_get               = ice_dcf_stats_get,
+	.stats_reset             = ice_dcf_stats_reset,
+	.promiscuous_enable      = ice_dcf_dev_promiscuous_enable,
+	.promiscuous_disable     = ice_dcf_dev_promiscuous_disable,
+	.allmulticast_enable     = ice_dcf_dev_allmulticast_enable,
+	.allmulticast_disable    = ice_dcf_dev_allmulticast_disable,
+	.filter_ctrl             = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+	eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+	eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+	eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+	adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
+	if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+		PMD_DRV_LOG(ERR, "Failed to init DCF hardware");
+		return -1;
+	}
+
+	if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
+		PMD_DRV_LOG(ERR, "Failed to init DCF parent adapter");
+		ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+	ice_dcf_dev_close(eth_dev);
+
+	return 0;
+}
+
+static int
+handle_dcf_arg(__rte_unused const char *key, const char *value,
+	       __rte_unused void *arg)
+{
+	bool *dcf = arg;
+
+	if (arg == NULL || value == NULL)
+		return -EINVAL;
+
+	if (strcmp(value, "dcf") == 0)
+		*dcf = true;
+	else
+		*dcf = false;
+
+	return 0;
+}
+
+static bool
+check_cap_dcf_enable(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	bool enable = false;
+
+	if (devargs == NULL)
+		return false;
+
+	kvlist = rte_kvargs_parse(devargs->args, NULL);
+	if (kvlist == NULL)
+		return false;
+
+	rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
+
+	rte_kvargs_free(kvlist);
+
+	return enable;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+			     struct rte_pci_device *pci_dev)
+{
+	if (!check_cap_dcf_enable(pci_dev->device.devargs))
+		return 1; /* continue to probe */
+
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+					     sizeof(struct ice_dcf_adapter),
+					     ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+	return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+	{ RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+	.id_table = pci_id_ice_dcf_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+	.probe = eth_ice_dcf_pci_probe,
+	.remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..e95266599
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "base/ice_common.h"
+#include "base/ice_adminq_cmd.h"
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS  1
+
+struct ice_dcf_queue {
+	uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+	struct ice_adapter parent; /* Must be first */
+
+	struct ice_dcf_hw real_hw;
+	struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+	struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+				 uint8_t *msg, uint16_t msglen);
+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
new file mode 100644
index 000000000..bca9cd34a
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -0,0 +1,348 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rte_alarm.h>
+
+#include "ice_dcf_ethdev.h"
+#include "ice_generic_flow.h"
+
+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL	100000 /* us */
+
+static __rte_always_inline void
+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
+		       uint16_t vsi_map)
+{
+	struct ice_vsi_ctx *vsi_ctx;
+
+	if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
+		PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
+		return;
+	}
+
+	vsi_ctx = hw->vsi_ctx[vsi_handle];
+
+	if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
+		if (!vsi_ctx)
+			vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
+
+		if (!vsi_ctx) {
+			PMD_DRV_LOG(ERR, "No memory for vsi context %u",
+				    vsi_handle);
+			return;
+		}
+
+		vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
+					      VIRTCHNL_DCF_VF_VSI_ID_S;
+		hw->vsi_ctx[vsi_handle] = vsi_ctx;
+
+		PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
+			    vsi_handle, vsi_ctx->vsi_num);
+	} else {
+		hw->vsi_ctx[vsi_handle] = NULL;
+
+		if (vsi_ctx)
+			ice_free(hw, vsi_ctx);
+
+		PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
+	}
+}
+
+static void
+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
+			  uint16_t *vf_vsi_map)
+{
+	uint16_t vf_id;
+
+	for (vf_id = 0; vf_id < num_vfs; vf_id++)
+		ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
+}
+
+static void
+ice_dcf_vsi_update_service_handler(void *param)
+{
+	struct ice_dcf_hw *hw = param;
+
+	if (!ice_dcf_handle_vsi_update_event(hw)) {
+		struct ice_dcf_adapter *dcf_ad =
+			container_of(hw, struct ice_dcf_adapter, real_hw);
+
+		ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
+					  hw->num_vfs, hw->vf_vsi_map);
+	}
+}
+
+void
+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+			    uint8_t *msg, uint16_t msglen)
+{
+	struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+
+	if (msglen < sizeof(struct virtchnl_pf_event)) {
+		PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
+		return;
+	}
+
+	switch (pf_msg->event) {
+	case VIRTCHNL_EVENT_RESET_IMPENDING:
+		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+		rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL * 2,
+				  ice_dcf_vsi_update_service_handler, dcf_hw);
+		break;
+	case VIRTCHNL_EVENT_LINK_CHANGE:
+		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
+		break;
+	case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
+		break;
+	case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
+		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
+			    pf_msg->event_data.vf_vsi_map.vf_id,
+			    pf_msg->event_data.vf_vsi_map.vsi_id);
+		rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
+				  ice_dcf_vsi_update_service_handler, dcf_hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
+		break;
+	}
+}
+
+static int
+ice_dcf_init_parent_hw(struct ice_hw *hw)
+{
+	struct ice_aqc_get_phy_caps_data *pcaps;
+	enum ice_status status;
+
+	status = ice_aq_get_fw_ver(hw, NULL);
+	if (status)
+		return status;
+
+	status = ice_get_caps(hw);
+	if (status)
+		return status;
+
+	hw->port_info = (struct ice_port_info *)
+			ice_malloc(hw, sizeof(*hw->port_info));
+	if (!hw->port_info)
+		return ICE_ERR_NO_MEMORY;
+
+	/* set the back pointer to HW */
+	hw->port_info->hw = hw;
+
+	/* Initialize port_info struct with switch configuration data */
+	status = ice_get_initial_sw_cfg(hw);
+	if (status)
+		goto err_unroll_alloc;
+
+	pcaps = (struct ice_aqc_get_phy_caps_data *)
+		ice_malloc(hw, sizeof(*pcaps));
+	if (!pcaps) {
+		status = ICE_ERR_NO_MEMORY;
+		goto err_unroll_alloc;
+	}
+
+	/* Initialize port_info struct with PHY capabilities */
+	status = ice_aq_get_phy_caps(hw->port_info, false,
+				     ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
+	ice_free(hw, pcaps);
+	if (status)
+		goto err_unroll_alloc;
+
+	/* Initialize port_info struct with link information */
+	status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
+	if (status)
+		goto err_unroll_alloc;
+
+	status = ice_init_fltr_mgmt_struct(hw);
+	if (status)
+		goto err_unroll_alloc;
+
+	status = ice_init_hw_tbls(hw);
+	if (status)
+		goto err_unroll_fltr_mgmt_struct;
+
+	PMD_DRV_LOG(INFO,
+		    "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
+		    hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
+		    hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
+		    hw->fw_build);
+
+	return ICE_SUCCESS;
+
+err_unroll_fltr_mgmt_struct:
+	ice_cleanup_fltr_mgmt_struct(hw);
+err_unroll_alloc:
+	ice_free(hw, hw->port_info);
+	hw->port_info = NULL;
+
+	return status;
+}
+
+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
+{
+	ice_cleanup_fltr_mgmt_struct(hw);
+
+	ice_free_seg(hw);
+	ice_free_hw_tbls(hw);
+
+	if (hw->port_info) {
+		ice_free(hw, hw->port_info);
+		hw->port_info = NULL;
+	}
+
+	ice_clear_all_vsi_ctx(hw);
+}
+
+static int
+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
+{
+	struct ice_dcf_adapter *dcf_adapter =
+			container_of(hw, struct ice_dcf_adapter, parent.hw);
+
+	/* TODO: check with DSN firstly by iAVF */
+	PMD_DRV_LOG(DEBUG,
+		    "DCF VSI_ID = %u",
+		    dcf_adapter->real_hw.vsi_id);
+
+	snprintf(pkg_name,
+		 ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
+	if (!access(pkg_name, 0))
+		return 0;
+
+	snprintf(pkg_name,
+		 ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
+	if (!access(pkg_name, 0))
+		return 0;
+
+	return -1;
+}
+
+static int
+ice_dcf_load_pkg(struct ice_hw *hw)
+{
+	char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
+	uint8_t *pkg_buf;
+	uint32_t buf_len;
+	struct stat st;
+	FILE *fp;
+	int err;
+
+	if (ice_dcf_request_pkg_name(hw, pkg_name)) {
+		PMD_INIT_LOG(ERR, "failed to locate the package file");
+		return -ENOENT;
+	}
+
+	PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
+
+	err = stat(pkg_name, &st);
+	if (err) {
+		PMD_INIT_LOG(ERR, "failed to get file status");
+		return err;
+	}
+
+	buf_len = st.st_size;
+	pkg_buf = rte_malloc(NULL, buf_len, 0);
+	if (!pkg_buf) {
+		PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
+			     buf_len);
+		return -1;
+	}
+
+	fp = fopen(pkg_name, "rb");
+	if (!fp)  {
+		PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
+		err = -1;
+		goto ret;
+	}
+
+	err = fread(pkg_buf, buf_len, 1, fp);
+	fclose(fp);
+	if (err != 1) {
+		PMD_INIT_LOG(ERR, "failed to read package data");
+		err = -1;
+		goto ret;
+	}
+
+	err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
+	if (err)
+		PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
+
+ret:
+	rte_free(pkg_buf);
+	return err;
+}
+
+int
+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+	struct ice_adapter *parent_adapter = &adapter->parent;
+	struct ice_hw *parent_hw = &parent_adapter->hw;
+	struct ice_dcf_hw *hw = &adapter->real_hw;
+	const struct rte_ether_addr *mac;
+	int err;
+
+	parent_adapter->eth_dev = eth_dev;
+	parent_adapter->pf.adapter = parent_adapter;
+	parent_adapter->pf.dev_data = eth_dev->data;
+	parent_hw->back = parent_adapter;
+	parent_hw->mac_type = ICE_MAC_GENERIC;
+	parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
+
+	ice_init_lock(&parent_hw->adminq.sq_lock);
+	ice_init_lock(&parent_hw->adminq.rq_lock);
+	parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
+	parent_hw->aq_send_cmd_param = &adapter->real_hw;
+	parent_hw->dcf_enabled = true;
+
+	err = ice_dcf_init_parent_hw(parent_hw);
+	if (err) {
+		PMD_DRV_LOG(ERR, "failed to init the DCF parent hardware with error %d",
+			    err);
+		return err;
+	}
+
+	err = ice_dcf_load_pkg(parent_hw);
+	if (err) {
+		PMD_DRV_LOG(ERR, "failed to load package with error %d",
+			    err);
+		goto uninit_hw;
+	}
+	parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+
+	ice_dcf_update_vf_vsi_map(parent_hw,
+				  hw->num_vfs, hw->vf_vsi_map);
+
+	mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
+	if (rte_is_valid_assigned_ether_addr(mac))
+		rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
+	else
+		rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
+
+	eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
+
+	return 0;
+
+uninit_hw:
+	ice_dcf_uninit_parent_hw(parent_hw);
+	return err;
+}
+
+void
+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+	struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+	struct ice_adapter *parent_adapter = &adapter->parent;
+	struct ice_hw *parent_hw = &parent_adapter->hw;
+
+	eth_dev->data->mac_addrs = NULL;
+
+	rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
+			     &adapter->real_hw);
+
+	ice_dcf_uninit_parent_hw(parent_hw);
+}
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0df8ddc0f 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
 	'ice_hash.c'
 	)
 
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
 
 if arch_subdir == 'x86'
 	sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,8 @@ if arch_subdir == 'x86'
 	endif
 endif
 
+sources += files('ice_dcf.c',
+		 'ice_dcf_parent.c',
+		 'ice_dcf_ethdev.c')
+
 install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD)       += -lrte_pmd_iavf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD)        += -lrte_pmd_ice
 IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
 ifeq ($(findstring y,$(IAVF-y)),y)
 _LDLIBS-y += -lrte_common_iavf
 endif
-- 
2.25.1


^ permalink raw reply	[relevance 1%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  2020-03-09  8:55  0%             ` Tonghao Zhang
  2020-03-09  9:05  0%               ` Olivier Matz
@ 2020-03-09 13:15  0%               ` David Marchand
  2020-03-16  7:43  0%                 ` Tonghao Zhang
  1 sibling, 1 reply; 200+ results
From: David Marchand @ 2020-03-09 13:15 UTC (permalink / raw)
  To: Tonghao Zhang
  Cc: Olivier Matz, Andrew Rybchenko, Jerin Jacob, dpdk-dev, Gage Eads,
	Artem V. Andreev, Jerin Jacob, Nithin Dabilpuram, Vamsi Attunuru,
	Hemant Agrawal, Burakov, Anatoly, Bruce Richardson

On Mon, Mar 9, 2020 at 9:56 AM Tonghao Zhang <xiangxia.m.yue@gmail.com> wrote:
> On Mon, Mar 9, 2020 at 4:27 PM Olivier Matz <olivier.matz@6wind.com> wrote:
> > The fact that the ops index changes during mempool driver lifetime is
> > indeed frightening, especially knowning that this is a dynamic
> > registration that could happen at any moment in the life of the
> > application. Also, breaking the ABI is not desirable.
> That solution is better.
>
> > Let me try to propose something else to solve your issue:
> >
> > 1/ At init, the primary process allocates a struct in shared memory
> >    (named memzone):
> >
> >    struct rte_mempool_shared_ops {
> >      size_t num_mempool_ops;
> >      struct {
> >        char name[RTE_MEMPOOL_OPS_NAMESIZE];
> >      } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];
> >      char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];
> >      rte_spinlock_t mempool;
> >    }
> >
> > 2/ When we register a mempool ops, we first get a name and id from the
> >    shared struct: with the lock held, lookup for the registered name and
> >    return its index, else get the last id and copy the name in the struct.
> >
> > 3/ Then do as before (in the per-process global table), except that we
> >    reuse the registered id.
> >
> > We can remove the num_ops field from rte_mempool_ops_table.
> >
> > Thoughts?

It seems better, just adding Anatoly and Bruce who know more about multiprocess.

Tonghao, could you add a unit test to exhibit the issue as part of this work?

Thanks.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  2020-03-09  8:55  0%             ` Tonghao Zhang
@ 2020-03-09  9:05  0%               ` Olivier Matz
  2020-03-09 13:15  0%               ` David Marchand
  1 sibling, 0 replies; 200+ results
From: Olivier Matz @ 2020-03-09  9:05 UTC (permalink / raw)
  To: Tonghao Zhang
  Cc: Andrew Rybchenko, Jerin Jacob, dpdk-dev, Gage Eads,
	Artem V. Andreev, Jerin Jacob, Nithin Dabilpuram, Vamsi Attunuru,
	Hemant Agrawal

On Mon, Mar 09, 2020 at 04:55:28PM +0800, Tonghao Zhang wrote:
> On Mon, Mar 9, 2020 at 4:27 PM Olivier Matz <olivier.matz@6wind.com> wrote:
> >
> > Hi,
> >
> > On Mon, Mar 09, 2020 at 11:01:25AM +0800, Tonghao Zhang wrote:
> > > On Sat, Mar 7, 2020 at 8:54 PM Andrew Rybchenko
> > > <arybchenko@solarflare.com> wrote:
> > > >
> > > > On 3/7/20 3:51 PM, Andrew Rybchenko wrote:
> > > > > On 3/6/20 4:37 PM, Jerin Jacob wrote:
> > > > >> On Fri, Mar 6, 2020 at 7:06 PM <xiangxia.m.yue@gmail.com> wrote:
> > > > >>> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > > > >>>
> > > > >>> The order of mempool initiation affects mempool index in the
> > > > >>> rte_mempool_ops_table. For example, when building APPs with:
> > > > >>>
> > > > >>> $ gcc -lrte_mempool_bucket -lrte_mempool_ring ...
> > > > >>>
> > > > >>> The "bucket" mempool will be registered firstly, and its index
> > > > >>> in table is 0 while the index of "ring" mempool is 1. DPDK
> > > > >>> uses the mk/rte.app.mk to build APPs, and others, for example,
> > > > >>> Open vSwitch, use the libdpdk.a or libdpdk.so to build it.
> > > > >>> The mempool lib linked in dpdk and Open vSwitch is different.
> > > > >>>
> > > > >>> The mempool can be used between primary and secondary process,
> > > > >>> such as dpdk-pdump and pdump-pmd/Open vSwitch(pdump enabled).
> > > > >>> There will be a crash because dpdk-pdump creates the "ring_mp_mc"
> > > > >>> ring which index in table is 0, but the index of "bucket" ring
> > > > >>> is 0 in Open vSwitch. If Open vSwitch use the index 0 to get
> > > > >>> mempool ops and malloc memory from mempool. The crash will occur:
> > > > >>>
> > > > >>>      bucket_dequeue (access null and crash)
> > > > >>>      rte_mempool_get_ops (should get "ring_mp_mc",
> > > > >>>                           but get "bucket" mempool)
> > > > >>>      rte_mempool_ops_dequeue_bulk
> > > > >>>      ...
> > > > >>>      rte_pktmbuf_alloc
> > > > >>>      rte_pktmbuf_copy
> > > > >>>      pdump_copy
> > > > >>>      pdump_rx
> > > > >>>      rte_eth_rx_burst
> > > > >>>
> > > > >>> To avoid the crash, there are some solution:
> > > > >>> * constructor priority: Different mempool uses different
> > > > >>>    priority in RTE_INIT, but it's not easy to maintain.
> > > > >>>
> > > > >>> * change mk/rte.app.mk: Change the order in mk/rte.app.mk to
> > > > >>>    be same as libdpdk.a/libdpdk.so, but when adding a new mempool
> > > > >>>    driver in future, we must make sure the order.
> > > > >>>
> > > > >>> * register mempool orderly: Sort the mempool when registering,
> > > > >>>    so the lib linked will not affect the index in mempool table.
> > > > >>>
> > > > >>> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > > > >>> Acked-by: Olivier Matz <olivier.matz@6wind.com>
> > > > >> Acked-by: Jerin Jacob <jerinj@marvell.com>
> > > > >
> > > > > The patch is OK, but the fact that ops index changes during
> > > > > mempool driver lifetime is frightening. In fact it breaks
> > > > > rte_mempool_register_ops() return value semantics (read
> > > > > as API break). The return value is not used in DPDK, but it
> > > > > is a public function. If I'm not mistaken it should be taken
> > > > > into account.
> >
> > Good points.
> >
> > The fact that the ops index changes during mempool driver lifetime is
> > indeed frightening, especially knowning that this is a dynamic
> > registration that could happen at any moment in the life of the
> > application. Also, breaking the ABI is not desirable.
> That solution is better.
> 
> > Let me try to propose something else to solve your issue:
> >
> > 1/ At init, the primary process allocates a struct in shared memory
> >    (named memzone):
> >
> >    struct rte_mempool_shared_ops {
> >      size_t num_mempool_ops;
> >      struct {
> >        char name[RTE_MEMPOOL_OPS_NAMESIZE];
> >      } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];


> >      char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];

oops I forgot to remove this line (replaced by mini-struct just above).


> >      rte_spinlock_t mempool;
> >    }
> >
> > 2/ When we register a mempool ops, we first get a name and id from the
> >    shared struct: with the lock held, lookup for the registered name and
> >    return its index, else get the last id and copy the name in the struct.
> >
> > 3/ Then do as before (in the per-process global table), except that we
> >    reuse the registered id.
> >
> > We can remove the num_ops field from rte_mempool_ops_table.
> >
> > Thoughts?
> >
> >
> > > Yes, should update the doc: how about this:
> > >
> > > diff --git a/lib/librte_mempool/rte_mempool.h b/lib/librte_mempool/rte_mempool.h
> > > index c90cf31..5a9c8a7 100644
> > > --- a/lib/librte_mempool/rte_mempool.h
> > > +++ b/lib/librte_mempool/rte_mempool.h
> > > @@ -904,7 +904,9 @@ int rte_mempool_ops_get_info(const struct rte_mempool *mp,
> > >   * @param ops
> > >   *   Pointer to an ops structure to register.
> > >   * @return
> > > - *   - >=0: Success; return the index of the ops struct in the table.
> > > + *   - >=0: Success; return the index of the last ops struct in the table.
> > > + *          The number of the ops struct registered is equal to index
> > > + *          returned + 1.
> > >   *   - -EINVAL - some missing callbacks while registering ops struct.
> > >   *   - -ENOSPC - the maximum number of ops structs has been reached.
> > >   */
> > > diff --git a/lib/librte_mempool/rte_mempool_ops.c
> > > b/lib/librte_mempool/rte_mempool_ops.c
> > > index b0da096..053f340 100644
> > > --- a/lib/librte_mempool/rte_mempool_ops.c
> > > +++ b/lib/librte_mempool/rte_mempool_ops.c
> > > @@ -26,7 +26,11 @@ struct rte_mempool_ops_table rte_mempool_ops_table = {
> > >         return strcmp(m_a->name, m_b->name);
> > >  }
> > >
> > > -/* add a new ops struct in rte_mempool_ops_table, return its index. */
> > > +/*
> > > + * add a new ops struct in rte_mempool_ops_table.
> > > + * on success, return the index of the last ops
> > > + * struct in the table.
> > > + */
> > >  int
> > >  rte_mempool_register_ops(const struct rte_mempool_ops *h)
> > >  {
> > > > > Also I remember patches which warn about above behaviour
> > > > > in documentation. If behaviour changes, corresponding
> > > > > documentation must be updated.
> > > >
> > > > One more point. If the patch is finally accepted it definitely
> > > > deserves few lines in release notes.
> > > OK, a separate patch should be sent before DPDK 20.05 release ?
> > > >
> > >
> > >
> > > --
> > > Thanks,
> > > Tonghao
> 
> 
> 
> --
> Thanks,
> Tonghao

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 0/7] vfio/pci: SR-IOV support
  2020-03-05 17:33  3%   ` Alex Williamson
@ 2020-03-06  9:21  0%     ` Tian, Kevin
  0 siblings, 0 replies; 200+ results
From: Tian, Kevin @ 2020-03-06  9:21 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm, linux-pci, linux-kernel, dev, mtosatti, thomas, bluca,
	jerinjacobk, Richardson, Bruce, cohuck, Jason Wang

> From: Alex Williamson
> Sent: Friday, March 6, 2020 1:34 AM
> 
> Hi Kevin,
> 
> Sorry for the delay, I've been out on PTO...
> 
> On Tue, 25 Feb 2020 02:33:27 +0000
> "Tian, Kevin" <kevin.tian@intel.com> wrote:
> 
> > > From: Alex Williamson
> > > Sent: Thursday, February 20, 2020 2:54 AM
> > >
> > > Changes since v1 are primarily to patch 3/7 where the commit log is
> > > rewritten, along with option parsing and failure logging based on
> > > upstream discussions.  The primary user visible difference is that
> > > option parsing is now much more strict.  If a vf_token option is
> > > provided that cannot be used, we generate an error.  As a result of
> > > this, opening a PF with a vf_token option will serve as a mechanism of
> > > setting the vf_token.  This seems like a more user friendly API than
> > > the alternative of sometimes requiring the option (VFs in use) and
> > > sometimes rejecting it, and upholds our desire that the option is
> > > always either used or rejected.
> > >
> > > This also means that the VFIO_DEVICE_FEATURE ioctl is not the only
> > > means of setting the VF token, which might call into question whether
> > > we absolutely need this new ioctl.  Currently I'm keeping it because I
> > > can imagine use cases, for example if a hypervisor were to support
> > > SR-IOV, the PF device might be opened without consideration for a VF
> > > token and we'd require the hypservisor to close and re-open the PF in
> > > order to set a known VF token, which is impractical.
> > >
> > > Series overview (same as provided with v1):
> >
> > Thanks for doing this!
> >
> > >
> > > The synopsis of this series is that we have an ongoing desire to drive
> > > PCIe SR-IOV PFs from userspace with VFIO.  There's an immediate need
> > > for this with DPDK drivers and potentially interesting future use
> >
> > Can you provide a link to the DPDK discussion?
> 
> There's a thread here which proposed an out-of-tree driver that enables
> a parallel sr-iov enabling interface for a vfio-pci own device.
> Clearly I felt strongly about it ;)
> 
> https://patches.dpdk.org/patch/58810/
> 
> Also, documentation for making use of an Intel FPGA device with DPDK
> requires the PF bound to igb_uio to support enabling SR-IOV:
> 
> https://doc.dpdk.org/guides/bbdevs/fpga_lte_fec.html

thanks. it is useful.

> 
> > > cases in virtualization.  We've been reluctant to add this support
> > > previously due to the dependency and trust relationship between the
> > > VF device and PF driver.  Minimally the PF driver can induce a denial
> > > of service to the VF, but depending on the specific implementation,
> > > the PF driver might also be responsible for moving data between VFs
> > > or have direct access to the state of the VF, including data or state
> > > otherwise private to the VF or VF driver.
> >
> > Just a loud thinking. While the motivation of VF token sounds reasonable
> > to me, I'm curious why the same concern is not raised in other usages.
> > For example, there is no such design in virtio framework, where the
> > virtio device could also be restarted, putting in separate process (vhost-
> user),
> > and even in separate VM (virtio-vhost-user), etc. Of course the para-
> > virtualized attribute of virtio implies some degree of trust, but as you
> > mentioned many SR-IOV implementations support VF->PF communication
> > which also implies some level of trust. It's perfectly fine if VFIO just tries
> > to do better than other sub-systems, but knowing how other people
> > tackle the similar problem may make the whole picture clearer. 😊
> >
> > +Jason.
> 
> We can follow the thread with Jason, but I can't really speak to
> whether virtio needs something similar or doesn't provide enough PF
> access to be concerned.  If they need a similar solution, we can
> collaborate, but the extension we're defining here is specifically part
> of the vfio-pci ABI, so it might not be easily portable to virtio.
> 
> > > To help resolve these concerns, we introduce a VF token into the VFIO
> > > PCI ABI, which acts as a shared secret key between drivers.  The
> > > userspace PF driver is required to set the VF token to a known value
> > > and userspace VF drivers are required to provide the token to access
> > > the VF device.  If a PF driver is restarted with VF drivers in use, it
> > > must also provide the current token in order to prevent a rogue
> > > untrusted PF driver from replacing a known driver.  The degree to
> > > which this new token is considered secret is left to the userspace
> > > drivers, the kernel intentionally provides no means to retrieve the
> > > current token.
> >
> > I'm wondering whether the token idea can be used beyond SR-IOV, e.g.
> > (1) we may allow vfio user space to manage Scalable IOV in the future,
> > which faces the similar challenge between the PF and mdev; (2) the
> > token might be used as a canonical way to replace off-tree acs-override
> > workaround, say, allowing the admin to assign devices within the
> > same iommu group to different VMs which trust each other. I'm not
> > sure how much complexity will be further introduced, but it's greatly
> > appreciated if you can help think a bit and if feasible abstract some
> > logic in vfio core layer for such potential usages...
> 
> I don't see how this can be used for ACS override.  Lacking ACS, we
> must assume lack of DMA isolation, which results in our IOMMU grouping.
> If we split IOMMU groups, that implies something that doesn't exist.  A
> user can already create a process that can own the vfio group and pass
> vfio devices to other tasks, with the restriction of having a single
> DMA address space.  If there is DMA isolation, then an mdev solution
> might be better, but given the IOMMU integration of SIOV, I'm not sure
> why the devices wouldn't simply be placed in separate groups by the
> IOMMU driver.  Thanks,

You are right. I overlooked the single DMA address space limitation.

> 
> Alex
> 
> > > Note that the above token is only required for this new model where
> > > both the PF and VF devices are usable through vfio-pci.  Existing
> > > models of VFIO drivers where the PF is used without SR-IOV enabled
> > > or the VF is bound to a userspace driver with an in-kernel, host PF
> > > driver are unaffected.
> > >
> > > The latter configuration above also highlights a new inverted scenario
> > > that is now possible, a userspace PF driver with in-kernel VF drivers.
> > > I believe this is a scenario that should be allowed, but should not be
> > > enabled by default.  This series includes code to set a default
> > > driver_override for VFs sourced from a vfio-pci user owned PF, such
> > > that the VFs are also bound to vfio-pci.  This model is compatible
> > > with tools like driverctl and allows the system administrator to
> > > decide if other bindings should be enabled.  The VF token interface
> > > above exists only between vfio-pci PF and VF drivers, once a VF is
> > > bound to another driver, the administrator has effectively pronounced
> > > the device as trusted.  The vfio-pci driver will note alternate
> > > binding in dmesg for logging and debugging purposes.
> > >
> > > Please review, comment, and test.  The example QEMU implementation
> > > provided with the RFC is still current for this version.  Thanks,
> > >
> > > Alex
> > >
> > > RFC:
> > >
> https://lore.kernel.org/lkml/158085337582.9445.17682266437583505502.stg
> > > it@gimli.home/
> > > v1:
> > >
> https://lore.kernel.org/lkml/158145472604.16827.15751375540102298130.st
> > > git@gimli.home/
> > >
> > > ---
> > >
> > > Alex Williamson (7):
> > >       vfio: Include optional device match in vfio_device_ops callbacks
> > >       vfio/pci: Implement match ops
> > >       vfio/pci: Introduce VF token
> > >       vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user
> > >       vfio/pci: Add sriov_configure support
> > >       vfio/pci: Remove dev_fmt definition
> > >       vfio/pci: Cleanup .probe() exit paths
> > >
> > >
> > >  drivers/vfio/pci/vfio_pci.c         |  383
> > > +++++++++++++++++++++++++++++++++--
> > >  drivers/vfio/pci/vfio_pci_private.h |   10 +
> > >  drivers/vfio/vfio.c                 |   20 +-
> > >  include/linux/vfio.h                |    4
> > >  include/uapi/linux/vfio.h           |   37 +++
> > >  5 files changed, 426 insertions(+), 28 deletions(-)
> >


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  2020-03-09  8:27  3%           ` Olivier Matz
@ 2020-03-09  8:55  0%             ` Tonghao Zhang
  2020-03-09  9:05  0%               ` Olivier Matz
  2020-03-09 13:15  0%               ` David Marchand
  2020-03-24  9:35  0%             ` Andrew Rybchenko
  1 sibling, 2 replies; 200+ results
From: Tonghao Zhang @ 2020-03-09  8:55 UTC (permalink / raw)
  To: Olivier Matz
  Cc: Andrew Rybchenko, Jerin Jacob, dpdk-dev, Gage Eads,
	Artem V. Andreev, Jerin Jacob, Nithin Dabilpuram, Vamsi Attunuru,
	Hemant Agrawal

On Mon, Mar 9, 2020 at 4:27 PM Olivier Matz <olivier.matz@6wind.com> wrote:
>
> Hi,
>
> On Mon, Mar 09, 2020 at 11:01:25AM +0800, Tonghao Zhang wrote:
> > On Sat, Mar 7, 2020 at 8:54 PM Andrew Rybchenko
> > <arybchenko@solarflare.com> wrote:
> > >
> > > On 3/7/20 3:51 PM, Andrew Rybchenko wrote:
> > > > On 3/6/20 4:37 PM, Jerin Jacob wrote:
> > > >> On Fri, Mar 6, 2020 at 7:06 PM <xiangxia.m.yue@gmail.com> wrote:
> > > >>> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > > >>>
> > > >>> The order of mempool initiation affects mempool index in the
> > > >>> rte_mempool_ops_table. For example, when building APPs with:
> > > >>>
> > > >>> $ gcc -lrte_mempool_bucket -lrte_mempool_ring ...
> > > >>>
> > > >>> The "bucket" mempool will be registered firstly, and its index
> > > >>> in table is 0 while the index of "ring" mempool is 1. DPDK
> > > >>> uses the mk/rte.app.mk to build APPs, and others, for example,
> > > >>> Open vSwitch, use the libdpdk.a or libdpdk.so to build it.
> > > >>> The mempool lib linked in dpdk and Open vSwitch is different.
> > > >>>
> > > >>> The mempool can be used between primary and secondary process,
> > > >>> such as dpdk-pdump and pdump-pmd/Open vSwitch(pdump enabled).
> > > >>> There will be a crash because dpdk-pdump creates the "ring_mp_mc"
> > > >>> ring which index in table is 0, but the index of "bucket" ring
> > > >>> is 0 in Open vSwitch. If Open vSwitch use the index 0 to get
> > > >>> mempool ops and malloc memory from mempool. The crash will occur:
> > > >>>
> > > >>>      bucket_dequeue (access null and crash)
> > > >>>      rte_mempool_get_ops (should get "ring_mp_mc",
> > > >>>                           but get "bucket" mempool)
> > > >>>      rte_mempool_ops_dequeue_bulk
> > > >>>      ...
> > > >>>      rte_pktmbuf_alloc
> > > >>>      rte_pktmbuf_copy
> > > >>>      pdump_copy
> > > >>>      pdump_rx
> > > >>>      rte_eth_rx_burst
> > > >>>
> > > >>> To avoid the crash, there are some solution:
> > > >>> * constructor priority: Different mempool uses different
> > > >>>    priority in RTE_INIT, but it's not easy to maintain.
> > > >>>
> > > >>> * change mk/rte.app.mk: Change the order in mk/rte.app.mk to
> > > >>>    be same as libdpdk.a/libdpdk.so, but when adding a new mempool
> > > >>>    driver in future, we must make sure the order.
> > > >>>
> > > >>> * register mempool orderly: Sort the mempool when registering,
> > > >>>    so the lib linked will not affect the index in mempool table.
> > > >>>
> > > >>> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > > >>> Acked-by: Olivier Matz <olivier.matz@6wind.com>
> > > >> Acked-by: Jerin Jacob <jerinj@marvell.com>
> > > >
> > > > The patch is OK, but the fact that ops index changes during
> > > > mempool driver lifetime is frightening. In fact it breaks
> > > > rte_mempool_register_ops() return value semantics (read
> > > > as API break). The return value is not used in DPDK, but it
> > > > is a public function. If I'm not mistaken it should be taken
> > > > into account.
>
> Good points.
>
> The fact that the ops index changes during mempool driver lifetime is
> indeed frightening, especially knowning that this is a dynamic
> registration that could happen at any moment in the life of the
> application. Also, breaking the ABI is not desirable.
That solution is better.

> Let me try to propose something else to solve your issue:
>
> 1/ At init, the primary process allocates a struct in shared memory
>    (named memzone):
>
>    struct rte_mempool_shared_ops {
>      size_t num_mempool_ops;
>      struct {
>        char name[RTE_MEMPOOL_OPS_NAMESIZE];
>      } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];
>      char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];
>      rte_spinlock_t mempool;
>    }
>
> 2/ When we register a mempool ops, we first get a name and id from the
>    shared struct: with the lock held, lookup for the registered name and
>    return its index, else get the last id and copy the name in the struct.
>
> 3/ Then do as before (in the per-process global table), except that we
>    reuse the registered id.
>
> We can remove the num_ops field from rte_mempool_ops_table.
>
> Thoughts?
>
>
> > Yes, should update the doc: how about this:
> >
> > diff --git a/lib/librte_mempool/rte_mempool.h b/lib/librte_mempool/rte_mempool.h
> > index c90cf31..5a9c8a7 100644
> > --- a/lib/librte_mempool/rte_mempool.h
> > +++ b/lib/librte_mempool/rte_mempool.h
> > @@ -904,7 +904,9 @@ int rte_mempool_ops_get_info(const struct rte_mempool *mp,
> >   * @param ops
> >   *   Pointer to an ops structure to register.
> >   * @return
> > - *   - >=0: Success; return the index of the ops struct in the table.
> > + *   - >=0: Success; return the index of the last ops struct in the table.
> > + *          The number of the ops struct registered is equal to index
> > + *          returned + 1.
> >   *   - -EINVAL - some missing callbacks while registering ops struct.
> >   *   - -ENOSPC - the maximum number of ops structs has been reached.
> >   */
> > diff --git a/lib/librte_mempool/rte_mempool_ops.c
> > b/lib/librte_mempool/rte_mempool_ops.c
> > index b0da096..053f340 100644
> > --- a/lib/librte_mempool/rte_mempool_ops.c
> > +++ b/lib/librte_mempool/rte_mempool_ops.c
> > @@ -26,7 +26,11 @@ struct rte_mempool_ops_table rte_mempool_ops_table = {
> >         return strcmp(m_a->name, m_b->name);
> >  }
> >
> > -/* add a new ops struct in rte_mempool_ops_table, return its index. */
> > +/*
> > + * add a new ops struct in rte_mempool_ops_table.
> > + * on success, return the index of the last ops
> > + * struct in the table.
> > + */
> >  int
> >  rte_mempool_register_ops(const struct rte_mempool_ops *h)
> >  {
> > > > Also I remember patches which warn about above behaviour
> > > > in documentation. If behaviour changes, corresponding
> > > > documentation must be updated.
> > >
> > > One more point. If the patch is finally accepted it definitely
> > > deserves few lines in release notes.
> > OK, a separate patch should be sent before DPDK 20.05 release ?
> > >
> >
> >
> > --
> > Thanks,
> > Tonghao



--
Thanks,
Tonghao

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH dpdk-dev v3] mempool: sort the rte_mempool_ops by name
  @ 2020-03-09  8:27  3%           ` Olivier Matz
  2020-03-09  8:55  0%             ` Tonghao Zhang
  2020-03-24  9:35  0%             ` Andrew Rybchenko
  0 siblings, 2 replies; 200+ results
From: Olivier Matz @ 2020-03-09  8:27 UTC (permalink / raw)
  To: Tonghao Zhang
  Cc: Andrew Rybchenko, Jerin Jacob, dpdk-dev, Gage Eads,
	Artem V. Andreev, Jerin Jacob, Nithin Dabilpuram, Vamsi Attunuru,
	Hemant Agrawal

Hi,

On Mon, Mar 09, 2020 at 11:01:25AM +0800, Tonghao Zhang wrote:
> On Sat, Mar 7, 2020 at 8:54 PM Andrew Rybchenko
> <arybchenko@solarflare.com> wrote:
> >
> > On 3/7/20 3:51 PM, Andrew Rybchenko wrote:
> > > On 3/6/20 4:37 PM, Jerin Jacob wrote:
> > >> On Fri, Mar 6, 2020 at 7:06 PM <xiangxia.m.yue@gmail.com> wrote:
> > >>> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > >>>
> > >>> The order of mempool initiation affects mempool index in the
> > >>> rte_mempool_ops_table. For example, when building APPs with:
> > >>>
> > >>> $ gcc -lrte_mempool_bucket -lrte_mempool_ring ...
> > >>>
> > >>> The "bucket" mempool will be registered firstly, and its index
> > >>> in table is 0 while the index of "ring" mempool is 1. DPDK
> > >>> uses the mk/rte.app.mk to build APPs, and others, for example,
> > >>> Open vSwitch, use the libdpdk.a or libdpdk.so to build it.
> > >>> The mempool lib linked in dpdk and Open vSwitch is different.
> > >>>
> > >>> The mempool can be used between primary and secondary process,
> > >>> such as dpdk-pdump and pdump-pmd/Open vSwitch(pdump enabled).
> > >>> There will be a crash because dpdk-pdump creates the "ring_mp_mc"
> > >>> ring which index in table is 0, but the index of "bucket" ring
> > >>> is 0 in Open vSwitch. If Open vSwitch use the index 0 to get
> > >>> mempool ops and malloc memory from mempool. The crash will occur:
> > >>>
> > >>>      bucket_dequeue (access null and crash)
> > >>>      rte_mempool_get_ops (should get "ring_mp_mc",
> > >>>                           but get "bucket" mempool)
> > >>>      rte_mempool_ops_dequeue_bulk
> > >>>      ...
> > >>>      rte_pktmbuf_alloc
> > >>>      rte_pktmbuf_copy
> > >>>      pdump_copy
> > >>>      pdump_rx
> > >>>      rte_eth_rx_burst
> > >>>
> > >>> To avoid the crash, there are some solution:
> > >>> * constructor priority: Different mempool uses different
> > >>>    priority in RTE_INIT, but it's not easy to maintain.
> > >>>
> > >>> * change mk/rte.app.mk: Change the order in mk/rte.app.mk to
> > >>>    be same as libdpdk.a/libdpdk.so, but when adding a new mempool
> > >>>    driver in future, we must make sure the order.
> > >>>
> > >>> * register mempool orderly: Sort the mempool when registering,
> > >>>    so the lib linked will not affect the index in mempool table.
> > >>>
> > >>> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > >>> Acked-by: Olivier Matz <olivier.matz@6wind.com>
> > >> Acked-by: Jerin Jacob <jerinj@marvell.com>
> > >
> > > The patch is OK, but the fact that ops index changes during
> > > mempool driver lifetime is frightening. In fact it breaks
> > > rte_mempool_register_ops() return value semantics (read
> > > as API break). The return value is not used in DPDK, but it
> > > is a public function. If I'm not mistaken it should be taken
> > > into account.

Good points.

The fact that the ops index changes during mempool driver lifetime is
indeed frightening, especially knowning that this is a dynamic
registration that could happen at any moment in the life of the
application. Also, breaking the ABI is not desirable.

Let me try to propose something else to solve your issue:

1/ At init, the primary process allocates a struct in shared memory
   (named memzone):

   struct rte_mempool_shared_ops {
     size_t num_mempool_ops;
     struct {
       char name[RTE_MEMPOOL_OPS_NAMESIZE];
     } mempool_ops[RTE_MEMPOOL_MAX_OPS_IDX];
     char *mempool_ops_name[RTE_MEMPOOL_MAX_OPS_IDX];
     rte_spinlock_t mempool;
   }

2/ When we register a mempool ops, we first get a name and id from the
   shared struct: with the lock held, lookup for the registered name and
   return its index, else get the last id and copy the name in the struct.

3/ Then do as before (in the per-process global table), except that we
   reuse the registered id.

We can remove the num_ops field from rte_mempool_ops_table.

Thoughts?


> Yes, should update the doc: how about this:
> 
> diff --git a/lib/librte_mempool/rte_mempool.h b/lib/librte_mempool/rte_mempool.h
> index c90cf31..5a9c8a7 100644
> --- a/lib/librte_mempool/rte_mempool.h
> +++ b/lib/librte_mempool/rte_mempool.h
> @@ -904,7 +904,9 @@ int rte_mempool_ops_get_info(const struct rte_mempool *mp,
>   * @param ops
>   *   Pointer to an ops structure to register.
>   * @return
> - *   - >=0: Success; return the index of the ops struct in the table.
> + *   - >=0: Success; return the index of the last ops struct in the table.
> + *          The number of the ops struct registered is equal to index
> + *          returned + 1.
>   *   - -EINVAL - some missing callbacks while registering ops struct.
>   *   - -ENOSPC - the maximum number of ops structs has been reached.
>   */
> diff --git a/lib/librte_mempool/rte_mempool_ops.c
> b/lib/librte_mempool/rte_mempool_ops.c
> index b0da096..053f340 100644
> --- a/lib/librte_mempool/rte_mempool_ops.c
> +++ b/lib/librte_mempool/rte_mempool_ops.c
> @@ -26,7 +26,11 @@ struct rte_mempool_ops_table rte_mempool_ops_table = {
>         return strcmp(m_a->name, m_b->name);
>  }
> 
> -/* add a new ops struct in rte_mempool_ops_table, return its index. */
> +/*
> + * add a new ops struct in rte_mempool_ops_table.
> + * on success, return the index of the last ops
> + * struct in the table.
> + */
>  int
>  rte_mempool_register_ops(const struct rte_mempool_ops *h)
>  {
> > > Also I remember patches which warn about above behaviour
> > > in documentation. If behaviour changes, corresponding
> > > documentation must be updated.
> >
> > One more point. If the patch is finally accepted it definitely
> > deserves few lines in release notes.
> OK, a separate patch should be sent before DPDK 20.05 release ?
> >
> 
> 
> -- 
> Thanks,
> Tonghao

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-03-05  9:19  0%       ` Hemant Agrawal (OSS)
@ 2020-03-06 10:12  3%         ` David Marchand
  2020-03-10 10:36  3%           ` Dodji Seketeli
  0 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-03-06 10:12 UTC (permalink / raw)
  To: Hemant Agrawal (OSS)
  Cc: Yigit, Ferruh, dev, Neil Horman, Thomas Monjalon, Dodji Seketeli

On Thu, Mar 5, 2020 at 10:19 AM Hemant Agrawal (OSS)
<hemant.agrawal@oss.nxp.com> wrote:
> > On Thu, Mar 5, 2020 at 10:06 AM Hemant Agrawal (OSS)
> > <hemant.agrawal@oss.nxp.com> wrote:
> > >
> > > Hi David,
> > > > On Mon, Mar 2, 2020 at 10:26 AM Hemant Agrawal
> > > > <hemant.agrawal@nxp.com> wrote:
> > > > >
> > > > > This patch series add various patches for enhancing and fixing NXP
> > > > > fslmc bus, dpaa bus, and dpaax.
> > > > >
> > > > > - the main change is support to allow thread migration across
> > > > > lcores
> > > > > - improving the multi-process support
> > > >
> > > > This series triggers an ABI warning that must be investigated.
> > > >https://travis-ci.com/ovsrobot/dpdk/jobs/292904119#L2233
> > >
> > > [Hemant]
> > > As per the logs:
> > >
> > > Variables changes summary: 1 Removed, 2 Changed, 0 Added variables
> > > 1 Removed variable:
> > >   'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'
> > {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
> > > 2 Changed variables:
> > >   [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at
> > dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
> > >   [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at
> > > dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16
> > >
> > > Error: ABI issue reported for 'abidiff --suppr devtools/libabigail.abignore --
> > no-added-syms --headers-dir1 reference/usr/local/include --headers-dir2
> > install/usr/local/include reference/dump/librte_bus_fslmc.dump
> > install/dump/librte_bus_fslmc.dump'
> > >
> > > ---------------
> > >
> > > These changes are w.r.t modifications in internal structures and variables.
> > They may be ignored.
> >
> > The ABI check considers symbol exposed in headers available to final users.
> > If those are internal, why are the headers public?
> >
>
> [Hemant] These symbols are not part of any public header files,  but they are part of *.map files to share them between different driver libs i.e bus_fslmc and net_dpaa2

I would expect libabigail to skip those symbols, so there is something
I have missed in how --headers-dirX work.


Anyway, all of those symbols in dpaa are part of the driver ABI.
We are still missing a way to mark internal symbols.
Neil had posted a framework for this
http://patchwork.dpdk.org/project/dpdk/list/?series=5004.

In order to get this series passing the checks, I recommend NXP
rebasing Neil scripts (I will help reviewing this part), then mark all
those symbols as internal in its drivers.
Other vendor will convert their drivers later, as there is no need at
the moment.

Thanks.

-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2 0/7] vfio/pci: SR-IOV support
  2020-02-25  2:33  0% ` Tian, Kevin
@ 2020-03-05 17:33  3%   ` Alex Williamson
  2020-03-06  9:21  0%     ` Tian, Kevin
  0 siblings, 1 reply; 200+ results
From: Alex Williamson @ 2020-03-05 17:33 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: kvm, linux-pci, linux-kernel, dev, mtosatti, thomas, bluca,
	jerinjacobk, Richardson, Bruce, cohuck, Jason Wang

Hi Kevin,

Sorry for the delay, I've been out on PTO...

On Tue, 25 Feb 2020 02:33:27 +0000
"Tian, Kevin" <kevin.tian@intel.com> wrote:

> > From: Alex Williamson
> > Sent: Thursday, February 20, 2020 2:54 AM
> > 
> > Changes since v1 are primarily to patch 3/7 where the commit log is
> > rewritten, along with option parsing and failure logging based on
> > upstream discussions.  The primary user visible difference is that
> > option parsing is now much more strict.  If a vf_token option is
> > provided that cannot be used, we generate an error.  As a result of
> > this, opening a PF with a vf_token option will serve as a mechanism of
> > setting the vf_token.  This seems like a more user friendly API than
> > the alternative of sometimes requiring the option (VFs in use) and
> > sometimes rejecting it, and upholds our desire that the option is
> > always either used or rejected.
> > 
> > This also means that the VFIO_DEVICE_FEATURE ioctl is not the only
> > means of setting the VF token, which might call into question whether
> > we absolutely need this new ioctl.  Currently I'm keeping it because I
> > can imagine use cases, for example if a hypervisor were to support
> > SR-IOV, the PF device might be opened without consideration for a VF
> > token and we'd require the hypservisor to close and re-open the PF in
> > order to set a known VF token, which is impractical.
> > 
> > Series overview (same as provided with v1):  
> 
> Thanks for doing this! 
> 
> > 
> > The synopsis of this series is that we have an ongoing desire to drive
> > PCIe SR-IOV PFs from userspace with VFIO.  There's an immediate need
> > for this with DPDK drivers and potentially interesting future use  
> 
> Can you provide a link to the DPDK discussion?

There's a thread here which proposed an out-of-tree driver that enables
a parallel sr-iov enabling interface for a vfio-pci own device.
Clearly I felt strongly about it ;)

https://patches.dpdk.org/patch/58810/

Also, documentation for making use of an Intel FPGA device with DPDK
requires the PF bound to igb_uio to support enabling SR-IOV:

https://doc.dpdk.org/guides/bbdevs/fpga_lte_fec.html

> > cases in virtualization.  We've been reluctant to add this support
> > previously due to the dependency and trust relationship between the
> > VF device and PF driver.  Minimally the PF driver can induce a denial
> > of service to the VF, but depending on the specific implementation,
> > the PF driver might also be responsible for moving data between VFs
> > or have direct access to the state of the VF, including data or state
> > otherwise private to the VF or VF driver.  
> 
> Just a loud thinking. While the motivation of VF token sounds reasonable
> to me, I'm curious why the same concern is not raised in other usages.
> For example, there is no such design in virtio framework, where the
> virtio device could also be restarted, putting in separate process (vhost-user),
> and even in separate VM (virtio-vhost-user), etc. Of course the para-
> virtualized attribute of virtio implies some degree of trust, but as you
> mentioned many SR-IOV implementations support VF->PF communication
> which also implies some level of trust. It's perfectly fine if VFIO just tries
> to do better than other sub-systems, but knowing how other people
> tackle the similar problem may make the whole picture clearer. 😊
> 
> +Jason.

We can follow the thread with Jason, but I can't really speak to
whether virtio needs something similar or doesn't provide enough PF
access to be concerned.  If they need a similar solution, we can
collaborate, but the extension we're defining here is specifically part
of the vfio-pci ABI, so it might not be easily portable to virtio.

> > To help resolve these concerns, we introduce a VF token into the VFIO
> > PCI ABI, which acts as a shared secret key between drivers.  The
> > userspace PF driver is required to set the VF token to a known value
> > and userspace VF drivers are required to provide the token to access
> > the VF device.  If a PF driver is restarted with VF drivers in use, it
> > must also provide the current token in order to prevent a rogue
> > untrusted PF driver from replacing a known driver.  The degree to
> > which this new token is considered secret is left to the userspace
> > drivers, the kernel intentionally provides no means to retrieve the
> > current token.  
> 
> I'm wondering whether the token idea can be used beyond SR-IOV, e.g.
> (1) we may allow vfio user space to manage Scalable IOV in the future,
> which faces the similar challenge between the PF and mdev; (2) the
> token might be used as a canonical way to replace off-tree acs-override
> workaround, say, allowing the admin to assign devices within the 
> same iommu group to different VMs which trust each other. I'm not
> sure how much complexity will be further introduced, but it's greatly
> appreciated if you can help think a bit and if feasible abstract some 
> logic in vfio core layer for such potential usages...

I don't see how this can be used for ACS override.  Lacking ACS, we
must assume lack of DMA isolation, which results in our IOMMU grouping.
If we split IOMMU groups, that implies something that doesn't exist.  A
user can already create a process that can own the vfio group and pass
vfio devices to other tasks, with the restriction of having a single
DMA address space.  If there is DMA isolation, then an mdev solution
might be better, but given the IOMMU integration of SIOV, I'm not sure
why the devices wouldn't simply be placed in separate groups by the
IOMMU driver.  Thanks,

Alex
 
> > Note that the above token is only required for this new model where
> > both the PF and VF devices are usable through vfio-pci.  Existing
> > models of VFIO drivers where the PF is used without SR-IOV enabled
> > or the VF is bound to a userspace driver with an in-kernel, host PF
> > driver are unaffected.
> > 
> > The latter configuration above also highlights a new inverted scenario
> > that is now possible, a userspace PF driver with in-kernel VF drivers.
> > I believe this is a scenario that should be allowed, but should not be
> > enabled by default.  This series includes code to set a default
> > driver_override for VFs sourced from a vfio-pci user owned PF, such
> > that the VFs are also bound to vfio-pci.  This model is compatible
> > with tools like driverctl and allows the system administrator to
> > decide if other bindings should be enabled.  The VF token interface
> > above exists only between vfio-pci PF and VF drivers, once a VF is
> > bound to another driver, the administrator has effectively pronounced
> > the device as trusted.  The vfio-pci driver will note alternate
> > binding in dmesg for logging and debugging purposes.
> > 
> > Please review, comment, and test.  The example QEMU implementation
> > provided with the RFC is still current for this version.  Thanks,
> > 
> > Alex
> > 
> > RFC:
> > https://lore.kernel.org/lkml/158085337582.9445.17682266437583505502.stg
> > it@gimli.home/
> > v1:
> > https://lore.kernel.org/lkml/158145472604.16827.15751375540102298130.st
> > git@gimli.home/
> > 
> > ---
> > 
> > Alex Williamson (7):
> >       vfio: Include optional device match in vfio_device_ops callbacks
> >       vfio/pci: Implement match ops
> >       vfio/pci: Introduce VF token
> >       vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user
> >       vfio/pci: Add sriov_configure support
> >       vfio/pci: Remove dev_fmt definition
> >       vfio/pci: Cleanup .probe() exit paths
> > 
> > 
> >  drivers/vfio/pci/vfio_pci.c         |  383
> > +++++++++++++++++++++++++++++++++--
> >  drivers/vfio/pci/vfio_pci_private.h |   10 +
> >  drivers/vfio/vfio.c                 |   20 +-
> >  include/linux/vfio.h                |    4
> >  include/uapi/linux/vfio.h           |   37 +++
> >  5 files changed, 426 insertions(+), 28 deletions(-)  
> 


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH 11/16] net/dpaa: enable Tx queue taildrop
  @ 2020-03-05 14:14  3%       ` Ferruh Yigit
  0 siblings, 0 replies; 200+ results
From: Ferruh Yigit @ 2020-03-05 14:14 UTC (permalink / raw)
  To: Gagandeep Singh, Hemant Agrawal; +Cc: dev, David Marchand, Neil Horman

On 3/5/2020 6:49 AM, Gagandeep Singh wrote:
> Hi Ferruh,
>>> diff --git a/drivers/bus/dpaa/rte_bus_dpaa_version.map
>> b/drivers/bus/dpaa/rte_bus_dpaa_version.map
>>> index e6ca4361e..86f5811b0 100644
>>> --- a/drivers/bus/dpaa/rte_bus_dpaa_version.map
>>> +++ b/drivers/bus/dpaa/rte_bus_dpaa_version.map
>>> @@ -94,3 +94,10 @@ DPDK_20.0 {
>>>
>>>  	local: *;
>>>  };
>>> +
>>> +EXPERIMENTAL {
>>> +	global:
>>> +
>>> +	qman_ern_poll_free;
>>> +	qman_ern_register_cb;
>>> +};
>>
>> Aren't these bus APIs internal (between net/crypto/event drivers and bus
>> libraries)? And they are *not* for applications to use.
>>
>> If they are only internal is there any point to make them experimental?
> 
> Yes, these are internal only APIS.  So, is it ok to add them directly into DPDK_20.0 section? 
> 

I think it is OK, but I don't know the what will be the affect to the ABI check
tools.

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-03-05  9:09  3%     ` David Marchand
@ 2020-03-05  9:19  0%       ` Hemant Agrawal (OSS)
  2020-03-06 10:12  3%         ` David Marchand
  0 siblings, 1 reply; 200+ results
From: Hemant Agrawal (OSS) @ 2020-03-05  9:19 UTC (permalink / raw)
  To: David Marchand, Hemant Agrawal (OSS); +Cc: Yigit, Ferruh, dev

Hi David,

> On Thu, Mar 5, 2020 at 10:06 AM Hemant Agrawal (OSS)
> <hemant.agrawal@oss.nxp.com> wrote:
> >
> > Hi David,
> > > On Mon, Mar 2, 2020 at 10:26 AM Hemant Agrawal
> > > <hemant.agrawal@nxp.com> wrote:
> > > >
> > > > This patch series add various patches for enhancing and fixing NXP
> > > > fslmc bus, dpaa bus, and dpaax.
> > > >
> > > > - the main change is support to allow thread migration across
> > > > lcores
> > > > - improving the multi-process support
> > >
> > > This series triggers an ABI warning that must be investigated.
> > >https://travis-ci.com/ovsrobot/dpdk/jobs/292904119#L2233
> >
> > [Hemant]
> > As per the logs:
> >
> > Variables changes summary: 1 Removed, 2 Changed, 0 Added variables
> > 1 Removed variable:
> >   'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'
> {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
> > 2 Changed variables:
> >   [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at
> dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
> >   [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at
> > dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16
> >
> > Error: ABI issue reported for 'abidiff --suppr devtools/libabigail.abignore --
> no-added-syms --headers-dir1 reference/usr/local/include --headers-dir2
> install/usr/local/include reference/dump/librte_bus_fslmc.dump
> install/dump/librte_bus_fslmc.dump'
> >
> > ---------------
> >
> > These changes are w.r.t modifications in internal structures and variables.
> They may be ignored.
> 
> The ABI check considers symbol exposed in headers available to final users.
> If those are internal, why are the headers public?
> 

[Hemant] These symbols are not part of any public header files,  but they are part of *.map files to share them between different driver libs i.e bus_fslmc and net_dpaa2 

> 
> --
> David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-03-05  9:06  3%   ` Hemant Agrawal (OSS)
@ 2020-03-05  9:09  3%     ` David Marchand
  2020-03-05  9:19  0%       ` Hemant Agrawal (OSS)
  0 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-03-05  9:09 UTC (permalink / raw)
  To: Hemant Agrawal (OSS); +Cc: Yigit, Ferruh, dev

On Thu, Mar 5, 2020 at 10:06 AM Hemant Agrawal (OSS)
<hemant.agrawal@oss.nxp.com> wrote:
>
> Hi David,
> > On Mon, Mar 2, 2020 at 10:26 AM Hemant Agrawal
> > <hemant.agrawal@nxp.com> wrote:
> > >
> > > This patch series add various patches for enhancing and fixing NXP
> > > fslmc bus, dpaa bus, and dpaax.
> > >
> > > - the main change is support to allow thread migration across lcores
> > > - improving the multi-process support
> >
> > This series triggers an ABI warning that must be investigated.
> >https://travis-ci.com/ovsrobot/dpdk/jobs/292904119#L2233
>
> [Hemant]
> As per the logs:
>
> Variables changes summary: 1 Removed, 2 Changed, 0 Added variables
> 1 Removed variable:
>   'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'    {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
> 2 Changed variables:
>   [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
>   [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16
>
> Error: ABI issue reported for 'abidiff --suppr devtools/libabigail.abignore --no-added-syms --headers-dir1 reference/usr/local/include --headers-dir2 install/usr/local/include reference/dump/librte_bus_fslmc.dump install/dump/librte_bus_fslmc.dump'
>
> ---------------
>
> These changes are w.r.t modifications in internal structures and variables. They may be ignored.

The ABI check considers symbol exposed in headers available to final users.
If those are internal, why are the headers public?


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  2020-03-02 13:01  3% ` David Marchand
@ 2020-03-05  9:06  3%   ` Hemant Agrawal (OSS)
  2020-03-05  9:09  3%     ` David Marchand
  0 siblings, 1 reply; 200+ results
From: Hemant Agrawal (OSS) @ 2020-03-05  9:06 UTC (permalink / raw)
  To: David Marchand; +Cc: Yigit, Ferruh, dev

Hi David,
> On Mon, Mar 2, 2020 at 10:26 AM Hemant Agrawal
> <hemant.agrawal@nxp.com> wrote:
> >
> > This patch series add various patches for enhancing and fixing NXP
> > fslmc bus, dpaa bus, and dpaax.
> >
> > - the main change is support to allow thread migration across lcores
> > - improving the multi-process support
> 
> This series triggers an ABI warning that must be investigated.
>https://travis-ci.com/ovsrobot/dpdk/jobs/292904119#L2233

[Hemant] 
As per the logs:

Variables changes summary: 1 Removed, 2 Changed, 0 Added variables
1 Removed variable:
  'dpaa2_portal_dqrr per_lcore_dpaa2_held_bufs'    {per_lcore_dpaa2_held_bufs@@DPDK_20.0}
2 Changed variables:
  [C]'dpaa2_io_portal_t dpaa2_io_portal[128]' was changed at dpaa2_hw_dpio.h:40:1: size of symbol changed from 5120 to 2048
  [C]'dpaa2_io_portal_t per_lcore__dpaa2_io' was changed at dpaa2_hw_dpio.h:20:1: size of symbol changed from 40 to 16

Error: ABI issue reported for 'abidiff --suppr devtools/libabigail.abignore --no-added-syms --headers-dir1 reference/usr/local/include --headers-dir2 install/usr/local/include reference/dump/librte_bus_fslmc.dump install/dump/librte_bus_fslmc.dump'

---------------

These changes are w.r.t modifications in internal structures and variables. They may be ignored.
> 
> --
> David Marchand


^ permalink raw reply	[relevance 3%]

* [dpdk-dev] DPDK techboard minutes of February 26
@ 2020-03-05  8:53  4% Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-03-05  8:53 UTC (permalink / raw)
  To: dev; +Cc: techboard

Minutes of Technical Board meeting, 2020-02-26

Members Attending: 9/11
  - Ferruh Yigit
  - Hemant Agrawal
  - Honnappa Nagarahalli
  - Jerin Jacob
  - Kevin Traynor
  - Konstantin Ananyev
  - Olivier Matz
  - Stephen Hemminger
  - Thomas Monjalon (Chair)

NOTE: Technical Board meetings happen every second Wednesday
on IRC channel #dpdk-board, at 3pm UTC.
Meetings are public and DPDK community members are welcome to attend.


1/ Technical Board status for the Governing Board meeting

  - ABI compatibility and tooling
  - SPDX conversion almost complete
  - Stepping away from Linux out-of-tree modules - new dpdk-kmods repo
  - Project scope discussion
  - PMDT project - new acceptance guidelines
  - Tooling trend (tracing, dumps, metrics, telemetry, monitoring)
  - ICC support: warning is not fatal
  - Windows port is progressing
  - new device classes: vDPA and regex
  - IPsec integration is difficult and progressing
  - Security pre-release list is not growing a lot
  - not tried any mentoring program this year


2/ Doc maintenance

Not much activity on documentation:
  - no content improvement
  - hard to get good reviews

Volunteers are welcome.

Maintenance of the documentation becomes a recurring techboard topic.


3/ Community lab goals

The Governing Board is evaluating how to progress with DPDK CI.
The Technical Board had to provide status and goals.

The first CI priority was already agreed in previous meeting:
basic ethdev functional testing on real NICs.

Coverity is doing static analysis regularly.
Travis is testing (requires integration for per-patch report):
  - compilation
  - ABI
  - libraries (without traffic)
OBS could be integrated for per-patch compilation testing.
The community lab is testing (for each patch):
  - compilation on more OSes
  - libraries (without traffic)
  - micro-benchmark with traffic on real HW
  - downstream projects (OVS, SPDK)

Key benefits of the community lab are:
  - real HW
  - vendor neutrality
  - confidence

The ideal lab should meet these requirements:
  - reliable
  - neutral
  - transparent visibility
  - coverage summary
  - trending graphs
  - easy to add/run a test
  - easy to reproduce a test locally
  - email reports
  - per-patch testing integrated with patchwork
  - per-commit testing (after merge in master or next-*)
  - per-release (including -rc) testing
and should run these tests:
  - compilation
  - functional
  - performance
  - interoperability
  - portability
  - downstream projects

Three roles are identified.
  1) Lab management: hosting, physical setup, monitoring.
  2) Framework/Infrastructure (can be remote):
     test integration, database, logs, reports, graphs, web pages.
  3) development of test cases:
     writing and/or evaluating test code for existing features.
     Future features could be gated by test requirement.

The third role require community involvement and volunteering.


4/ rte_graph + DPDK scope

The new library rte_graph is accepted to be part of dpdk.org.

During the next meeting, it will be discussed whether
adding rte_graph and similar libraries in the main repository,
or splitting in different git repositories.
The question of possibly dead/unused code in some libraries
should be debated as well.



^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2 0/7] vfio/pci: SR-IOV support
    2020-02-25  2:33  0% ` Tian, Kevin
@ 2020-03-05  6:38  0% ` Vamsi Krishna Attunuru
  1 sibling, 0 replies; 200+ results
From: Vamsi Krishna Attunuru @ 2020-03-05  6:38 UTC (permalink / raw)
  To: Alex Williamson, kvm
  Cc: linux-pci, linux-kernel, dev, mtosatti, thomas, bluca,
	jerinjacobk, bruce.richardson, cohuck


> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Alex Williamson
> Sent: Thursday, February 20, 2020 12:24 AM
> To: kvm@vger.kernel.org
> Cc: linux-pci@vger.kernel.org; linux-kernel@vger.kernel.org; dev@dpdk.org;
> mtosatti@redhat.com; thomas@monjalon.net; bluca@debian.org;
> jerinjacobk@gmail.com; bruce.richardson@intel.com; cohuck@redhat.com
> Subject: [dpdk-dev] [PATCH v2 0/7] vfio/pci: SR-IOV support
> 
> Changes since v1 are primarily to patch 3/7 where the commit log is
> rewritten, along with option parsing and failure logging based on upstream
> discussions.  The primary user visible difference is that option parsing is now
> much more strict.  If a vf_token option is provided that cannot be used, we
> generate an error.  As a result of this, opening a PF with a vf_token option
> will serve as a mechanism of setting the vf_token.  This seems like a more
> user friendly API than the alternative of sometimes requiring the option (VFs
> in use) and sometimes rejecting it, and upholds our desire that the option is
> always either used or rejected.
> 
> This also means that the VFIO_DEVICE_FEATURE ioctl is not the only means
> of setting the VF token, which might call into question whether we absolutely
> need this new ioctl.  Currently I'm keeping it because I can imagine use cases,
> for example if a hypervisor were to support SR-IOV, the PF device might be
> opened without consideration for a VF token and we'd require the
> hypservisor to close and re-open the PF in order to set a known VF token,
> which is impractical.
> 
> Series overview (same as provided with v1):
> 
> The synopsis of this series is that we have an ongoing desire to drive PCIe SR-
> IOV PFs from userspace with VFIO.  There's an immediate need for this with
> DPDK drivers and potentially interesting future use cases in virtualization.
> We've been reluctant to add this support previously due to the dependency
> and trust relationship between the VF device and PF driver.  Minimally the PF
> driver can induce a denial of service to the VF, but depending on the specific
> implementation, the PF driver might also be responsible for moving data
> between VFs or have direct access to the state of the VF, including data or
> state otherwise private to the VF or VF driver.
> 
> To help resolve these concerns, we introduce a VF token into the VFIO PCI
> ABI, which acts as a shared secret key between drivers.  The userspace PF
> driver is required to set the VF token to a known value and userspace VF
> drivers are required to provide the token to access the VF device.  If a PF
> driver is restarted with VF drivers in use, it must also provide the current
> token in order to prevent a rogue untrusted PF driver from replacing a known
> driver.  The degree to which this new token is considered secret is left to the
> userspace drivers, the kernel intentionally provides no means to retrieve the
> current token.
> 
> Note that the above token is only required for this new model where both
> the PF and VF devices are usable through vfio-pci.  Existing models of VFIO
> drivers where the PF is used without SR-IOV enabled or the VF is bound to a
> userspace driver with an in-kernel, host PF driver are unaffected.
> 
> The latter configuration above also highlights a new inverted scenario that is
> now possible, a userspace PF driver with in-kernel VF drivers.
> I believe this is a scenario that should be allowed, but should not be enabled
> by default.  This series includes code to set a default driver_override for VFs
> sourced from a vfio-pci user owned PF, such that the VFs are also bound to
> vfio-pci.  This model is compatible with tools like driverctl and allows the
> system administrator to decide if other bindings should be enabled.  The VF
> token interface above exists only between vfio-pci PF and VF drivers, once a
> VF is bound to another driver, the administrator has effectively pronounced
> the device as trusted.  The vfio-pci driver will note alternate binding in dmesg
> for logging and debugging purposes.
> 
> Please review, comment, and test.  The example QEMU implementation
> provided with the RFC is still current for this version.  Thanks,
> 
> Alex

Hi Alex,

Thanks for enabling this feature support.

Tested-by: Vamsi Attunuru <vattunuru@marvell.com>

Tested v2 patch set with below DPDK patch.
http://patches.dpdk.org/patch/66281/

Regards
A Vamsi

> 
> RFC: https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__lore.kernel.org_lkml_158085337582.9445.17682266437583505502.stgit-
> 40gimli.home_&d=DwICaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=2rpxxNF2qeP0
> 2gVZIWTVrW-6zNZz5-uKt9pRqpR_M3U&m=V-6mKmCTHPZa5jwepXU_-
> Ma1_BGF0OWJ_IRCF_p4GVo&s=YnO98PGK9ro7F6_XZTccHdYcZ-
> rMMOin0nRFhPD6Uv4&e=
> v1: https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__lore.kernel.org_lkml_158145472604.16827.15751375540102298130.stgit
> -
> 40gimli.home_&d=DwICaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=2rpxxNF2qeP0
> 2gVZIWTVrW-6zNZz5-uKt9pRqpR_M3U&m=V-6mKmCTHPZa5jwepXU_-
> Ma1_BGF0OWJ_IRCF_p4GVo&s=rvUxLCENwNk0GBYkcsBVVobsLfMb4BV5gtc
> 3VqYQTS4&e=
> 
> ---
> 
> Alex Williamson (7):
>       vfio: Include optional device match in vfio_device_ops callbacks
>       vfio/pci: Implement match ops
>       vfio/pci: Introduce VF token
>       vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user
>       vfio/pci: Add sriov_configure support
>       vfio/pci: Remove dev_fmt definition
>       vfio/pci: Cleanup .probe() exit paths
> 
> 
>  drivers/vfio/pci/vfio_pci.c         |  383
> +++++++++++++++++++++++++++++++++--
>  drivers/vfio/pci/vfio_pci_private.h |   10 +
>  drivers/vfio/vfio.c                 |   20 +-
>  include/linux/vfio.h                |    4
>  include/uapi/linux/vfio.h           |   37 +++
>  5 files changed, 426 insertions(+), 28 deletions(-)


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v3] doc: plan splitting the ethdev ops struct
  2020-02-25 12:44  3% ` [dpdk-dev] [PATCH v2] " Ferruh Yigit
  2020-02-25 15:51  3%   ` Andrew Rybchenko
  2020-02-25 18:13  0%   ` David Marchand
@ 2020-03-04  9:57  4%   ` Ferruh Yigit
  2 siblings, 0 replies; 200+ results
From: Ferruh Yigit @ 2020-03-04  9:57 UTC (permalink / raw)
  To: Neil Horman, John McNamara, Marko Kovacevic
  Cc: dev, Ferruh Yigit, Jerin Jacob Kollanukkaran, David Marchand,
	Thomas Monjalon, Andrew Rybchenko

For the ABI compatibility it is better to hide internal data structures
from the application as much as possible. But because of some inline
functions 'struct eth_dev_ops' can't be hidden completely.

Plan is to split the 'struct eth_dev_ops' into two as ones used by
inline functions and ones not used, and hide the second part that not
used by inline functions completely to the application.

Because of ABI break the work will be done in 20.11

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
Cc: David Marchand <david.marchand@redhat.com>
Cc: Thomas Monjalon <thomas@monjalon.net>
Cc: Andrew Rybchenko <arybchenko@solarflare.com>

v2:
* Add target date for the work
* Give more detail on what will be done

v3:
* Drop the interim implementation, and target 20.11 with ABI break.
---
 doc/guides/rel_notes/deprecation.rst | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 1339f54f5..0bb252f71 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -93,6 +93,15 @@ Deprecation Notices
   In 19.11 PMDs will still update the field even when the offload is not
   enabled.
 
+* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible
+  will be done in 20.11.
+  Currently the ``struct eth_dev_ops`` struct is accessible by the application
+  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
+  access the struct directly.
+  The struct will be separate in two, the ops used by inline functions will be moved
+  next to Rx/Tx burst functions, rest of the ``struct eth_dev_ops`` struct will be
+  moved to header file for drivers to hide it from applications.
+
 * cryptodev: support for using IV with all sizes is added, J0 still can
   be used but only when IV length in following structs ``rte_crypto_auth_xform``,
   ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
-- 
2.24.1


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements
  @ 2020-03-02 13:01  3% ` David Marchand
  2020-03-05  9:06  3%   ` Hemant Agrawal (OSS)
    1 sibling, 1 reply; 200+ results
From: David Marchand @ 2020-03-02 13:01 UTC (permalink / raw)
  To: Hemant Agrawal; +Cc: Yigit, Ferruh, dev

On Mon, Mar 2, 2020 at 10:26 AM Hemant Agrawal <hemant.agrawal@nxp.com> wrote:
>
> This patch series add various patches for enhancing and fixing NXP
> fslmc bus, dpaa bus, and dpaax.
>
> - the main change is support to allow thread migration across lcores
> - improving the multi-process support

This series triggers an ABI warning that must be investigated.
https://travis-ci.com/ovsrobot/dpdk/jobs/292904119#L2233


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
  2020-03-02  7:35  0%     ` Ali Alnubani
@ 2020-03-02  8:13  0%       ` Tonghao Zhang
  0 siblings, 0 replies; 200+ results
From: Tonghao Zhang @ 2020-03-02  8:13 UTC (permalink / raw)
  To: Ali Alnubani; +Cc: stable, Matan Azrad, dev

On Mon, Mar 2, 2020 at 3:35 PM Ali Alnubani <alialnu@mellanox.com> wrote:
>
> > -----Original Message-----
> > From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > Sent: Monday, March 2, 2020 2:23 AM
> > To: Ali Alnubani <alialnu@mellanox.com>
> > Cc: stable@dpdk.org; Matan Azrad <matan@mellanox.com>; dev@dpdk.org
> > Subject: Re: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
> >
> > On Mon, Mar 2, 2020 at 1:09 AM Ali Alnubani <alialnu@mellanox.com>
> > wrote:
> > >
> > > Hi Tonghao,
> > >
> > > > -----Original Message-----
> > > > From: dev <dev-bounces@dpdk.org> On Behalf Of
> > > > xiangxia.m.yue@gmail.com
> > > > Sent: Saturday, February 29, 2020 12:27 PM
> > > > To: Matan Azrad <matan@mellanox.com>; dev@dpdk.org
> > > > Cc: Tonghao Zhang <xiangxia.m.yue@gmail.com>; stable@dpdk.org
> > > > Subject: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
> > > >
> > > > From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > > >
> > > > When setting the CONFIG_RTE_BUILD_SHARED_LIB to y, and build the
> > > > mlx5 pmd, there is a building error.
> > > > To fix it, add RTE_IBVERBS_LINK_DLOPEN to include relative codes.
> > > >
> > > > > mlx5_common.o: In function `mlx5_glue_init':
> > > > > drivers/common/mlx5/mlx5_common.c:324: undefined reference to
> > > > `dlclose'
> > > >
> > > > Fixes: 7b4f1e6bd367 ("common/mlx5: introduce common library")
> > > > Cc: stable@dpdk.org
> > > >
> > > > Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > > > ---
> > > >  drivers/common/mlx5/mlx5_common.c | 5 +++--
> > > >  1 file changed, 3 insertions(+), 2 deletions(-)
> > > >
> > >
> > > I test this case on multiple environments and don't see the build failure.
> > Can you please provide more information about yours, and how to
> > reproduce this?
> > Hi Ali,
> > I use the dpdk-next-net, and the last commit id is
> > d7142fbae16f185e11bfa44be061399afc40a1be.
> > The build config is show as below:
> >
> > diff --git a/config/common_base b/config/common_base index
> > 7ca2f28..4bd5126 100644
> > --- a/config/common_base
> > +++ b/config/common_base
> > @@ -57,7 +57,7 @@ CONFIG_RTE_ENABLE_LTO=n  #  # Compile to share
> > library  # -CONFIG_RTE_BUILD_SHARED_LIB=n
> > +CONFIG_RTE_BUILD_SHARED_LIB=y
> >
> >  #
> >  # Use newest code breaking previous ABI @@ -363,7 +363,7 @@
> > CONFIG_RTE_LIBRTE_MLX4_DEBUG=n  # Compile burst-oriented Mellanox
> > ConnectX-4, ConnectX-5,  # ConnectX-6 & BlueField (MLX5) PMD  # -
> > CONFIG_RTE_LIBRTE_MLX5_PMD=n
> > +CONFIG_RTE_LIBRTE_MLX5_PMD=y
> >  CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
> >
> >  #
> >
> > The building failure log show:
> > LD librte_common_mlx5.so.20.0.1
> > mlx5_common.o: In function `mlx5_glue_init':
> > /root/zth/myshell/dpdk-next-
> > net/drivers/common/mlx5/mlx5_common.c:324:
> > undefined reference to `dlclose'
> > collect2: error: ld returned 1 exit status
> >
>
> Do you mind sharing which OS are you using, which gcc/clang version, whether you have MLNX_OFED or rdma-core installed, and which version?
1. CentOS Linux release 7.6.1810 (Core)
2. kernel 3.10.0-957.1.3.el7.x86_64
3. OFED 4.7-3.2.9
4. FW 16.26.4012
5. gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
6. build the dpdk with x86_64-native-linuxapp-gcc
> Thanks,
> Ali

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
  2020-03-02  0:22  3%   ` Tonghao Zhang
@ 2020-03-02  7:35  0%     ` Ali Alnubani
  2020-03-02  8:13  0%       ` Tonghao Zhang
  0 siblings, 1 reply; 200+ results
From: Ali Alnubani @ 2020-03-02  7:35 UTC (permalink / raw)
  To: Tonghao Zhang; +Cc: stable, Matan Azrad, dev

> -----Original Message-----
> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> Sent: Monday, March 2, 2020 2:23 AM
> To: Ali Alnubani <alialnu@mellanox.com>
> Cc: stable@dpdk.org; Matan Azrad <matan@mellanox.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
> 
> On Mon, Mar 2, 2020 at 1:09 AM Ali Alnubani <alialnu@mellanox.com>
> wrote:
> >
> > Hi Tonghao,
> >
> > > -----Original Message-----
> > > From: dev <dev-bounces@dpdk.org> On Behalf Of
> > > xiangxia.m.yue@gmail.com
> > > Sent: Saturday, February 29, 2020 12:27 PM
> > > To: Matan Azrad <matan@mellanox.com>; dev@dpdk.org
> > > Cc: Tonghao Zhang <xiangxia.m.yue@gmail.com>; stable@dpdk.org
> > > Subject: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
> > >
> > > From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > >
> > > When setting the CONFIG_RTE_BUILD_SHARED_LIB to y, and build the
> > > mlx5 pmd, there is a building error.
> > > To fix it, add RTE_IBVERBS_LINK_DLOPEN to include relative codes.
> > >
> > > > mlx5_common.o: In function `mlx5_glue_init':
> > > > drivers/common/mlx5/mlx5_common.c:324: undefined reference to
> > > `dlclose'
> > >
> > > Fixes: 7b4f1e6bd367 ("common/mlx5: introduce common library")
> > > Cc: stable@dpdk.org
> > >
> > > Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > > ---
> > >  drivers/common/mlx5/mlx5_common.c | 5 +++--
> > >  1 file changed, 3 insertions(+), 2 deletions(-)
> > >
> >
> > I test this case on multiple environments and don't see the build failure.
> Can you please provide more information about yours, and how to
> reproduce this?
> Hi Ali,
> I use the dpdk-next-net, and the last commit id is
> d7142fbae16f185e11bfa44be061399afc40a1be.
> The build config is show as below:
> 
> diff --git a/config/common_base b/config/common_base index
> 7ca2f28..4bd5126 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -57,7 +57,7 @@ CONFIG_RTE_ENABLE_LTO=n  #  # Compile to share
> library  # -CONFIG_RTE_BUILD_SHARED_LIB=n
> +CONFIG_RTE_BUILD_SHARED_LIB=y
> 
>  #
>  # Use newest code breaking previous ABI @@ -363,7 +363,7 @@
> CONFIG_RTE_LIBRTE_MLX4_DEBUG=n  # Compile burst-oriented Mellanox
> ConnectX-4, ConnectX-5,  # ConnectX-6 & BlueField (MLX5) PMD  # -
> CONFIG_RTE_LIBRTE_MLX5_PMD=n
> +CONFIG_RTE_LIBRTE_MLX5_PMD=y
>  CONFIG_RTE_LIBRTE_MLX5_DEBUG=n
> 
>  #
> 
> The building failure log show:
> LD librte_common_mlx5.so.20.0.1
> mlx5_common.o: In function `mlx5_glue_init':
> /root/zth/myshell/dpdk-next-
> net/drivers/common/mlx5/mlx5_common.c:324:
> undefined reference to `dlclose'
> collect2: error: ld returned 1 exit status
> 

Do you mind sharing which OS are you using, which gcc/clang version, whether you have MLNX_OFED or rdma-core installed, and which version?

Thanks,
Ali

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
  @ 2020-03-02  0:22  3%   ` Tonghao Zhang
  2020-03-02  7:35  0%     ` Ali Alnubani
  0 siblings, 1 reply; 200+ results
From: Tonghao Zhang @ 2020-03-02  0:22 UTC (permalink / raw)
  To: Ali Alnubani; +Cc: stable, Matan Azrad, dev

On Mon, Mar 2, 2020 at 1:09 AM Ali Alnubani <alialnu@mellanox.com> wrote:
>
> Hi Tonghao,
>
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of
> > xiangxia.m.yue@gmail.com
> > Sent: Saturday, February 29, 2020 12:27 PM
> > To: Matan Azrad <matan@mellanox.com>; dev@dpdk.org
> > Cc: Tonghao Zhang <xiangxia.m.yue@gmail.com>; stable@dpdk.org
> > Subject: [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error
> >
> > From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> >
> > When setting the CONFIG_RTE_BUILD_SHARED_LIB to y, and build the mlx5
> > pmd, there is a building error.
> > To fix it, add RTE_IBVERBS_LINK_DLOPEN to include relative codes.
> >
> > > mlx5_common.o: In function `mlx5_glue_init':
> > > drivers/common/mlx5/mlx5_common.c:324: undefined reference to
> > `dlclose'
> >
> > Fixes: 7b4f1e6bd367 ("common/mlx5: introduce common library")
> > Cc: stable@dpdk.org
> >
> > Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > ---
> >  drivers/common/mlx5/mlx5_common.c | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> >
>
> I test this case on multiple environments and don't see the build failure. Can you please provide more information about yours, and how to reproduce this?
Hi Ali,
I use the dpdk-next-net, and the last commit id is
d7142fbae16f185e11bfa44be061399afc40a1be.
The build config is show as below:

diff --git a/config/common_base b/config/common_base
index 7ca2f28..4bd5126 100644
--- a/config/common_base
+++ b/config/common_base
@@ -57,7 +57,7 @@ CONFIG_RTE_ENABLE_LTO=n
 #
 # Compile to share library
 #
-CONFIG_RTE_BUILD_SHARED_LIB=n
+CONFIG_RTE_BUILD_SHARED_LIB=y

 #
 # Use newest code breaking previous ABI
@@ -363,7 +363,7 @@ CONFIG_RTE_LIBRTE_MLX4_DEBUG=n
 # Compile burst-oriented Mellanox ConnectX-4, ConnectX-5,
 # ConnectX-6 & BlueField (MLX5) PMD
 #
-CONFIG_RTE_LIBRTE_MLX5_PMD=n
+CONFIG_RTE_LIBRTE_MLX5_PMD=y
 CONFIG_RTE_LIBRTE_MLX5_DEBUG=n

 #

The building failure log show:
LD librte_common_mlx5.so.20.0.1
mlx5_common.o: In function `mlx5_glue_init':
/root/zth/myshell/dpdk-next-net/drivers/common/mlx5/mlx5_common.c:324:
undefined reference to `dlclose'
collect2: error: ld returned 1 exit status

> Thanks,
> Ali

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-27 10:31  0%         ` Jerin Jacob
@ 2020-02-28  0:17  0%           ` David Christensen
  0 siblings, 0 replies; 200+ results
From: David Christensen @ 2020-02-28  0:17 UTC (permalink / raw)
  To: Jerin Jacob, Ananyev, Konstantin
  Cc: Stephen Hemminger, dpdk-dev, Olivier Matz

> On Tue, Feb 25, 2020 at 7:11 PM Ananyev, Konstantin
> <konstantin.ananyev@intel.com> wrote:
> 
>> We do have a run-time check in our current enqueue()/dequeue implementation.
>> In fact we support both modes: we have generic rte_ring_enqueue(/dequeue)_bulk(/burst)
>> where sync behaviour is determined at runtime by value of prod(/cons).single.
>> Or user can call  rte_ring_(mp/sp)_enqueue_* functions directly.
>> This RFC follows exactly the same paradigm:
>> rte_ring_enqueue(/dequeue)_bulk(/burst) kept generic and it's
>> behaviour is determined at runtime, by value of prod(/cons).sync_type.
>> Or user can call enqueue/dequeue with particular sync mode directly:
>> rte_ring_(mp/sp/rts/hts)_enqueue_(bulk/burst)*.
>> The only thing that changed:
>>   Format of prod/cons now could differ depending on mode selected at _init_.
>>   So you can't create a ring for let say SP mode and then in the middle of data-path
>>   change your mind and start using MP_RTS mode.
>>   For existing modes (SP/MP, SC/MC)  format remains the same and user can still
>>   use them interchangeably, though of course that is an error prone practice.
> 
> Makes sense.
> 
> 
>>
>>>> But I agree with the problem statement that in the virtualization use
>>>> case, It may be possible to have N virtual cores runs on a physical
>>>> core.
>>>>
>>>> IMO, The best solution would be keeping the ring API same and have a
>>>> different flavor in "compile-time". Something like
>>>> liburcu did for accommodating different flavors.
>>>>
>>>> i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The
>>>> application can simply include ONE header file in a C file based on
>>>> the flavor.
>>
>> I don't think it is a flexible enough approach.
>> In one app user might need to have several rings with different sync modes.
>> Or even user might need a ring with different sync modes for enqueue/dequeue.
> 
> Ack.
> 
> 
>> Yes, hiding rte_ring implementation inside .c would help a lot
>> in terms of ABI maintenance and would make our future life easier.
>> The question is what is the price for it in terms of performance,
>> and are we ready to pay it. Not to mention that it would cause
>> changes in many other libs/apps...
>> So I think it should be a subject for a separate discussion.
>> But, agree it would be good at least to measure the performance
>> impact of such change.
>> If I'll have some spare cycles, will give it a try.
>> Meanwhile, can I ask Jerin and other guys to repeat tests from this RFC
>> on their HW? Before continuing discussion would probably be good to know
>> does the suggested patch work as expected across different platforms.
> 
> 
> I tested on an arm64 HW. The former section is without the
> patch(20.02) and later one with this patch.
> I agree with Konstantin that getting more platform tests will be good
> early so that we can focus on the approach
> to avoid back and forth latter.
> 
> 
> RTE>>ring_perf_autotest // without path
> 
> ### Testing single element enq/deq ###
> legacy APIs: SP/SC: single: 289.78
> legacy APIs: MP/MC: single: 516.20
> 
> ### Testing burst enq/deq ###
> legacy APIs: SP/SC: burst (size: 8): 312.88
> legacy APIs: SP/SC: burst (size: 32): 426.72
> legacy APIs: MP/MC: burst (size: 8): 510.95
> legacy APIs: MP/MC: burst (size: 32): 702.01
> 
> ### Testing bulk enq/deq ###
> legacy APIs: SP/SC: bulk (size: 8): 306.74
> legacy APIs: SP/SC: bulk (size: 32): 411.56
> legacy APIs: MP/MC: bulk (size: 8): 501.32
> legacy APIs: MP/MC: bulk (size: 32): 693.07
> 
> ### Testing empty bulk deq ###
> legacy APIs: SP/SC: bulk (size: 8): 7.00
> legacy APIs: MP/MC: bulk (size: 8): 7.00
> 
> ### Testing using two physical cores ###
> legacy APIs: SP/SC: bulk (size: 8): 74.36
> legacy APIs: MP/MC: bulk (size: 8): 110.18
> legacy APIs: SP/SC: bulk (size: 32): 23.04
> legacy APIs: MP/MC: bulk (size: 32): 32.29
> 
> ### Testing using all slave nodes ##
> Bulk enq/dequeue count on size 8
> Core [8] count = 293741
> Core [9] count = 293741
> Total count (size: 8): 587482
> 
> Bulk enq/dequeue count on size 32
> Core [8] count = 244909
> Core [9] count = 244909
> Total count (size: 32): 1077300
> 
> ### Testing single element enq/deq ###
> elem APIs: element size 16B: SP/SC: single: 255.37
> elem APIs: element size 16B: MP/MC: single: 456.68
> 
> ### Testing burst enq/deq ###
> elem APIs: element size 16B: SP/SC: burst (size: 8): 291.99
> elem APIs: element size 16B: SP/SC: burst (size: 32): 456.25
> elem APIs: element size 16B: MP/MC: burst (size: 8): 497.77
> elem APIs: element size 16B: MP/MC: burst (size: 32): 680.87
> 
> ### Testing bulk enq/deq ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 284.40
> elem APIs: element size 16B: SP/SC: bulk (size: 32): 453.17
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 485.77
> elem APIs: element size 16B: MP/MC: bulk (size: 32): 675.08
> 
> ### Testing empty bulk deq ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 8.00
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 7.00
> 
> ### Testing using two physical cores ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 74.45
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 105.91
> elem APIs: element size 16B: SP/SC: bulk (size: 32): 22.92
> elem APIs: element size 16B: MP/MC: bulk (size: 32): 31.55
> 
> ### Testing using all slave nodes ###
> 
> Bulk enq/dequeue count on size 8
> Core [8] count = 308724
> Core [9] count = 308723
> Total count (size: 8): 617447
> 
> Bulk enq/dequeue count on size 32
> Core [8] count = 214269
> Core [9] count = 214269
> Total count (size: 32): 1045985
> 
> RTE>>ring_perf_autotest // with patch
> 
> ### Testing single element enq/deq ###
> legacy APIs: SP/SC: single: 289.78
> legacy APIs: MP/MC: single: 475.76
> 
> ### Testing burst enq/deq ###
> legacy APIs: SP/SC: burst (size: 8): 323.91
> legacy APIs: SP/SC: burst (size: 32): 424.60
> legacy APIs: MP/MC: burst (size: 8): 523.00
> legacy APIs: MP/MC: burst (size: 32): 717.09
> 
> ### Testing bulk enq/deq ###
> legacy APIs: SP/SC: bulk (size: 8): 317.74
> legacy APIs: SP/SC: bulk (size: 32): 413.57
> legacy APIs: MP/MC: bulk (size: 8): 512.89
> legacy APIs: MP/MC: bulk (size: 32): 712.45
> 
> ### Testing empty bulk deq ###
> legacy APIs: SP/SC: bulk (size: 8): 7.00
> legacy APIs: MP/MC: bulk (size: 8): 7.00
> 
> ### Testing using two physical cores ###
> legacy APIs: SP/SC: bulk (size: 8): 74.82
> legacy APIs: MP/MC: bulk (size: 8): 96.45
> legacy APIs: SP/SC: bulk (size: 32): 22.97
> legacy APIs: MP/MC: bulk (size: 32): 32.52
> 
> ### Testing using all slave nodes ###
> 
> Bulk enq/dequeue count on size 8
> Core [8] count = 283928
> Core [9] count = 283927
> Total count (size: 8): 567855
> 
> Bulk enq/dequeue count on size 32
> Core [8] count = 223916
> Core [9] count = 223915
> Total count (size: 32): 1015686
> 
> ### Testing single element enq/deq ###
> elem APIs: element size 16B: SP/SC: single: 267.65
> elem APIs: element size 16B: MP/MC: single: 439.06
> 
> ### Testing burst enq/deq ###
> elem APIs: element size 16B: SP/SC: burst (size: 8): 302.44
> elem APIs: element size 16B: SP/SC: burst (size: 32): 466.31
> elem APIs: element size 16B: MP/MC: burst (size: 8): 502.51
> elem APIs: element size 16B: MP/MC: burst (size: 32): 695.81
> 
> ### Testing bulk enq/deq ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 295.15
> elem APIs: element size 16B: SP/SC: bulk (size: 32): 462.77
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 496.89
> elem APIs: element size 16B: MP/MC: bulk (size: 32): 690.46
> 
> ### Testing empty bulk deq ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 7.50
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 7.44
> 
> ### Testing using two physical cores ###
> elem APIs: element size 16B: SP/SC: bulk (size: 8): 65.85
> elem APIs: element size 16B: MP/MC: bulk (size: 8): 103.80
> elem APIs: element size 16B: SP/SC: bulk (size: 32): 23.27
> elem APIs: element size 16B: MP/MC: bulk (size: 32): 31.17
> 
> ### Testing using all slave nodes ###
> 
> Bulk enq/dequeue count on size 8
> Core [8] count = 304223
> Core [9] count = 304221
> Total count (size: 8): 608444
> 
> Bulk enq/dequeue count on size 32
> Core [8] count = 214856
> Core [9] count = 214855
> Total count (size: 32): 1038155
> Test OK
> RTE>>quit
> 
> 

Encountered a couple of different build errors with these patches on my 
Power 9 system:

In file included from ../lib/librte_ring/rte_ring.h:534,
                  from ../drivers/mempool/ring/rte_mempool_ring.c:9:
../lib/librte_ring/rte_ring_hts_generic.h: In function 
‘__rte_ring_hts_update_tail’:
../lib/librte_ring/rte_ring_hts_generic.h:61:2: warning: implicit 
declaration of function ‘RTE_ASSERT’; did you mean ‘RTE_STR’? 
[-Wimplicit-function-declaration]
   RTE_ASSERT(n >= num);
   ^~~~~~~~~~
   RTE_STR

Fixed by adding "#include <rte_debug.h>" to rte_ring.h.

Also encountered:

In file included from ../app/test/test_ring_hts_stress.c:5:
../app/test/test_ring_stress.h: In function ‘check_updt_elem’:
../app/test/test_ring_stress.h:162:9: error: unknown type name 
‘rte_spinlock_t’
   static rte_spinlock_t dump_lock;
          ^~~~~~~~~~~~~~
../app/test/test_ring_stress.h:166:4: warning: implicit declaration of 
function ‘rte_spinlock_lock’; did you mean ‘rte_calloc_socket’? 
[-Wimplicit-function-declaration]
     rte_spinlock_lock(&dump_lock);
     ^~~~~~~~~~~~~~~~~
     rte_calloc_socket
../app/test/test_ring_stress.h:166:4: warning: nested extern declaration 
of ‘rte_spinlock_lock’ [-Wnested-externs]
../app/test/test_ring_stress.h:172:4: warning: implicit declaration of 
function ‘rte_spinlock_unlock’; did you mean ‘pthread_rwlock_unlock’? 
[-Wimplicit-function-declaration]
     rte_spinlock_unlock(&dump_lock);
     ^~~~~~~~~~~~~~~~~~~
     pthread_rwlock_unlock
../app/test/test_ring_stress.h:172:4: warning: nested extern declaration 
of ‘rte_spinlock_unlock’ [-Wnested-externs]

Fixed by adding "#include <rte_spinlock.h>" to test_ring_stress.h.

Autoperf test results
---------------------
RTE>>ring_perf_autotest // DPDK 20.02, without patch

### Testing single element enq/deq ###
legacy APIs: SP/SC: single: 42.14
legacy APIs: MP/MC: single: 56.26

### Testing burst enq/deq ###
legacy APIs: SP/SC: burst (size: 8): 43.59
legacy APIs: SP/SC: burst (size: 32): 49.87
legacy APIs: MP/MC: burst (size: 8): 58.43
legacy APIs: MP/MC: burst (size: 32): 65.68

### Testing bulk enq/deq ###
legacy APIs: SP/SC: bulk (size: 8): 43.59
legacy APIs: SP/SC: bulk (size: 32): 49.85
legacy APIs: MP/MC: bulk (size: 8): 58.43
legacy APIs: MP/MC: bulk (size: 32): 65.60

### Testing empty bulk deq ###
legacy APIs: SP/SC: bulk (size: 8): 7.16
legacy APIs: MP/MC: bulk (size: 8): 7.16

### Testing using two hyperthreads ###
legacy APIs: SP/SC: bulk (size: 8): 12.46
legacy APIs: MP/MC: bulk (size: 8): 16.20
legacy APIs: SP/SC: bulk (size: 32): 3.21
legacy APIs: MP/MC: bulk (size: 32): 3.73

### Testing using two physical cores ###
legacy APIs: SP/SC: bulk (size: 8): 33.34
legacy APIs: MP/MC: bulk (size: 8): 37.99
legacy APIs: SP/SC: bulk (size: 32): 10.19
legacy APIs: MP/MC: bulk (size: 32): 11.90

### Testing using two NUMA nodes ###
legacy APIs: SP/SC: bulk (size: 8): 49.50
legacy APIs: MP/MC: bulk (size: 8): 63.65
legacy APIs: SP/SC: bulk (size: 32): 12.49
legacy APIs: MP/MC: bulk (size: 32): 23.53

### Testing using all slave nodes ###

Bulk enq/dequeue count on size 8
Core [4] count = 5604
Core [5] count = 5563
Core [6] count = 5576
Core [7] count = 5630
Core [8] count = 5643
Core [9] count = 5727
Core [10] count = 5698
Core [11] count = 5711
Core [64] count = 5259
Core [65] count = 5322
Core [66] count = 5321
Core [67] count = 5310
Core [68] count = 4350
Core [69] count = 4455
Core [70] count = 4546
Core [71] count = 4475
Total count (size: 8): 84190

Bulk enq/dequeue count on size 32
Core [4] count = 5543
Core [5] count = 5555
Core [6] count = 5596
Core [7] count = 5584
Core [8] count = 5613
Core [9] count = 5686
Core [10] count = 5689
Core [11] count = 5677
Core [64] count = 5228
Core [65] count = 5389
Core [66] count = 5406
Core [67] count = 5359
Core [68] count = 4554
Core [69] count = 4673
Core [70] count = 4675
Core [71] count = 4644
Total count (size: 32): 169061

### Testing single element enq/deq ###
elem APIs: element size 16B: SP/SC: single: 42.84
elem APIs: element size 16B: MP/MC: single: 56.77

### Testing burst enq/deq ###
elem APIs: element size 16B: SP/SC: burst (size: 8): 44.98
elem APIs: element size 16B: SP/SC: burst (size: 32): 59.16
elem APIs: element size 16B: MP/MC: burst (size: 8): 60.58
elem APIs: element size 16B: MP/MC: burst (size: 32): 74.75

### Testing bulk enq/deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 45.01
elem APIs: element size 16B: SP/SC: bulk (size: 32): 59.08
elem APIs: element size 16B: MP/MC: bulk (size: 8): 60.58
elem APIs: element size 16B: MP/MC: bulk (size: 32): 74.76

### Testing empty bulk deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 7.16
elem APIs: element size 16B: MP/MC: bulk (size: 8): 7.16

### Testing using two hyperthreads ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 12.18
elem APIs: element size 16B: MP/MC: bulk (size: 8): 15.44
elem APIs: element size 16B: SP/SC: bulk (size: 32): 3.22
elem APIs: element size 16B: MP/MC: bulk (size: 32): 3.97

### Testing using two physical cores ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 42.07
elem APIs: element size 16B: MP/MC: bulk (size: 8): 44.50
elem APIs: element size 16B: SP/SC: bulk (size: 32): 10.73
elem APIs: element size 16B: MP/MC: bulk (size: 32): 11.73

### Testing using two NUMA nodes ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 49.55
elem APIs: element size 16B: MP/MC: bulk (size: 8): 93.10
elem APIs: element size 16B: SP/SC: bulk (size: 32): 12.33
elem APIs: element size 16B: MP/MC: bulk (size: 32): 27.10

### Testing using all slave nodes ###

Bulk enq/dequeue count on size 8
Core [4] count = 5489
Core [5] count = 5559
Core [6] count = 5566
Core [7] count = 5577
Core [8] count = 5645
Core [9] count = 5699
Core [10] count = 5695
Core [11] count = 5733
Core [64] count = 5202
Core [65] count = 5284
Core [66] count = 5319
Core [67] count = 5349
Core [68] count = 4331
Core [69] count = 4465
Core [70] count = 4484
Core [71] count = 4439
Total count (size: 8): 83836

Bulk enq/dequeue count on size 32
Core [4] count = 5567
Core [5] count = 5492
Core [6] count = 5517
Core [7] count = 5515
Core [8] count = 5593
Core [9] count = 5650
Core [10] count = 5694
Core [11] count = 5665
Core [64] count = 5236
Core [65] count = 5319
Core [66] count = 5333
Core [67] count = 5304
Core [68] count = 4608
Core [69] count = 4669
Core [70] count = 4690
Core [71] count = 4654
Total count (size: 32): 168342
Test OK
---------------------
RTE>>ring_perf_autotest // DPDK 20.02, without patch

### Testing single element enq/deq ###
legacy APIs: SP/SC: single: 42.18
legacy APIs: MP/MC: single: 56.26

### Testing burst enq/deq ###
legacy APIs: SP/SC: burst (size: 8): 43.60
legacy APIs: SP/SC: burst (size: 32): 49.86
legacy APIs: MP/MC: burst (size: 8): 58.43
legacy APIs: MP/MC: burst (size: 32): 65.67

### Testing bulk enq/deq ###
legacy APIs: SP/SC: bulk (size: 8): 43.59
legacy APIs: SP/SC: bulk (size: 32): 49.86
legacy APIs: MP/MC: bulk (size: 8): 58.43
legacy APIs: MP/MC: bulk (size: 32): 65.63

### Testing empty bulk deq ###
legacy APIs: SP/SC: bulk (size: 8): 7.16
legacy APIs: MP/MC: bulk (size: 8): 7.16

### Testing using two hyperthreads ###
legacy APIs: SP/SC: bulk (size: 8): 12.07
legacy APIs: MP/MC: bulk (size: 8): 16.24
legacy APIs: SP/SC: bulk (size: 32): 3.20
legacy APIs: MP/MC: bulk (size: 32): 3.72

### Testing using two physical cores ###
legacy APIs: SP/SC: bulk (size: 8): 33.41
legacy APIs: MP/MC: bulk (size: 8): 38.01
legacy APIs: SP/SC: bulk (size: 32): 10.23
legacy APIs: MP/MC: bulk (size: 32): 11.90

### Testing using two NUMA nodes ###
legacy APIs: SP/SC: bulk (size: 8): 49.27
legacy APIs: MP/MC: bulk (size: 8): 64.80
legacy APIs: SP/SC: bulk (size: 32): 12.45
legacy APIs: MP/MC: bulk (size: 32): 23.11

### Testing using all slave nodes ###

Bulk enq/dequeue count on size 8
Core [4] count = 5637
Core [5] count = 5599
Core [6] count = 5623
Core [7] count = 5627
Core [8] count = 5723
Core [9] count = 5758
Core [10] count = 5714
Core [11] count = 5724
Core [64] count = 5310
Core [65] count = 5438
Core [66] count = 5448
Core [67] count = 5374
Core [68] count = 4441
Core [69] count = 4550
Core [70] count = 4550
Core [71] count = 4558
Total count (size: 8): 85074

Bulk enq/dequeue count on size 32
Core [4] count = 5608
Core [5] count = 5623
Core [6] count = 5590
Core [7] count = 5658
Core [8] count = 5680
Core [9] count = 5738
Core [10] count = 5692
Core [11] count = 5712
Core [64] count = 5273
Core [65] count = 5363
Core [66] count = 5341
Core [67] count = 5349
Core [68] count = 4591
Core [69] count = 4673
Core [70] count = 4698
Core [71] count = 4687
Total count (size: 32): 170350

### Testing single element enq/deq ###
elem APIs: element size 16B: SP/SC: single: 42.82
elem APIs: element size 16B: MP/MC: single: 56.79

### Testing burst enq/deq ###
elem APIs: element size 16B: SP/SC: burst (size: 8): 44.99
elem APIs: element size 16B: SP/SC: burst (size: 32): 59.00
elem APIs: element size 16B: MP/MC: burst (size: 8): 60.59
elem APIs: element size 16B: MP/MC: burst (size: 32): 74.78

### Testing bulk enq/deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 44.97
elem APIs: element size 16B: SP/SC: bulk (size: 32): 58.91
elem APIs: element size 16B: MP/MC: bulk (size: 8): 60.60
elem APIs: element size 16B: MP/MC: bulk (size: 32): 74.61

### Testing empty bulk deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 7.16
elem APIs: element size 16B: MP/MC: bulk (size: 8): 7.16

### Testing using two hyperthreads ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 12.18
elem APIs: element size 16B: MP/MC: bulk (size: 8): 15.41
elem APIs: element size 16B: SP/SC: bulk (size: 32): 3.19
elem APIs: element size 16B: MP/MC: bulk (size: 32): 4.06

### Testing using two physical cores ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 42.08
elem APIs: element size 16B: MP/MC: bulk (size: 8): 44.52
elem APIs: element size 16B: SP/SC: bulk (size: 32): 10.73
elem APIs: element size 16B: MP/MC: bulk (size: 32): 12.39

### Testing using two NUMA nodes ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 49.65
elem APIs: element size 16B: MP/MC: bulk (size: 8): 93.27
elem APIs: element size 16B: SP/SC: bulk (size: 32): 12.38
elem APIs: element size 16B: MP/MC: bulk (size: 32): 27.19

### Testing using all slave nodes ###

Bulk enq/dequeue count on size 8
Core [4] count = 5629
Core [5] count = 5585
Core [6] count = 5676
Core [7] count = 5604
Core [8] count = 5639
Core [9] count = 5731
Core [10] count = 5694
Core [11] count = 5707
Core [64] count = 5254
Core [65] count = 5331
Core [66] count = 5340
Core [67] count = 5355
Core [68] count = 4339
Core [69] count = 4481
Core [70] count = 4504
Core [71] count = 4507
Total count (size: 8): 84376

Bulk enq/dequeue count on size 32
Core [4] count = 5518
Core [5] count = 5493
Core [6] count = 5559
Core [7] count = 5484
Core [8] count = 5623
Core [9] count = 5669
Core [10] count = 5661
Core [11] count = 5658
Core [64] count = 5207
Core [65] count = 5305
Core [66] count = 5273
Core [67] count = 5303
Core [68] count = 4542
Core [69] count = 4682
Core [70] count = 4672
Core [71] count = 4609
Total count (size: 32): 168634
Test OK


Dave

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] Questions about rte_timer APIs
  2020-02-26 16:57  0%   ` Carrillo, Erik G
@ 2020-02-27 16:58  0%     ` Honnappa Nagarahalli
  0 siblings, 0 replies; 200+ results
From: Honnappa Nagarahalli @ 2020-02-27 16:58 UTC (permalink / raw)
  To: Carrillo, Erik G, Robert Sanford
  Cc: dev, nd, Phil Yang, Gavin Hu, david.marchand, thomas, nd, nd

Thanks Erik. We will create some patches and send them for review.

> -----Original Message-----
> From: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Sent: Wednesday, February 26, 2020 10:58 AM
> To: Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>; Robert
> Sanford <rsanford@akamai.com>
> Cc: dev <dev@dpdk.org>; nd <nd@arm.com>; Phil Yang
> <Phil.Yang@arm.com>; Gavin Hu <Gavin.Hu@arm.com>;
> david.marchand@redhat.com; thomas@monjalon.net; nd <nd@arm.com>
> Subject: RE: Questions about rte_timer APIs
> 
> Hi Honnappa,
> 
> Your description below looks correct to me.  For the current implementation, I
> referenced a couple of existing DPDK libraries, but primarily the rte_service
> library.  However, I agree that allocating the timer data structs only as needed
> would be a good idea.
> 
> You are also correct that, since the rte_timer_alt_* APIs are still experimental,
> they can change without constraint;  this would allow for the APIs to change
> as needed to support the above design.  It looks like the only users of those
> APIs in DPDK currently are the event timer adapter and unit test code.
> 
> Thanks,
> Erik
> 
> > -----Original Message-----
> > From: Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>
> > Sent: Tuesday, February 25, 2020 5:56 PM
> > To: Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>; Robert
> > Sanford <rsanford@akamai.com>; Carrillo, Erik G
> > <erik.g.carrillo@intel.com>
> > Cc: dev <dev@dpdk.org>; nd <nd@arm.com>; Phil Yang
> > <Phil.Yang@arm.com>; Gavin Hu <Gavin.Hu@arm.com>;
> > david.marchand@redhat.com; thomas@monjalon.net; nd <nd@arm.com>
> > Subject: RE: Questions about rte_timer APIs
> >
> > Hi Erik,
> > 	I see that the rte_timer_alt_xxx APIs are still marked as
> > experimental. So, we should be able to change them without any ABI
> > constraints. Please let me know what you think.
> >
> > Thank you,
> > Honnappa
> >
> > > -----Original Message-----
> > > From: dev <dev-bounces@dpdk.org> On Behalf Of Honnappa Nagarahalli
> > > Sent: Thursday, February 13, 2020 11:55 PM
> > > To: Robert Sanford <rsanford@akamai.com>; Erik Gabriel Carrillo
> > > <erik.g.carrillo@intel.com>
> > > Cc: dev <dev@dpdk.org>; nd <nd@arm.com>; Phil Yang
> > > <Phil.Yang@arm.com>; Gavin Hu <Gavin.Hu@arm.com>; nd
> > <nd@arm.com>
> > > Subject: [dpdk-dev] Questions about rte_timer APIs
> > >
> > > Hi Erik/Robert,
> > > 	I was looking at the rte_timer library code and have questions
> > > around the way instances of timer list are allocated.
> > >
> > > The API 'rte_timer_subsystem_init' allocates RTE_MAX_DATA_ELS (64)
> > > number of timer data structs. Each timer data struct acts as an
> > > independent instance of timer list. The user allocates an instance
> > > by calling 'rte_timer_data_alloc' which provides an index in the
> > > instance array.to s Essentially, the library is allocating the
> > > memory upfront even though there might not be a need to have 64
> > > instances. Please correct me if I am
> > wrong.
> > >
> > > Usually, creating multiple instances is handled by allocating
> > > required memory, as and when required, by an 'init' API. This API
> > > also returns a pointer to that instance which is passed to other
> > > APIs in the library. For ex: rte_hash library follows this approach.
> > > IMO, this is an
> > elegant way to handle multiple instances.
> > > This approach does not waste memory and does not put any restriction
> > > on number of instances.
> > >
> > > I wanted to understand the reasoning behind the current design to
> > > handle multiple instances. Appreciate your inputs.
> > >
> > > Thank you,
> > > Honnappa


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] version: 20.05-rc0
  2020-02-27 11:01  0%   ` David Marchand
@ 2020-02-27 11:31  0%     ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-02-27 11:31 UTC (permalink / raw)
  Cc: dev, Thomas Monjalon

On Thu, Feb 27, 2020 at 12:01 PM David Marchand
<david.marchand@redhat.com> wrote:
>
> On Wed, Feb 26, 2020 at 2:55 PM Thomas Monjalon <thomas@monjalon.net> wrote:
> >
> > 26/02/2020 14:38, David Marchand:
> > > Start a new release cycle with empty release notes.
> > > ABI must now be checked with v20.02 as a reference.
> > >
> > > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > > ---
> > >  .travis.yml                            |   4 +
> > >  ABI_VERSION                            |   2 +-
> > >  VERSION                                |   2 +-
> > >  doc/guides/rel_notes/index.rst         |   1 +
> > >  doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
> > >  5 files changed, 146 insertions(+), 2 deletions(-)
> > >  create mode 100644 doc/guides/rel_notes/release_20_05.rst
> >
> > Acked-by: Thomas Monjalon <thomas@monjalon.net>
>
> Applied, here we go.

Patchwork has just been cleaned: old patches archived, Deferred
patches back to state NEW.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] version: 20.05-rc0
  2020-02-27 11:23  3%       ` David Marchand
@ 2020-02-27 11:26  4%         ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-02-27 11:26 UTC (permalink / raw)
  To: Bruce Richardson, David Marchand; +Cc: dev

27/02/2020 12:23, David Marchand:
> On Thu, Feb 27, 2020 at 12:17 PM Bruce Richardson
> <bruce.richardson@intel.com> wrote:
> >
> > On Wed, Feb 26, 2020 at 03:01:04PM +0100, David Marchand wrote:
> > > On Wed, Feb 26, 2020 at 2:55 PM Thomas Monjalon <thomas@monjalon.net> wrote:
> > > >
> > > > 26/02/2020 14:38, David Marchand:
> > > > > Start a new release cycle with empty release notes.
> > > > > ABI must now be checked with v20.02 as a reference.
> > > > >
> > > > > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > > > > ---
> > > > >  .travis.yml                            |   4 +
> > > > >  ABI_VERSION                            |   2 +-
> > > > >  VERSION                                |   2 +-
> > > > >  doc/guides/rel_notes/index.rst         |   1 +
> > > > >  doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
> > > > >  5 files changed, 146 insertions(+), 2 deletions(-)
> > > > >  create mode 100644 doc/guides/rel_notes/release_20_05.rst
> > > >
> > > > Acked-by: Thomas Monjalon <thomas@monjalon.net>
> > > >
> > > >
> > > > > --- a/.travis.yml
> > > > > +++ b/.travis.yml
> > > > > +env:
> > > > > +  global:
> > > > > +    - REF_GIT_TAG=v20.02
> > > >
> > > > One question: why REF_GIT_TAG was not needed in Travis during 20.02?
> > >
> > > The .ci/linux-build.sh script has a default value for parameters.
> > > http://git.dpdk.org/dpdk/tree/.ci/linux-build.sh#n71&h=v20.02
> > >
> > > This could be removed, so that we only have explicit values in the
> > > .travis.yml configuration.
> > > No strong opinion keeping them.
> > >
> > Why do we need to update the git ref tag at all. Since these releases are
> > all ABI compatible with each other, can we not leave the checks still to be
> > against 19.11?
> 
> Checking only with 19.11 (major abi) would not detected breakage
> between minor versions.
> Like the meter symbols that entered the 20.0.1 version.

We check that new ABI, introduced in a minor ABI version, is not broken.




^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] version: 20.05-rc0
  2020-02-27 11:17  3%     ` Bruce Richardson
@ 2020-02-27 11:23  3%       ` David Marchand
  2020-02-27 11:26  4%         ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-02-27 11:23 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: Thomas Monjalon, dev

On Thu, Feb 27, 2020 at 12:17 PM Bruce Richardson
<bruce.richardson@intel.com> wrote:
>
> On Wed, Feb 26, 2020 at 03:01:04PM +0100, David Marchand wrote:
> > On Wed, Feb 26, 2020 at 2:55 PM Thomas Monjalon <thomas@monjalon.net> wrote:
> > >
> > > 26/02/2020 14:38, David Marchand:
> > > > Start a new release cycle with empty release notes.
> > > > ABI must now be checked with v20.02 as a reference.
> > > >
> > > > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > > > ---
> > > >  .travis.yml                            |   4 +
> > > >  ABI_VERSION                            |   2 +-
> > > >  VERSION                                |   2 +-
> > > >  doc/guides/rel_notes/index.rst         |   1 +
> > > >  doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
> > > >  5 files changed, 146 insertions(+), 2 deletions(-)
> > > >  create mode 100644 doc/guides/rel_notes/release_20_05.rst
> > >
> > > Acked-by: Thomas Monjalon <thomas@monjalon.net>
> > >
> > >
> > > > --- a/.travis.yml
> > > > +++ b/.travis.yml
> > > > +env:
> > > > +  global:
> > > > +    - REF_GIT_TAG=v20.02
> > >
> > > One question: why REF_GIT_TAG was not needed in Travis during 20.02?
> >
> > The .ci/linux-build.sh script has a default value for parameters.
> > http://git.dpdk.org/dpdk/tree/.ci/linux-build.sh#n71&h=v20.02
> >
> > This could be removed, so that we only have explicit values in the
> > .travis.yml configuration.
> > No strong opinion keeping them.
> >
> Why do we need to update the git ref tag at all. Since these releases are
> all ABI compatible with each other, can we not leave the checks still to be
> against 19.11?

Checking only with 19.11 (major abi) would not detected breakage
between minor versions.
Like the meter symbols that entered the 20.0.1 version.


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] version: 20.05-rc0
  2020-02-26 14:01  0%   ` David Marchand
@ 2020-02-27 11:17  3%     ` Bruce Richardson
  2020-02-27 11:23  3%       ` David Marchand
  0 siblings, 1 reply; 200+ results
From: Bruce Richardson @ 2020-02-27 11:17 UTC (permalink / raw)
  To: David Marchand; +Cc: Thomas Monjalon, dev

On Wed, Feb 26, 2020 at 03:01:04PM +0100, David Marchand wrote:
> On Wed, Feb 26, 2020 at 2:55 PM Thomas Monjalon <thomas@monjalon.net> wrote:
> >
> > 26/02/2020 14:38, David Marchand:
> > > Start a new release cycle with empty release notes.
> > > ABI must now be checked with v20.02 as a reference.
> > >
> > > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > > ---
> > >  .travis.yml                            |   4 +
> > >  ABI_VERSION                            |   2 +-
> > >  VERSION                                |   2 +-
> > >  doc/guides/rel_notes/index.rst         |   1 +
> > >  doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
> > >  5 files changed, 146 insertions(+), 2 deletions(-)
> > >  create mode 100644 doc/guides/rel_notes/release_20_05.rst
> >
> > Acked-by: Thomas Monjalon <thomas@monjalon.net>
> >
> >
> > > --- a/.travis.yml
> > > +++ b/.travis.yml
> > > +env:
> > > +  global:
> > > +    - REF_GIT_TAG=v20.02
> >
> > One question: why REF_GIT_TAG was not needed in Travis during 20.02?
> 
> The .ci/linux-build.sh script has a default value for parameters.
> http://git.dpdk.org/dpdk/tree/.ci/linux-build.sh#n71&h=v20.02
> 
> This could be removed, so that we only have explicit values in the
> .travis.yml configuration.
> No strong opinion keeping them.
> 
Why do we need to update the git ref tag at all. Since these releases are
all ABI compatible with each other, can we not leave the checks still to be
against 19.11?

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] version: 20.05-rc0
  2020-02-26 13:55  0% ` Thomas Monjalon
  2020-02-26 14:01  0%   ` David Marchand
@ 2020-02-27 11:01  0%   ` David Marchand
  2020-02-27 11:31  0%     ` David Marchand
  1 sibling, 1 reply; 200+ results
From: David Marchand @ 2020-02-27 11:01 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, Thomas Monjalon

On Wed, Feb 26, 2020 at 2:55 PM Thomas Monjalon <thomas@monjalon.net> wrote:
>
> 26/02/2020 14:38, David Marchand:
> > Start a new release cycle with empty release notes.
> > ABI must now be checked with v20.02 as a reference.
> >
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > ---
> >  .travis.yml                            |   4 +
> >  ABI_VERSION                            |   2 +-
> >  VERSION                                |   2 +-
> >  doc/guides/rel_notes/index.rst         |   1 +
> >  doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
> >  5 files changed, 146 insertions(+), 2 deletions(-)
> >  create mode 100644 doc/guides/rel_notes/release_20_05.rst
>
> Acked-by: Thomas Monjalon <thomas@monjalon.net>

Applied, here we go.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-25 13:41  3%       ` Ananyev, Konstantin
@ 2020-02-27 10:31  0%         ` Jerin Jacob
  2020-02-28  0:17  0%           ` David Christensen
  0 siblings, 1 reply; 200+ results
From: Jerin Jacob @ 2020-02-27 10:31 UTC (permalink / raw)
  To: Ananyev, Konstantin; +Cc: Stephen Hemminger, dpdk-dev, Olivier Matz, drc

On Tue, Feb 25, 2020 at 7:11 PM Ananyev, Konstantin
<konstantin.ananyev@intel.com> wrote:

> We do have a run-time check in our current enqueue()/dequeue implementation.
> In fact we support both modes: we have generic rte_ring_enqueue(/dequeue)_bulk(/burst)
> where sync behaviour is determined at runtime by value of prod(/cons).single.
> Or user can call  rte_ring_(mp/sp)_enqueue_* functions directly.
> This RFC follows exactly the same paradigm:
> rte_ring_enqueue(/dequeue)_bulk(/burst) kept generic and it's
> behaviour is determined at runtime, by value of prod(/cons).sync_type.
> Or user can call enqueue/dequeue with particular sync mode directly:
> rte_ring_(mp/sp/rts/hts)_enqueue_(bulk/burst)*.
> The only thing that changed:
>  Format of prod/cons now could differ depending on mode selected at _init_.
>  So you can't create a ring for let say SP mode and then in the middle of data-path
>  change your mind and start using MP_RTS mode.
>  For existing modes (SP/MP, SC/MC)  format remains the same and user can still
>  use them interchangeably, though of course that is an error prone practice.

Makes sense.


>
> > > But I agree with the problem statement that in the virtualization use
> > > case, It may be possible to have N virtual cores runs on a physical
> > > core.
> > >
> > > IMO, The best solution would be keeping the ring API same and have a
> > > different flavor in "compile-time". Something like
> > > liburcu did for accommodating different flavors.
> > >
> > > i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The
> > > application can simply include ONE header file in a C file based on
> > > the flavor.
>
> I don't think it is a flexible enough approach.
> In one app user might need to have several rings with different sync modes.
> Or even user might need a ring with different sync modes for enqueue/dequeue.

Ack.


> Yes, hiding rte_ring implementation inside .c would help a lot
> in terms of ABI maintenance and would make our future life easier.
> The question is what is the price for it in terms of performance,
> and are we ready to pay it. Not to mention that it would cause
> changes in many other libs/apps...
> So I think it should be a subject for a separate discussion.
> But, agree it would be good at least to measure the performance
> impact of such change.
> If I'll have some spare cycles, will give it a try.
> Meanwhile, can I ask Jerin and other guys to repeat tests from this RFC
> on their HW? Before continuing discussion would probably be good to know
> does the suggested patch work as expected across different platforms.


I tested on an arm64 HW. The former section is without the
patch(20.02) and later one with this patch.
I agree with Konstantin that getting more platform tests will be good
early so that we can focus on the approach
to avoid back and forth latter.


RTE>>ring_perf_autotest // without path

### Testing single element enq/deq ###
legacy APIs: SP/SC: single: 289.78
legacy APIs: MP/MC: single: 516.20

### Testing burst enq/deq ###
legacy APIs: SP/SC: burst (size: 8): 312.88
legacy APIs: SP/SC: burst (size: 32): 426.72
legacy APIs: MP/MC: burst (size: 8): 510.95
legacy APIs: MP/MC: burst (size: 32): 702.01

### Testing bulk enq/deq ###
legacy APIs: SP/SC: bulk (size: 8): 306.74
legacy APIs: SP/SC: bulk (size: 32): 411.56
legacy APIs: MP/MC: bulk (size: 8): 501.32
legacy APIs: MP/MC: bulk (size: 32): 693.07

### Testing empty bulk deq ###
legacy APIs: SP/SC: bulk (size: 8): 7.00
legacy APIs: MP/MC: bulk (size: 8): 7.00

### Testing using two physical cores ###
legacy APIs: SP/SC: bulk (size: 8): 74.36
legacy APIs: MP/MC: bulk (size: 8): 110.18
legacy APIs: SP/SC: bulk (size: 32): 23.04
legacy APIs: MP/MC: bulk (size: 32): 32.29

### Testing using all slave nodes ##
Bulk enq/dequeue count on size 8
Core [8] count = 293741
Core [9] count = 293741
Total count (size: 8): 587482

Bulk enq/dequeue count on size 32
Core [8] count = 244909
Core [9] count = 244909
Total count (size: 32): 1077300

### Testing single element enq/deq ###
elem APIs: element size 16B: SP/SC: single: 255.37
elem APIs: element size 16B: MP/MC: single: 456.68

### Testing burst enq/deq ###
elem APIs: element size 16B: SP/SC: burst (size: 8): 291.99
elem APIs: element size 16B: SP/SC: burst (size: 32): 456.25
elem APIs: element size 16B: MP/MC: burst (size: 8): 497.77
elem APIs: element size 16B: MP/MC: burst (size: 32): 680.87

### Testing bulk enq/deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 284.40
elem APIs: element size 16B: SP/SC: bulk (size: 32): 453.17
elem APIs: element size 16B: MP/MC: bulk (size: 8): 485.77
elem APIs: element size 16B: MP/MC: bulk (size: 32): 675.08

### Testing empty bulk deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 8.00
elem APIs: element size 16B: MP/MC: bulk (size: 8): 7.00

### Testing using two physical cores ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 74.45
elem APIs: element size 16B: MP/MC: bulk (size: 8): 105.91
elem APIs: element size 16B: SP/SC: bulk (size: 32): 22.92
elem APIs: element size 16B: MP/MC: bulk (size: 32): 31.55

### Testing using all slave nodes ###

Bulk enq/dequeue count on size 8
Core [8] count = 308724
Core [9] count = 308723
Total count (size: 8): 617447

Bulk enq/dequeue count on size 32
Core [8] count = 214269
Core [9] count = 214269
Total count (size: 32): 1045985

RTE>>ring_perf_autotest // with patch

### Testing single element enq/deq ###
legacy APIs: SP/SC: single: 289.78
legacy APIs: MP/MC: single: 475.76

### Testing burst enq/deq ###
legacy APIs: SP/SC: burst (size: 8): 323.91
legacy APIs: SP/SC: burst (size: 32): 424.60
legacy APIs: MP/MC: burst (size: 8): 523.00
legacy APIs: MP/MC: burst (size: 32): 717.09

### Testing bulk enq/deq ###
legacy APIs: SP/SC: bulk (size: 8): 317.74
legacy APIs: SP/SC: bulk (size: 32): 413.57
legacy APIs: MP/MC: bulk (size: 8): 512.89
legacy APIs: MP/MC: bulk (size: 32): 712.45

### Testing empty bulk deq ###
legacy APIs: SP/SC: bulk (size: 8): 7.00
legacy APIs: MP/MC: bulk (size: 8): 7.00

### Testing using two physical cores ###
legacy APIs: SP/SC: bulk (size: 8): 74.82
legacy APIs: MP/MC: bulk (size: 8): 96.45
legacy APIs: SP/SC: bulk (size: 32): 22.97
legacy APIs: MP/MC: bulk (size: 32): 32.52

### Testing using all slave nodes ###

Bulk enq/dequeue count on size 8
Core [8] count = 283928
Core [9] count = 283927
Total count (size: 8): 567855

Bulk enq/dequeue count on size 32
Core [8] count = 223916
Core [9] count = 223915
Total count (size: 32): 1015686

### Testing single element enq/deq ###
elem APIs: element size 16B: SP/SC: single: 267.65
elem APIs: element size 16B: MP/MC: single: 439.06

### Testing burst enq/deq ###
elem APIs: element size 16B: SP/SC: burst (size: 8): 302.44
elem APIs: element size 16B: SP/SC: burst (size: 32): 466.31
elem APIs: element size 16B: MP/MC: burst (size: 8): 502.51
elem APIs: element size 16B: MP/MC: burst (size: 32): 695.81

### Testing bulk enq/deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 295.15
elem APIs: element size 16B: SP/SC: bulk (size: 32): 462.77
elem APIs: element size 16B: MP/MC: bulk (size: 8): 496.89
elem APIs: element size 16B: MP/MC: bulk (size: 32): 690.46

### Testing empty bulk deq ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 7.50
elem APIs: element size 16B: MP/MC: bulk (size: 8): 7.44

### Testing using two physical cores ###
elem APIs: element size 16B: SP/SC: bulk (size: 8): 65.85
elem APIs: element size 16B: MP/MC: bulk (size: 8): 103.80
elem APIs: element size 16B: SP/SC: bulk (size: 32): 23.27
elem APIs: element size 16B: MP/MC: bulk (size: 32): 31.17

### Testing using all slave nodes ###

Bulk enq/dequeue count on size 8
Core [8] count = 304223
Core [9] count = 304221
Total count (size: 8): 608444

Bulk enq/dequeue count on size 32
Core [8] count = 214856
Core [9] count = 214855
Total count (size: 32): 1038155
Test OK
RTE>>quit









> Thanks
> Konstantin

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] Questions about rte_timer APIs
  2020-02-25 23:56  3% ` Honnappa Nagarahalli
@ 2020-02-26 16:57  0%   ` Carrillo, Erik G
  2020-02-27 16:58  0%     ` Honnappa Nagarahalli
  0 siblings, 1 reply; 200+ results
From: Carrillo, Erik G @ 2020-02-26 16:57 UTC (permalink / raw)
  To: Honnappa Nagarahalli, Robert Sanford
  Cc: dev, nd, Phil Yang, Gavin Hu, david.marchand, thomas, nd

Hi Honnappa,

Your description below looks correct to me.  For the current implementation, I referenced a couple of existing DPDK libraries, but primarily the rte_service library.  However, I agree that allocating the timer data structs only as needed would be a good idea.

You are also correct that, since the rte_timer_alt_* APIs are still experimental, they can change without constraint;  this would allow for the APIs to change as needed to support the above design.  It looks like the only users of those APIs in DPDK currently are the event timer adapter and unit test code.

Thanks,
Erik

> -----Original Message-----
> From: Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>
> Sent: Tuesday, February 25, 2020 5:56 PM
> To: Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com>; Robert
> Sanford <rsanford@akamai.com>; Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: dev <dev@dpdk.org>; nd <nd@arm.com>; Phil Yang
> <Phil.Yang@arm.com>; Gavin Hu <Gavin.Hu@arm.com>;
> david.marchand@redhat.com; thomas@monjalon.net; nd <nd@arm.com>
> Subject: RE: Questions about rte_timer APIs
> 
> Hi Erik,
> 	I see that the rte_timer_alt_xxx APIs are still marked as
> experimental. So, we should be able to change them without any ABI
> constraints. Please let me know what you think.
> 
> Thank you,
> Honnappa
> 
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Honnappa Nagarahalli
> > Sent: Thursday, February 13, 2020 11:55 PM
> > To: Robert Sanford <rsanford@akamai.com>; Erik Gabriel Carrillo
> > <erik.g.carrillo@intel.com>
> > Cc: dev <dev@dpdk.org>; nd <nd@arm.com>; Phil Yang
> > <Phil.Yang@arm.com>; Gavin Hu <Gavin.Hu@arm.com>; nd
> <nd@arm.com>
> > Subject: [dpdk-dev] Questions about rte_timer APIs
> >
> > Hi Erik/Robert,
> > 	I was looking at the rte_timer library code and have questions around
> > the way instances of timer list are allocated.
> >
> > The API 'rte_timer_subsystem_init' allocates RTE_MAX_DATA_ELS (64)
> > number of timer data structs. Each timer data struct acts as an
> > independent instance of timer list. The user allocates an instance by
> > calling 'rte_timer_data_alloc' which provides an index in the instance array.to s
> > Essentially, the library is allocating the memory upfront even though
> > there might not be a need to have 64 instances. Please correct me if I am
> wrong.
> >
> > Usually, creating multiple instances is handled by allocating required
> > memory, as and when required, by an 'init' API. This API also returns
> > a pointer to that instance which is passed to other APIs in the
> > library. For ex: rte_hash library follows this approach. IMO, this is an
> elegant way to handle multiple instances.
> > This approach does not waste memory and does not put any restriction
> > on number of instances.
> >
> > I wanted to understand the reasoning behind the current design to
> > handle multiple instances. Appreciate your inputs.
> >
> > Thank you,
> > Honnappa


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] version: 20.05-rc0
  2020-02-26 13:55  0% ` Thomas Monjalon
@ 2020-02-26 14:01  0%   ` David Marchand
  2020-02-27 11:17  3%     ` Bruce Richardson
  2020-02-27 11:01  0%   ` David Marchand
  1 sibling, 1 reply; 200+ results
From: David Marchand @ 2020-02-26 14:01 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

On Wed, Feb 26, 2020 at 2:55 PM Thomas Monjalon <thomas@monjalon.net> wrote:
>
> 26/02/2020 14:38, David Marchand:
> > Start a new release cycle with empty release notes.
> > ABI must now be checked with v20.02 as a reference.
> >
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > ---
> >  .travis.yml                            |   4 +
> >  ABI_VERSION                            |   2 +-
> >  VERSION                                |   2 +-
> >  doc/guides/rel_notes/index.rst         |   1 +
> >  doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
> >  5 files changed, 146 insertions(+), 2 deletions(-)
> >  create mode 100644 doc/guides/rel_notes/release_20_05.rst
>
> Acked-by: Thomas Monjalon <thomas@monjalon.net>
>
>
> > --- a/.travis.yml
> > +++ b/.travis.yml
> > +env:
> > +  global:
> > +    - REF_GIT_TAG=v20.02
>
> One question: why REF_GIT_TAG was not needed in Travis during 20.02?

The .ci/linux-build.sh script has a default value for parameters.
http://git.dpdk.org/dpdk/tree/.ci/linux-build.sh#n71&h=v20.02

This could be removed, so that we only have explicit values in the
.travis.yml configuration.
No strong opinion keeping them.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] version: 20.05-rc0
  2020-02-26 13:38 10% [dpdk-dev] [PATCH] version: 20.05-rc0 David Marchand
@ 2020-02-26 13:55  0% ` Thomas Monjalon
  2020-02-26 14:01  0%   ` David Marchand
  2020-02-27 11:01  0%   ` David Marchand
  0 siblings, 2 replies; 200+ results
From: Thomas Monjalon @ 2020-02-26 13:55 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

26/02/2020 14:38, David Marchand:
> Start a new release cycle with empty release notes.
> ABI must now be checked with v20.02 as a reference.
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
>  .travis.yml                            |   4 +
>  ABI_VERSION                            |   2 +-
>  VERSION                                |   2 +-
>  doc/guides/rel_notes/index.rst         |   1 +
>  doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
>  5 files changed, 146 insertions(+), 2 deletions(-)
>  create mode 100644 doc/guides/rel_notes/release_20_05.rst

Acked-by: Thomas Monjalon <thomas@monjalon.net>


> --- a/.travis.yml
> +++ b/.travis.yml
> +env:
> +  global:
> +    - REF_GIT_TAG=v20.02

One question: why REF_GIT_TAG was not needed in Travis during 20.02?



^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH] version: 20.05-rc0
@ 2020-02-26 13:38 10% David Marchand
  2020-02-26 13:55  0% ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-02-26 13:38 UTC (permalink / raw)
  To: dev; +Cc: thomas

Start a new release cycle with empty release notes.
ABI must now be checked with v20.02 as a reference.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 .travis.yml                            |   4 +
 ABI_VERSION                            |   2 +-
 VERSION                                |   2 +-
 doc/guides/rel_notes/index.rst         |   1 +
 doc/guides/rel_notes/release_20_05.rst | 139 +++++++++++++++++++++++++
 5 files changed, 146 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/rel_notes/release_20_05.rst

diff --git a/.travis.yml b/.travis.yml
index b64a81bd0..a57790ba8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,6 +34,10 @@ _doc_packages: &doc_packages
 before_install: ./.ci/${TRAVIS_OS_NAME}-setup.sh
 script: ./.ci/${TRAVIS_OS_NAME}-build.sh
 
+env:
+  global:
+    - REF_GIT_TAG=v20.02
+
 jobs:
   include:
   # x86_64 gcc jobs
diff --git a/ABI_VERSION b/ABI_VERSION
index fcc01369a..204da679a 100644
--- a/ABI_VERSION
+++ b/ABI_VERSION
@@ -1 +1 @@
-20.0.1
+20.0.2
diff --git a/VERSION b/VERSION
index d07c5a629..9791dd8af 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-20.02.0
+20.05.0-rc0
diff --git a/doc/guides/rel_notes/index.rst b/doc/guides/rel_notes/index.rst
index 24d927d33..31278d2a8 100644
--- a/doc/guides/rel_notes/index.rst
+++ b/doc/guides/rel_notes/index.rst
@@ -8,6 +8,7 @@ Release Notes
     :maxdepth: 1
     :numbered:
 
+    release_20_05
     release_20_02
     release_19_11
     release_19_08
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
new file mode 100644
index 000000000..2190eaf85
--- /dev/null
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -0,0 +1,139 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+   Copyright 2020 The DPDK contributors
+
+.. include:: <isonum.txt>
+
+DPDK Release 20.05
+==================
+
+.. **Read this first.**
+
+   The text in the sections below explains how to update the release notes.
+
+   Use proper spelling, capitalization and punctuation in all sections.
+
+   Variable and config names should be quoted as fixed width text:
+   ``LIKE_THIS``.
+
+   Build the docs and view the output file to ensure the changes are correct::
+
+      make doc-guides-html
+
+      xdg-open build/doc/html/guides/rel_notes/release_20_05.html
+
+
+New Features
+------------
+
+.. This section should contain new features added in this release.
+   Sample format:
+
+   * **Add a title in the past tense with a full stop.**
+
+     Add a short 1-2 sentence description in the past tense.
+     The description should be enough to allow someone scanning
+     the release notes to understand the new feature.
+
+     If the feature adds a lot of sub-features you can use a bullet list
+     like this:
+
+     * Added feature foo to do something.
+     * Enhanced feature bar to do something else.
+
+     Refer to the previous release notes for examples.
+
+     Suggested order in release notes items:
+     * Core libs (EAL, mempool, ring, mbuf, buses)
+     * Device abstraction libs and PMDs
+       - ethdev (lib, PMDs)
+       - cryptodev (lib, PMDs)
+       - eventdev (lib, PMDs)
+       - etc
+     * Other libs
+     * Apps, Examples, Tools (if significant)
+
+     This section is a comment. Do not overwrite or remove it.
+     Also, make sure to start the actual text at the margin.
+     =========================================================
+
+
+Removed Items
+-------------
+
+.. This section should contain removed items in this release. Sample format:
+
+   * Add a short 1-2 sentence description of the removed item
+     in the past tense.
+
+   This section is a comment. Do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+API Changes
+-----------
+
+.. This section should contain API changes. Sample format:
+
+   * sample: Add a short 1-2 sentence description of the API change
+     which was announced in the previous releases and made in this release.
+     Start with a scope label like "ethdev:".
+     Use fixed width quotes for ``function_names`` or ``struct_names``.
+     Use the past tense.
+
+   This section is a comment. Do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+ABI Changes
+-----------
+
+.. This section should contain ABI changes. Sample format:
+
+   * sample: Add a short 1-2 sentence description of the ABI change
+     which was announced in the previous releases and made in this release.
+     Start with a scope label like "ethdev:".
+     Use fixed width quotes for ``function_names`` or ``struct_names``.
+     Use the past tense.
+
+   This section is a comment. Do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+* No ABI change that would break compatibility with DPDK 20.02 and 19.11.
+
+
+Known Issues
+------------
+
+.. This section should contain new known issues in this release. Sample format:
+
+   * **Add title in present tense with full stop.**
+
+     Add a short 1-2 sentence description of the known issue
+     in the present tense. Add information on any known workarounds.
+
+   This section is a comment. Do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
+
+
+Tested Platforms
+----------------
+
+.. This section should contain a list of platforms that were tested
+   with this release.
+
+   The format is:
+
+   * <vendor> platform with <vendor> <type of devices> combinations
+
+     * List of CPU
+     * List of OS
+     * List of devices
+     * Other relevant details...
+
+   This section is a comment. Do not overwrite or remove it.
+   Also, make sure to start the actual text at the margin.
+   =========================================================
-- 
2.23.0


^ permalink raw reply	[relevance 10%]

* Re: [dpdk-dev] Questions about rte_timer APIs
  @ 2020-02-25 23:56  3% ` Honnappa Nagarahalli
  2020-02-26 16:57  0%   ` Carrillo, Erik G
  0 siblings, 1 reply; 200+ results
From: Honnappa Nagarahalli @ 2020-02-25 23:56 UTC (permalink / raw)
  To: Honnappa Nagarahalli, Robert Sanford, Erik Gabriel Carrillo
  Cc: dev, nd, Phil Yang, Gavin Hu, david.marchand, thomas, nd

Hi Erik,
	I see that the rte_timer_alt_xxx APIs are still marked as experimental. So, we should be able to change them without any ABI constraints. Please let me know what you think.

Thank you,
Honnappa

> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Honnappa Nagarahalli
> Sent: Thursday, February 13, 2020 11:55 PM
> To: Robert Sanford <rsanford@akamai.com>; Erik Gabriel Carrillo
> <erik.g.carrillo@intel.com>
> Cc: dev <dev@dpdk.org>; nd <nd@arm.com>; Phil Yang
> <Phil.Yang@arm.com>; Gavin Hu <Gavin.Hu@arm.com>; nd <nd@arm.com>
> Subject: [dpdk-dev] Questions about rte_timer APIs
> 
> Hi Erik/Robert,
> 	I was looking at the rte_timer library code and have questions around
> the way instances of timer list are allocated.
> 
> The API 'rte_timer_subsystem_init' allocates RTE_MAX_DATA_ELS (64)
> number of timer data structs. Each timer data struct acts as an independent
> instance of timer list. The user allocates an instance by calling
> 'rte_timer_data_alloc' which provides an index in the instance array.
> Essentially, the library is allocating the memory upfront even though there
> might not be a need to have 64 instances. Please correct me if I am wrong.
> 
> Usually, creating multiple instances is handled by allocating required memory,
> as and when required, by an 'init' API. This API also returns a pointer to that
> instance which is passed to other APIs in the library. For ex: rte_hash library
> follows this approach. IMO, this is an elegant way to handle multiple instances.
> This approach does not waste memory and does not put any restriction on
> number of instances.
> 
> I wanted to understand the reasoning behind the current design to handle
> multiple instances. Appreciate your inputs.
> 
> Thank you,
> Honnappa


^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [dpdk-announce] DPDK 20.02 released
@ 2020-02-25 22:59  4% Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-02-25 22:59 UTC (permalink / raw)
  To: announce

A new release is available:
	https://fast.dpdk.org/rel/dpdk-20.02.tar.xz

The statistics looks like a post-LTS ABI-compatible release:
	820 commits from 156 authors
	876 files changed, 59941 insertions(+), 22565 deletions(-)

It is not planned (yet) to start a maintenance branch for 20.02.
This release and next ones (20.05, 20.08) are ABI-compatible with 19.11.


Below are some new features, grouped by category.
General:
	- ABI check tooling
	- FreeBSD 13 support
	- Linux kernel modules disabled in default build
	- API wait until equal
	- use CPU lcore with ID > total max
	- ring with configurable element size
	- pool of mbufs with pinned external buffers
Networking:
	- Pensando ionic driver
	- Marvell driver for OCTEON TX2 end point
	- Mellanox vDPA driver
	- rte_flow API for DSCP
	- rte_flow API for L2TPv3 over IP
Cryptography:
	- Marvell OCTEON TX2 inline IPsec
	- CPU crypto based on new libraries (intel-ipsec-mb and AArch64cryptolib)
	- synchronous CPU crypto API
	- more algorithms: ECDSA, ECPM
Applications:
	- event mode in l3fwd example

More details in the release notes:
	http://doc.dpdk.org/guides/rel_notes/release_20_02.html


There are 69 new contributors (including authors, reviewers and testers).
Welcome to Abed Kamaluddin, Abhishek Marathe, Adam Ludkiewicz,
Adrian Podlawski, Aleksandr Loktionov, Alexander Kozyrev,
Alfredo Cardigliano, Andrew Pinski, Apeksha Gupta,
Balakrishna Bhamidipati, Carolyn Wyborny, Chandu Babu N,
Cheng Jiang, Chengchang Tang, Damian Milosek, Dariusz Chaberski,
Dariusz Jagus, Dexuan Cui, Dmitry Kozlyuk, Donald Lee, Dzmitry Sautsa,
Eugenio Pérez, Fang TongHao, Gal Cohen, Gargi Sau, Girish Nandibasappa,
Ilja Van Sprundel, Itsuro Oda, Jaroslaw Gawin, Jörg Thalheim,
Kiran Patil, Krzysztof Galazka, Kumar Amber, Li Feng, Lijun Ou,
Mahipal Challa, Manish Chopra, Marcin Formela, Martyna Szapar,
Mateusz Rusinski, Michael Baum, Michal Litwicki, Michal Swiatkowski,
Narcisa Vasile, Niclas Storm, Pandi Kumar Maharajan, Piotr Azarewicz,
Piotr Kwapulinski, Piotr Pietruszewski, Prateek Agarwal, Praveen Shetty,
Rafael Ávila de Espíndola, Ricardo Roldan, Robert Konklewski,
Satananda Burla, Savinay Dharmappa, Scott Wasson, Selwin Sebastian,
Shannon Nelson, Shiri Kuzin, Sunil Pai G, Sylwia Wnuczko, Thomas Faivre,
Tomasz Konieczny, Vitaliy Mysak, Xuan Ding, Xuan Li, Xueming Zhang,
and Yisen Zhuang.

Below is the number of patches per company (with authors count):
    268     Intel (54)
    193     Mellanox (16)
    114     Marvell (23)
     49     Broadcom (7)
     34     Red Hat (7)
     32     Huawei (8)
     30     ARM (4)
     25     Microsoft (1)
     18     ntop (1)
      9     6WIND (5)
      6     NXP (4)
      5     AMD (3)
      4     VA Linux Systems (1)
      4     Ericsson (1)
      4     Cisco (1)

Based on Reviewed-by and Acked-by tags, the top reviewers are:
     76     Viacheslav Ovsiienko <viacheslavo@mellanox.com>
     56     Qi Zhang <qi.z.zhang@intel.com>
     47     Xiaolong Ye <xiaolong.ye@intel.com>
     46     Akhil Goyal <akhil.goyal@nxp.com>
     44     Ferruh Yigit <ferruh.yigit@intel.com>
     43     Matan Azrad <matan@mellanox.com>
     43     Jerin Jacob <jerinj@marvell.com>
     38     Beilei Xing <beilei.xing@intel.com>
     35     Qiming Yang <qiming.yang@intel.com>
     34     Ajit Khaparde <ajit.khaparde@broadcom.com>
     33     Maxime Coquelin <maxime.coquelin@redhat.com>
     31     Ori Kam <orika@mellanox.com>
     25     Gavin Hu <gavin.hu@arm.com>
     24     David Marchand <david.marchand@redhat.com>
     23     Konstantin Ananyev <konstantin.ananyev@intel.com>


The new features for 20.05 may be submitted during the next 21 days,
in order to be reviewed and integrated before mid-April.
DPDK 20.05 should be released on 20-05-20.
	http://core.dpdk.org/roadmap#dates
The schedule is pushed because of the special worldwide context.
Some future release cycles will have to be shorter.

Thanks everyone, and take care.



^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v2] doc: plan splitting the ethdev ops struct
  2020-02-25 18:13  0%   ` David Marchand
@ 2020-02-25 18:18  0%     ` Ferruh Yigit
  0 siblings, 0 replies; 200+ results
From: Ferruh Yigit @ 2020-02-25 18:18 UTC (permalink / raw)
  To: David Marchand
  Cc: Neil Horman, John McNamara, Marko Kovacevic, dev, Jerin Jacob,
	Thomas Monjalon, Andrew Rybchenko

On 2/25/2020 6:13 PM, David Marchand wrote:
> On Tue, Feb 25, 2020 at 1:44 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>
>> For the ABI compatibility it is better to hide internal data structures
>> from the application as much as possible. But because of some inline
>> functions 'struct eth_dev_ops' can't be hidden completely.
>>
>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
>> inline functions and ones not used, and hide the second part that not
>> used by inline functions completely to the application.
>>
>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>> Acked-by: Jerin Jacob <jerinj@marvell.com>
> 
> Sorry, this patch is missing the necessary acks for merging.
> This change can still be announced for 20.11 in the next releases and
> the details can be discussed again since a conclusion was not reached.
> 
> 

That is OK, we can drop for 20.02, I can send a new version to target the 20.11
change only removing interim change.


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] doc: plan splitting the ethdev ops struct
  2020-02-25 12:44  3% ` [dpdk-dev] [PATCH v2] " Ferruh Yigit
  2020-02-25 15:51  3%   ` Andrew Rybchenko
@ 2020-02-25 18:13  0%   ` David Marchand
  2020-02-25 18:18  0%     ` Ferruh Yigit
  2020-03-04  9:57  4%   ` [dpdk-dev] [PATCH v3] " Ferruh Yigit
  2 siblings, 1 reply; 200+ results
From: David Marchand @ 2020-02-25 18:13 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Neil Horman, John McNamara, Marko Kovacevic, dev, Jerin Jacob,
	Thomas Monjalon, Andrew Rybchenko

On Tue, Feb 25, 2020 at 1:44 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>
> For the ABI compatibility it is better to hide internal data structures
> from the application as much as possible. But because of some inline
> functions 'struct eth_dev_ops' can't be hidden completely.
>
> Plan is to split the 'struct eth_dev_ops' into two as ones used by
> inline functions and ones not used, and hide the second part that not
> used by inline functions completely to the application.
>
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> Acked-by: Jerin Jacob <jerinj@marvell.com>

Sorry, this patch is missing the necessary acks for merging.
This change can still be announced for 20.11 in the next releases and
the details can be discussed again since a conclusion was not reached.


Thanks.

-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: alias to experimental tag for stable apis
  2020-02-25 15:35  0% ` [dpdk-dev] [PATCH] " Neil Horman
@ 2020-02-25 17:57  0%   ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-02-25 17:57 UTC (permalink / raw)
  To: Ray Kinsella, Neil Horman
  Cc: dev, Mcnamara, John, Yigit, Ferruh, Kovacevic, Marko

On Tue, Feb 25, 2020 at 4:36 PM Neil Horman <nhorman@tuxdriver.com> wrote:
>
> On Wed, Feb 05, 2020 at 03:17:52PM +0000, Ray Kinsella wrote:
> > When a maintainer is promoting an API to become part of the next major ABI
> > version by removing the experimental tag, possibly a few releases in advance of
> > the declaration of the next ABI version. The maintainer may choose to offer an
> > alias to the experimental tag, as removing the tag before the declaration of the
> > next major ABI version, would cause an ABI breakage for applications using the
> > API.
> >
> > Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
> > ---
> >  doc/guides/contributing/abi_policy.rst | 10 ++++++++++
> >  1 file changed, 10 insertions(+)
> >
> > diff --git a/doc/guides/contributing/abi_policy.rst b/doc/guides/contributing/abi_policy.rst
> > index 05ca959..9a4a102 100644
> > --- a/doc/guides/contributing/abi_policy.rst
> > +++ b/doc/guides/contributing/abi_policy.rst
> > @@ -159,6 +159,11 @@ The requirements for changing the ABI are:
> >       ``experimental``, as described in the section on :ref:`Experimental APIs
> >       and Libraries <experimental_apis>`.
> >
> > +   - In situations where an ``experimental`` API has been stable for some time.
> > +     When promoting the API to become part of the next ABI version, the
> > +     maintainer may choose to provide an alias to the ``experimental`` tag, so
> > +     as not to break consuming applications.
> > +
> I don't have any issue with the approach, but just to ask the question, is it
> worth providing an example here, of how exactly to do this?  The use of
> VERSION_SYMBOL isn't often used, and so may be non-obvious.
>
> Actually, as I look at it, the VERSION_SYMBOL macro assume a DPDK_ prefix on the
> version string, which works for versioned symbols, but not for the EXPERIMENTAL
> symbol version (no DPDK_ prefix).  We should probably create a variant of the
> VERSION_SYMBOL macro to allow aliasing to the EXPERIMENTAL version, something
> like ALIAS_TO_EXPERIMENTAL() or some such

Let's clarify this part so this can be merged in early 20.05.
Thanks.


-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] doc: plan splitting the ethdev ops struct
  2020-02-25 16:13  3%     ` Ferruh Yigit
@ 2020-02-25 16:41  0%       ` Andrew Rybchenko
  0 siblings, 0 replies; 200+ results
From: Andrew Rybchenko @ 2020-02-25 16:41 UTC (permalink / raw)
  To: Ferruh Yigit, Neil Horman, John McNamara, Marko Kovacevic
  Cc: dev, Jerin Jacob, David Marchand, Thomas Monjalon

On 2/25/20 7:13 PM, Ferruh Yigit wrote:
> On 2/25/2020 3:51 PM, Andrew Rybchenko wrote:
>> On 2/25/20 3:44 PM, Ferruh Yigit wrote:
>>> For the ABI compatibility it is better to hide internal data structures
>>> from the application as much as possible. But because of some inline
>>> functions 'struct eth_dev_ops' can't be hidden completely.
>>>
>>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
>>> inline functions and ones not used, and hide the second part that not
>>> used by inline functions completely to the application.
>>>
>>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>>> Acked-by: Jerin Jacob <jerinj@marvell.com>
>>> ---
>>> Cc: David Marchand <david.marchand@redhat.com>
>>> Cc: Thomas Monjalon <thomas@monjalon.net>
>>> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
>>>
>>> v2:
>>> * Add target date for the work
>>> * Give more detail on what will be done
>>> ---
>>>  doc/guides/rel_notes/deprecation.rst | 11 +++++++++++
>>>  1 file changed, 11 insertions(+)
>>>
>>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>>> index 99d81564a..ff612a615 100644
>>> --- a/doc/guides/rel_notes/deprecation.rst
>>> +++ b/doc/guides/rel_notes/deprecation.rst
>>> @@ -86,6 +86,17 @@ Deprecation Notices
>>>    In 19.11 PMDs will still update the field even when the offload is not
>>>    enabled.
>>>  
>>> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
>>> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
>>> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
>>> +  access the struct directly. The struct will be separate in two, the ops used
>>> +  by inline functions still will be accessible to user but rest will be hidden.
>>> +  Initial split will be done in 20.05 with adding reserved fields for the struct
>>> +  used by inline functions, and by putting new struct reference into public one
>>> +  to not increase the size of ``struct rte_eth_dev``, proper split will be done
>>> +  in 20.11 by moving inline dev_ops function to next to Rx/Tx burst functions and
>>> +  hiding rest.
>>> +
>>>  * cryptodev: support for using IV with all sizes is added, J0 still can
>>>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
>>>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
>>
>> I'd like to understand why do we need an intermediate solution first.
> 
> We don't need it really, we may prefer to postpone the update to 20.11.
> 
>> Also rereading above few times I've failed to fully understand what
>> will be done and why it does not break API/ABI.
>>
> 
> Agree it wasn't very clear, but I mean something like below, I hope it clarifies:
> 
> Previously:
> 
> struct rte_eth_dev
> 
> +--------+
> |        |    *dev_ops    struct eth_dev_ops
> |        |
> |        +-------------->+--------+
> |        |               |        |
> |        |               |        |
> |        |               |        |
> |        |               |        |
> +--------+               |        |
>                          |        |
>                          |        |
>                          |        |
>                          +--------+
> 
> 
> Proposed:
> 
> struct rte_eth_dev
> 
> +--------+
> |        |                struct eth_dev_ops
> |        |
> |*dev_ops+-------------->+--------+
> |        |               |        |
> |        |               | Reserv |
> |        |               |        |
> |        |               |        |
> +--------+               |        |
>                          +--------+
>                          | inline |
>                          | de^_ops|               struct eth_dev_ops
>                          +--------+
>                          | *priv  +------------->+--------+
>                          +--------+              |        |
>                                                  |        |
>                                                  |        |
>                                                  |        |
>                                                  |        |
>                                                  |        |
>                                                  |        |
>                                                  |        |
>                                                  +--------+
> 
> This is only to keep ABI compatibility [1] while separating the struct.
> 
> [1]
> - The offset of some functions in the dev_ops struct should be same
> - The size of the "struct rte_eth_dev" should be same
> 

OK, got it. Many thanks for explanations.

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2] doc: plan splitting the ethdev ops struct
  2020-02-25 15:51  3%   ` Andrew Rybchenko
@ 2020-02-25 16:13  3%     ` Ferruh Yigit
  2020-02-25 16:41  0%       ` Andrew Rybchenko
  0 siblings, 1 reply; 200+ results
From: Ferruh Yigit @ 2020-02-25 16:13 UTC (permalink / raw)
  To: Andrew Rybchenko, Neil Horman, John McNamara, Marko Kovacevic
  Cc: dev, Jerin Jacob, David Marchand, Thomas Monjalon

On 2/25/2020 3:51 PM, Andrew Rybchenko wrote:
> On 2/25/20 3:44 PM, Ferruh Yigit wrote:
>> For the ABI compatibility it is better to hide internal data structures
>> from the application as much as possible. But because of some inline
>> functions 'struct eth_dev_ops' can't be hidden completely.
>>
>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
>> inline functions and ones not used, and hide the second part that not
>> used by inline functions completely to the application.
>>
>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>> Acked-by: Jerin Jacob <jerinj@marvell.com>
>> ---
>> Cc: David Marchand <david.marchand@redhat.com>
>> Cc: Thomas Monjalon <thomas@monjalon.net>
>> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
>>
>> v2:
>> * Add target date for the work
>> * Give more detail on what will be done
>> ---
>>  doc/guides/rel_notes/deprecation.rst | 11 +++++++++++
>>  1 file changed, 11 insertions(+)
>>
>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>> index 99d81564a..ff612a615 100644
>> --- a/doc/guides/rel_notes/deprecation.rst
>> +++ b/doc/guides/rel_notes/deprecation.rst
>> @@ -86,6 +86,17 @@ Deprecation Notices
>>    In 19.11 PMDs will still update the field even when the offload is not
>>    enabled.
>>  
>> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
>> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
>> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
>> +  access the struct directly. The struct will be separate in two, the ops used
>> +  by inline functions still will be accessible to user but rest will be hidden.
>> +  Initial split will be done in 20.05 with adding reserved fields for the struct
>> +  used by inline functions, and by putting new struct reference into public one
>> +  to not increase the size of ``struct rte_eth_dev``, proper split will be done
>> +  in 20.11 by moving inline dev_ops function to next to Rx/Tx burst functions and
>> +  hiding rest.
>> +
>>  * cryptodev: support for using IV with all sizes is added, J0 still can
>>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
>>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
> 
> I'd like to understand why do we need an intermediate solution first.

We don't need it really, we may prefer to postpone the update to 20.11.

> Also rereading above few times I've failed to fully understand what
> will be done and why it does not break API/ABI.
> 

Agree it wasn't very clear, but I mean something like below, I hope it clarifies:

Previously:

struct rte_eth_dev

+--------+
|        |    *dev_ops    struct eth_dev_ops
|        |
|        +-------------->+--------+
|        |               |        |
|        |               |        |
|        |               |        |
|        |               |        |
+--------+               |        |
                         |        |
                         |        |
                         |        |
                         +--------+


Proposed:

struct rte_eth_dev

+--------+
|        |                struct eth_dev_ops
|        |
|*dev_ops+-------------->+--------+
|        |               |        |
|        |               | Reserv |
|        |               |        |
|        |               |        |
+--------+               |        |
                         +--------+
                         | inline |
                         | de^_ops|               struct eth_dev_ops
                         +--------+
                         | *priv  +------------->+--------+
                         +--------+              |        |
                                                 |        |
                                                 |        |
                                                 |        |
                                                 |        |
                                                 |        |
                                                 |        |
                                                 |        |
                                                 +--------+

This is only to keep ABI compatibility [1] while separating the struct.

[1]
- The offset of some functions in the dev_ops struct should be same
- The size of the "struct rte_eth_dev" should be same

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v2] doc: plan splitting the ethdev ops struct
  2020-02-25 12:44  3% ` [dpdk-dev] [PATCH v2] " Ferruh Yigit
@ 2020-02-25 15:51  3%   ` Andrew Rybchenko
  2020-02-25 16:13  3%     ` Ferruh Yigit
  2020-02-25 18:13  0%   ` David Marchand
  2020-03-04  9:57  4%   ` [dpdk-dev] [PATCH v3] " Ferruh Yigit
  2 siblings, 1 reply; 200+ results
From: Andrew Rybchenko @ 2020-02-25 15:51 UTC (permalink / raw)
  To: Ferruh Yigit, Neil Horman, John McNamara, Marko Kovacevic
  Cc: dev, Jerin Jacob, David Marchand, Thomas Monjalon

On 2/25/20 3:44 PM, Ferruh Yigit wrote:
> For the ABI compatibility it is better to hide internal data structures
> from the application as much as possible. But because of some inline
> functions 'struct eth_dev_ops' can't be hidden completely.
>
> Plan is to split the 'struct eth_dev_ops' into two as ones used by
> inline functions and ones not used, and hide the second part that not
> used by inline functions completely to the application.
>
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> Acked-by: Jerin Jacob <jerinj@marvell.com>
> ---
> Cc: David Marchand <david.marchand@redhat.com>
> Cc: Thomas Monjalon <thomas@monjalon.net>
> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
>
> v2:
> * Add target date for the work
> * Give more detail on what will be done
> ---
>  doc/guides/rel_notes/deprecation.rst | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index 99d81564a..ff612a615 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -86,6 +86,17 @@ Deprecation Notices
>    In 19.11 PMDs will still update the field even when the offload is not
>    enabled.
>  
> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
> +  access the struct directly. The struct will be separate in two, the ops used
> +  by inline functions still will be accessible to user but rest will be hidden.
> +  Initial split will be done in 20.05 with adding reserved fields for the struct
> +  used by inline functions, and by putting new struct reference into public one
> +  to not increase the size of ``struct rte_eth_dev``, proper split will be done
> +  in 20.11 by moving inline dev_ops function to next to Rx/Tx burst functions and
> +  hiding rest.
> +
>  * cryptodev: support for using IV with all sizes is added, J0 still can
>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal

I'd like to understand why do we need an intermediate solution first.
Also rereading above few times I've failed to fully understand what
will be done and why it does not break API/ABI.


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] doc: alias to experimental tag for stable apis
    @ 2020-02-25 15:35  0% ` Neil Horman
  2020-02-25 17:57  0%   ` David Marchand
  1 sibling, 1 reply; 200+ results
From: Neil Horman @ 2020-02-25 15:35 UTC (permalink / raw)
  To: Ray Kinsella; +Cc: dev, john.mcnamara, ferruh.yigit, marko.kovacevic

On Wed, Feb 05, 2020 at 03:17:52PM +0000, Ray Kinsella wrote:
> When a maintainer is promoting an API to become part of the next major ABI
> version by removing the experimental tag, possibly a few releases in advance of
> the declaration of the next ABI version. The maintainer may choose to offer an
> alias to the experimental tag, as removing the tag before the declaration of the
> next major ABI version, would cause an ABI breakage for applications using the
> API.
> 
> Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
> ---
>  doc/guides/contributing/abi_policy.rst | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/doc/guides/contributing/abi_policy.rst b/doc/guides/contributing/abi_policy.rst
> index 05ca959..9a4a102 100644
> --- a/doc/guides/contributing/abi_policy.rst
> +++ b/doc/guides/contributing/abi_policy.rst
> @@ -159,6 +159,11 @@ The requirements for changing the ABI are:
>       ``experimental``, as described in the section on :ref:`Experimental APIs
>       and Libraries <experimental_apis>`.
>  
> +   - In situations where an ``experimental`` API has been stable for some time.
> +     When promoting the API to become part of the next ABI version, the
> +     maintainer may choose to provide an alias to the ``experimental`` tag, so
> +     as not to break consuming applications.
> +
I don't have any issue with the approach, but just to ask the question, is it
worth providing an example here, of how exactly to do this?  The use of
VERSION_SYMBOL isn't often used, and so may be non-obvious.

Actually, as I look at it, the VERSION_SYMBOL macro assume a DPDK_ prefix on the
version string, which works for versioned symbols, but not for the EXPERIMENTAL
symbol version (no DPDK_ prefix).  We should probably create a variant of the
VERSION_SYMBOL macro to allow aliasing to the EXPERIMENTAL version, something
like ALIAS_TO_EXPERIMENTAL() or some such

Neil

>  #. If a newly proposed API functionally replaces an existing one, when the new
>     API becomes non-experimental, then the old one is marked with
>     ``__rte_deprecated``.
> @@ -317,6 +322,11 @@ not required. Though, an API should remain in experimental state for at least
>  one release. Thereafter, the normal process of posting patch for review to
>  mailing list can be followed.
>  
> +After the experimental tag has been formally removed, a tree/sub-tree maintainer
> +may choose to offer an alias to the experimental tag so as not to break
> +applications using the API. This alias can then be dropped at the declaration of
> +next major ABI version.
> +
>  Libraries
>  ~~~~~~~~~
>  
> -- 
> 2.7.4
> 
> 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk-announce] release candidate 20.02-rc4
  2020-02-25 14:44  0%     ` Thomas Monjalon
@ 2020-02-25 15:27  0%       ` Raslan Darawsheh
  0 siblings, 0 replies; 200+ results
From: Raslan Darawsheh @ 2020-02-25 15:27 UTC (permalink / raw)
  To: Ali Alnubani, Xu, Qian Q, Thomas Monjalon
  Cc: dev, Asaf Penso, Peng, Yuan, Yu, PingX

Hi,

It's Ok from our side and we can release.

Kindest regards
Raslan Darawsheh

Kindest regards
Raslan Darawsheh

________________________________
From: Thomas Monjalon <thomas@monjalon.net>
Sent: Tuesday, February 25, 2020 4:44:26 PM
To: Ali Alnubani <alialnu@mellanox.com>; Xu, Qian Q <qian.q.xu@intel.com>; Raslan Darawsheh <rasland@mellanox.com>
Cc: dev@dpdk.org <dev@dpdk.org>; Asaf Penso <asafp@mellanox.com>; Peng, Yuan <yuan.peng@intel.com>; Yu, PingX <pingx.yu@intel.com>
Subject: Re: [dpdk-announce] release candidate 20.02-rc4

Can we assume we are OK to release today?


25/02/2020 15:37, Xu, Qian Q:
> Some quick update from Intel on RC4 testing
>
> Summary
>
> 1. Totally execution percentage is around 90%, pass rate is around 98%
> 2. Created 2 new medium/low issue in RC4.
>
> Details:
> 1. Intel NIC PMD PF & VF regression: 95% executed, 0 critical issue and high issue found.
> Function cases include rx/tx/forward packets, packet processing, jumboframe, dual vlan, filter cases and so on: 2 bugs found, no critical/high bugs.
> Performance cases such as l2fwd, l3fwd, single core and so on: no new bug is found.
> 2. Cryptodev cases include ipsec_gw cryptodev, fips cryptodev, l2fwd crypto, performance cases and so on: no critical and no high bugs found.
>  Function cases all passed, performance cases not fully executed.
> 3. Vhost/virtio: PVP/loopback, qemu/virtio-user, multi-queue, dequeue zero copy cases and so on: 1 new medium bug is found.
> 4. Power relate cases, no new bug is found.
> 5. ABI test includes unit test, vhost and flow related tests.  no new bug is  found.
> 6. 20.02 new features include ABI test, L2tpv3,  crypto_dev related new features and so no.  no new bug is found.
>
>
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Ali Alnubani
> > Sent: Tuesday, February 25, 2020 5:59 PM
> > To: Thomas Monjalon <thomas@monjalon.net>; dev@dpdk.org
> > Cc: Raslan Darawsheh <rasland@mellanox.com>; Asaf Penso
> > <asafp@mellanox.com>
> > Subject: Re: [dpdk-dev] [dpdk-announce] release candidate 20.02-rc4
> >
> > Hi,
> >
> > > -----Original Message-----
> > > From: announce <announce-bounces@dpdk.org> On Behalf Of Thomas
> > > Monjalon
> > > Sent: Saturday, February 22, 2020 11:08 PM
> > > To: announce@dpdk.org
> > > Subject: [dpdk-announce] release candidate 20.02-rc4
> > >
> > > A new DPDK release candidate is ready for testing:
> > <removed>
> > >
> > > This is the last release candidate for DPDK 20.02.
> > > Please share some release validation results by replying to this
> > > message (at dev@dpdk.org).
> > > If no critical issue is reported, 20.02 will be closed on Tuesday 25th.
> > >
> > > If you are preparing the next release cycle, please send your v1
> > > patches before the 20.05 proposal deadline, which will happen on March 18th.
> > > It is also time to build an estimated roadmap for the next cycles.
> > >
> > > Thank you everyone
> > >
> >
> > The following covers the tests that we ran on Mellanox hardware for this
> > version:
> >
> > - Basic functionality:
> >   Send and receive multiple types of traffic.
> > - testpmd xstats counter test.
> > - testpmd timestamp test.
> > - Changing/checking link status through testpmd.
> > - RTE flow and flow_director tests.
> >   Items: eth / vlan / ipv4 / ipv6 / tcp / udp / icmp / gre / nvgre / vxlan / geneve /
> > ip in ip / mplsoudp / mplsogre / gtp
> >   Actions: drop / queue / rss / mark / flag / jump / count / port_id / raw_encap /
> > raw_decap / vxlan_encap / vxlan_decap / NAT
> > - Some RSS tests.
> > - VLAN stripping and insertion tests.
> > - Checksum and TSO tests.
> > - ptype tests.
> > - l3fwd-power example application tests.
> > - Multi-process example applications tests.
> >
> > We don't see any critical issues blocking the release.
> >
> > Thanks,
> > Ali




^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-25  0:58  0%     ` Honnappa Nagarahalli
@ 2020-02-25 15:14  0%       ` Ananyev, Konstantin
  0 siblings, 0 replies; 200+ results
From: Ananyev, Konstantin @ 2020-02-25 15:14 UTC (permalink / raw)
  To: Honnappa Nagarahalli, Jerin Jacob, Stephen Hemminger
  Cc: dpdk-dev, Olivier Matz, nd, nd, wang.yong19

> > > > Upfront note - that RFC is not a complete patch.
> > > > It introduces an ABI breakage, plus it doesn't update ring_elem code
> > > > properly, etc.
> > > > I plan to deal with all these things in later versions.
> > > > Right now I seek an initial feedback about proposed ideas.
> > > > Would also ask people to repeat performance tests (see below) on
> > > > their platforms to confirm the impact.
> > > >
> > > > More and more customers use(/try to use) DPDK based apps within
> > > > overcommitted systems (multiple acttive threads over same pysical cores):
> > > > VM, container deployments, etc.
> > > > One quite common problem they hit: Lock-Holder-Preemption with
> > rte_ring.
> > > > LHP is quite a common problem for spin-based sync primitives
> > > > (spin-locks, etc.) on overcommitted systems.
> > > > The situation gets much worse when some sort of fair-locking
> > > > technique is used (ticket-lock, etc.).
> > > > As now not only lock-owner but also lock-waiters scheduling order
> > > > matters a lot.
> > > > This is a well-known problem for kernel within VMs:
> > > > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> These slides seem to indicate that the problems are mitigated through the Hypervisor configuration. Do we still need to address the issues?

I am not really an expert here, but AFAIK current mitigations deal mostly with guest kernel:
linux implements PV version of spinlocks (unfair and/or based on hypercall availability),
hypervisor might make decision itself based on is guest in user/kernel mode,
plus on some special cpu instructions. 
We do spin in user-space mode.
Might be hypervisors became smarter these days, but so far,
I heard about few different customers that hit such problem.
As an example, NA DPDK summit presentation:
https://dpdkna2019.sched.com/event/WYBG/dpdk-containers-challenges-solutions-wang-yong-zte
page 16 (problem #4) describes same issue.

> 
> > > > The problem with rte_ring is that while head accusion is sort of
> > > > un-fair locking, waiting on tail is very similar to ticket lock
> > > > schema - tail has to be updated in particular order.
> > > > That makes current rte_ring implementation to perform really pure on
> > > > some overcommited scenarios.
> > >
> > > Rather than reform rte_ring to fit this scenario, it would make more
> > > sense to me to introduce another primitive. The current lockless ring
> > > performs very well for the isolated thread model that DPDK was built
> > > around. This looks like a case of customers violating the usage model
> > > of the DPDK and then being surprised at the fallout.
> >
> > I agree with Stephen here.
> >
> > I think, adding more runtime check in the enqueue() and dequeue() will have a
> > bad effect on the low-end cores too.
> > But I agree with the problem statement that in the virtualization use case, It
> > may be possible to have N virtual cores runs on a physical core.
> It is hard to imagine that there are data plane applications deployed in such environments. Wouldn't this affect the performance terribly?

It wouldn't reach same performance as isolated threads, 
but for some tasks it might be enough. 
AFAIK, one quite common scenario - few isolated threads(/processes) doing
actual IO and then spread packets over dozens(/hundreds) non-isolated
consumers. 

> 
> >
> > IMO, The best solution would be keeping the ring API same and have a
> > different flavor in "compile-time". Something like liburcu did for
> > accommodating different flavors.
> >
> > i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The application
> > can simply include ONE header file in a C file based on the flavor.
> > If need both at runtime. Need to have function pointer or so in the application
> > and define the function in different c file by including the approaite flavor in C
> > file.
> >
> > #include <urcu-qsbr.h> /* QSBR RCU flavor */ #include <urcu-bp.h> /*
> > Bulletproof RCU flavor */

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: deprecate using MAX values as array size
      2020-02-25 13:52  0% ` David Marchand
@ 2020-02-25 14:53  0% ` David Marchand
  2 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-02-25 14:53 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Neil Horman, John McNamara, Marko Kovacevic, dev

On Thu, Jan 30, 2020 at 3:20 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> Adding the deprecation notice as reminder for next ABI breakage release
> (20.11).
> This one time breakage is required to be able to extend enum/define
> without breaking ABI.
>
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>

Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Andrew Rybchenko <arybchenko@solarflare.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
Acked-by: David Marchand <david.marchand@redhat.com>


Applied, thanks.

-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk-announce] release candidate 20.02-rc4
  2020-02-25 14:37  4%   ` Xu, Qian Q
@ 2020-02-25 14:44  0%     ` Thomas Monjalon
  2020-02-25 15:27  0%       ` Raslan Darawsheh
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-02-25 14:44 UTC (permalink / raw)
  To: Ali Alnubani, Xu, Qian Q, Raslan Darawsheh
  Cc: dev, Asaf Penso, Peng, Yuan, Yu, PingX

Can we assume we are OK to release today?


25/02/2020 15:37, Xu, Qian Q:
> Some quick update from Intel on RC4 testing
> 
> Summary
> 
> 1. Totally execution percentage is around 90%, pass rate is around 98%
> 2. Created 2 new medium/low issue in RC4.  
> 
> Details:
> 1. Intel NIC PMD PF & VF regression: 95% executed, 0 critical issue and high issue found. 
> Function cases include rx/tx/forward packets, packet processing, jumboframe, dual vlan, filter cases and so on: 2 bugs found, no critical/high bugs. 
> Performance cases such as l2fwd, l3fwd, single core and so on: no new bug is found.
> 2. Cryptodev cases include ipsec_gw cryptodev, fips cryptodev, l2fwd crypto, performance cases and so on: no critical and no high bugs found.
>  Function cases all passed, performance cases not fully executed. 
> 3. Vhost/virtio: PVP/loopback, qemu/virtio-user, multi-queue, dequeue zero copy cases and so on: 1 new medium bug is found.
> 4. Power relate cases, no new bug is found.
> 5. ABI test includes unit test, vhost and flow related tests.  no new bug is  found.
> 6. 20.02 new features include ABI test, L2tpv3,  crypto_dev related new features and so no.  no new bug is found. 
> 
> 
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Ali Alnubani
> > Sent: Tuesday, February 25, 2020 5:59 PM
> > To: Thomas Monjalon <thomas@monjalon.net>; dev@dpdk.org
> > Cc: Raslan Darawsheh <rasland@mellanox.com>; Asaf Penso
> > <asafp@mellanox.com>
> > Subject: Re: [dpdk-dev] [dpdk-announce] release candidate 20.02-rc4
> > 
> > Hi,
> > 
> > > -----Original Message-----
> > > From: announce <announce-bounces@dpdk.org> On Behalf Of Thomas
> > > Monjalon
> > > Sent: Saturday, February 22, 2020 11:08 PM
> > > To: announce@dpdk.org
> > > Subject: [dpdk-announce] release candidate 20.02-rc4
> > >
> > > A new DPDK release candidate is ready for testing:
> > <removed>
> > >
> > > This is the last release candidate for DPDK 20.02.
> > > Please share some release validation results by replying to this
> > > message (at dev@dpdk.org).
> > > If no critical issue is reported, 20.02 will be closed on Tuesday 25th.
> > >
> > > If you are preparing the next release cycle, please send your v1
> > > patches before the 20.05 proposal deadline, which will happen on March 18th.
> > > It is also time to build an estimated roadmap for the next cycles.
> > >
> > > Thank you everyone
> > >
> > 
> > The following covers the tests that we ran on Mellanox hardware for this
> > version:
> > 
> > - Basic functionality:
> >   Send and receive multiple types of traffic.
> > - testpmd xstats counter test.
> > - testpmd timestamp test.
> > - Changing/checking link status through testpmd.
> > - RTE flow and flow_director tests.
> >   Items: eth / vlan / ipv4 / ipv6 / tcp / udp / icmp / gre / nvgre / vxlan / geneve /
> > ip in ip / mplsoudp / mplsogre / gtp
> >   Actions: drop / queue / rss / mark / flag / jump / count / port_id / raw_encap /
> > raw_decap / vxlan_encap / vxlan_decap / NAT
> > - Some RSS tests.
> > - VLAN stripping and insertion tests.
> > - Checksum and TSO tests.
> > - ptype tests.
> > - l3fwd-power example application tests.
> > - Multi-process example applications tests.
> > 
> > We don't see any critical issues blocking the release.
> > 
> > Thanks,
> > Ali




^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk-announce] release candidate 20.02-rc4
  @ 2020-02-25 14:37  4%   ` Xu, Qian Q
  2020-02-25 14:44  0%     ` Thomas Monjalon
  0 siblings, 1 reply; 200+ results
From: Xu, Qian Q @ 2020-02-25 14:37 UTC (permalink / raw)
  To: Ali Alnubani, Thomas Monjalon, dev
  Cc: Raslan Darawsheh, Asaf Penso, Peng, Yuan, Yu, PingX

Some quick update from Intel on RC4 testing

Summary

1. Totally execution percentage is around 90%, pass rate is around 98%
2. Created 2 new medium/low issue in RC4.  

Details:
1. Intel NIC PMD PF & VF regression: 95% executed, 0 critical issue and high issue found. 
Function cases include rx/tx/forward packets, packet processing, jumboframe, dual vlan, filter cases and so on: 2 bugs found, no critical/high bugs. 
Performance cases such as l2fwd, l3fwd, single core and so on: no new bug is found.
2. Cryptodev cases include ipsec_gw cryptodev, fips cryptodev, l2fwd crypto, performance cases and so on: no critical and no high bugs found.
 Function cases all passed, performance cases not fully executed. 
3. Vhost/virtio: PVP/loopback, qemu/virtio-user, multi-queue, dequeue zero copy cases and so on: 1 new medium bug is found.
4. Power relate cases, no new bug is found.
5. ABI test includes unit test, vhost and flow related tests.  no new bug is  found.
6. 20.02 new features include ABI test, L2tpv3,  crypto_dev related new features and so no.  no new bug is found. 


> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Ali Alnubani
> Sent: Tuesday, February 25, 2020 5:59 PM
> To: Thomas Monjalon <thomas@monjalon.net>; dev@dpdk.org
> Cc: Raslan Darawsheh <rasland@mellanox.com>; Asaf Penso
> <asafp@mellanox.com>
> Subject: Re: [dpdk-dev] [dpdk-announce] release candidate 20.02-rc4
> 
> Hi,
> 
> > -----Original Message-----
> > From: announce <announce-bounces@dpdk.org> On Behalf Of Thomas
> > Monjalon
> > Sent: Saturday, February 22, 2020 11:08 PM
> > To: announce@dpdk.org
> > Subject: [dpdk-announce] release candidate 20.02-rc4
> >
> > A new DPDK release candidate is ready for testing:
> <removed>
> >
> > This is the last release candidate for DPDK 20.02.
> > Please share some release validation results by replying to this
> > message (at dev@dpdk.org).
> > If no critical issue is reported, 20.02 will be closed on Tuesday 25th.
> >
> > If you are preparing the next release cycle, please send your v1
> > patches before the 20.05 proposal deadline, which will happen on March 18th.
> > It is also time to build an estimated roadmap for the next cycles.
> >
> > Thank you everyone
> >
> 
> The following covers the tests that we ran on Mellanox hardware for this
> version:
> 
> - Basic functionality:
>   Send and receive multiple types of traffic.
> - testpmd xstats counter test.
> - testpmd timestamp test.
> - Changing/checking link status through testpmd.
> - RTE flow and flow_director tests.
>   Items: eth / vlan / ipv4 / ipv6 / tcp / udp / icmp / gre / nvgre / vxlan / geneve /
> ip in ip / mplsoudp / mplsogre / gtp
>   Actions: drop / queue / rss / mark / flag / jump / count / port_id / raw_encap /
> raw_decap / vxlan_encap / vxlan_decap / NAT
> - Some RSS tests.
> - VLAN stripping and insertion tests.
> - Checksum and TSO tests.
> - ptype tests.
> - l3fwd-power example application tests.
> - Multi-process example applications tests.
> 
> We don't see any critical issues blocking the release.
> 
> Thanks,
> Ali

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH v4] doc: alias to experimental tag for stable apis
    2020-02-21 17:11  0%   ` Ferruh Yigit
@ 2020-02-25 14:22  0%   ` Kevin Traynor
  1 sibling, 0 replies; 200+ results
From: Kevin Traynor @ 2020-02-25 14:22 UTC (permalink / raw)
  To: Ray Kinsella, dev
  Cc: john.mcnamara, nhorman, ferruh.yigit, marko.kovacevic, bruce.richardson

On 18/02/2020 10:46, Ray Kinsella wrote:
> When a maintainer is promoting an API to become part of the next major ABI
> version by removing the experimental tag, possibly a few releases in
> advance of the declaration of the next ABI version. The maintainer may
> choose to offer an alias to the experimental tag, as removing the tag
> before the declaration of the next major ABI version, would cause an ABI
> breakage for applications using the API.
> 
> Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
> ---
>  doc/guides/contributing/abi_policy.rst | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/doc/guides/contributing/abi_policy.rst b/doc/guides/contributing/abi_policy.rst
> index 05ca959..7ae7de7 100644
> --- a/doc/guides/contributing/abi_policy.rst
> +++ b/doc/guides/contributing/abi_policy.rst
> @@ -159,6 +159,11 @@ The requirements for changing the ABI are:
>       ``experimental``, as described in the section on :ref:`Experimental APIs
>       and Libraries <experimental_apis>`.
>  
> +   - In situations in which an ``experimental`` API has been stable for some
> +     time. When promoting the API to become part of the next ABI version, the
> +     maintainer may choose to provide an alias to the ``experimental`` tag, so
> +     as not to break consuming applications.
> +
>  #. If a newly proposed API functionally replaces an existing one, when the new
>     API becomes non-experimental, then the old one is marked with
>     ``__rte_deprecated``.
> @@ -317,6 +322,11 @@ not required. Though, an API should remain in experimental state for at least
>  one release. Thereafter, the normal process of posting patch for review to
>  mailing list can be followed.
>  
> +After the experimental tag has been formally removed, a tree/sub-tree maintainer
> +may choose to offer an alias to the experimental tag so as not to break
> +applications using the API. The alias is then dropped at the declaration of next
> +major ABI version.
> +
>  Libraries
>  ~~~~~~~~~
>  
> 

Sounds good. It doesn't change the minimum contract but gives some
flexibility to deal with individual cases.

Acked-by: Kevin Traynor <ktraynor@redhat.com>


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: deprecate using MAX values as array size
    @ 2020-02-25 13:52  0% ` David Marchand
  2020-02-25 14:53  0% ` David Marchand
  2 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-02-25 13:52 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Neil Horman, John McNamara, Marko Kovacevic, dev

On Thu, Jan 30, 2020 at 3:20 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> Adding the deprecation notice as reminder for next ABI breakage release
> (20.11).
> This one time breakage is required to be able to extend enum/define
> without breaking ABI.
>
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> ---
>  doc/guides/rel_notes/deprecation.rst | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
>
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index dfcca87ab..99d81564a 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -38,6 +38,20 @@ Deprecation Notices
>    remove it from the externally visible ABI and allow it to be updated in the
>    future.
>
> +* lib: will fix extending some enum/define breaking the ABI. There are multiple
> +  samples in DPDK that enum/define terminated with a ``.*MAX.*`` value which is
> +  used by iterators, and arrays holding these values are sized with this
> +  ``.*MAX.*`` value. So extending this enum/define increases the ``.*MAX.*``
> +  value which increases the size of the array and depending on how/where the
> +  array is used this may break the ABI.
> +  ``RTE_ETH_FLOW_MAX`` is one sample of the mentioned case, adding a new flow
> +  type will break the ABI because of ``flex_mask[RTE_ETH_FLOW_MAX]`` array
> +  usage in following public struct hierarchy:
> +  ``rte_eth_fdir_flex_conf -> rte_fdir_conf -> rte_eth_conf (in the middle)``.
> +  Need to identify this kind of usages and fix in 20.11, otherwise this blocks
> +  us extending existing enum/define.
> +  One solution can be using a fixed size array instead of ``.*MAX.*`` value.
> +
>  * dpaa2: removal of ``rte_dpaa2_memsegs`` structure which has been replaced
>    by a pa-va search library. This structure was earlier being used for holding
>    memory segments used by dpaa2 driver for faster pa->va translation. This
> --
> 2.24.1
>

Acked-by: David Marchand <david.marchand@redhat.com>


--
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 19:35  3%     ` Stephen Hemminger
  2020-02-24 20:52  0%       ` Honnappa Nagarahalli
@ 2020-02-25 13:41  3%       ` Ananyev, Konstantin
  2020-02-27 10:31  0%         ` Jerin Jacob
  1 sibling, 1 reply; 200+ results
From: Ananyev, Konstantin @ 2020-02-25 13:41 UTC (permalink / raw)
  To: Stephen Hemminger, Jerin Jacob; +Cc: dpdk-dev, Olivier Matz, drc

> > > > Upfront note - that RFC is not a complete patch.
> > > > It introduces an ABI breakage, plus it doesn't update ring_elem
> > > > code properly, etc.
> > > > I plan to deal with all these things in later versions.
> > > > Right now I seek an initial feedback about proposed ideas.
> > > > Would also ask people to repeat performance tests (see below)
> > > > on their platforms to confirm the impact.
> > > >
> > > > More and more customers use(/try to use) DPDK based apps within
> > > > overcommitted systems (multiple acttive threads over same pysical cores):
> > > > VM, container deployments, etc.
> > > > One quite common problem they hit: Lock-Holder-Preemption with rte_ring.
> > > > LHP is quite a common problem for spin-based sync primitives
> > > > (spin-locks, etc.) on overcommitted systems.
> > > > The situation gets much worse when some sort of
> > > > fair-locking technique is used (ticket-lock, etc.).
> > > > As now not only lock-owner but also lock-waiters scheduling
> > > > order matters a lot.
> > > > This is a well-known problem for kernel within VMs:
> > > > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > > > The problem with rte_ring is that while head accusion is sort of
> > > > un-fair locking, waiting on tail is very similar to ticket lock schema -
> > > > tail has to be updated in particular order.
> > > > That makes current rte_ring implementation to perform
> > > > really pure on some overcommited scenarios.
> > >
> > > Rather than reform rte_ring to fit this scenario, it would make
> > > more sense to me to introduce another primitive. 

I don't see much advantages it will bring us.
As a disadvantages, for developers and maintainers - code duplication,
for end users - extra code churn and removed ability to mix and match
different sync modes in one ring.

> The current lockless
> > > ring performs very well for the isolated thread model that DPDK
> > > was built around. This looks like a case of customers violating
> > > the usage model of the DPDK and then being surprised at the fallout.

For customers using isolated thread model - nothing should change
(both in terms of API and performance).
Existing sync modes MP/MC,SP/SC kept untouched, set up in the same
way (via flags and _init_), and MP/MC remains as default one.
From other side I don't see why we should ignore customers that want to use
their DPDK apps in different deployment scenarios.

> >
> > I agree with Stephen here.
> >
> > I think, adding more runtime check in the enqueue() and dequeue() will
> > have a bad effect on the low-end cores too.

We do have a run-time check in our current enqueue()/dequeue implementation.
In fact we support both modes: we have generic rte_ring_enqueue(/dequeue)_bulk(/burst)
where sync behaviour is determined at runtime by value of prod(/cons).single.
Or user can call  rte_ring_(mp/sp)_enqueue_* functions directly.
This RFC follows exactly the same paradigm:
rte_ring_enqueue(/dequeue)_bulk(/burst) kept generic and it's
behaviour is determined at runtime, by value of prod(/cons).sync_type.
Or user can call enqueue/dequeue with particular sync mode directly:
rte_ring_(mp/sp/rts/hts)_enqueue_(bulk/burst)*.
The only thing that changed:
 Format of prod/cons now could differ depending on mode selected at _init_.
 So you can't create a ring for let say SP mode and then in the middle of data-path
 change your mind and start using MP_RTS mode.
 For existing modes (SP/MP, SC/MC)  format remains the same and user can still
 use them interchangeably, though of course that is an error prone practice.   

> > But I agree with the problem statement that in the virtualization use
> > case, It may be possible to have N virtual cores runs on a physical
> > core.
> >
> > IMO, The best solution would be keeping the ring API same and have a
> > different flavor in "compile-time". Something like
> > liburcu did for accommodating different flavors.
> >
> > i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The
> > application can simply include ONE header file in a C file based on
> > the flavor.

I don't think it is a flexible enough approach.
In one app user might need to have several rings with different sync modes.
Or even user might need a ring with different sync modes for enqueue/dequeue.

> > If need both at runtime. Need to have function pointer or so in the
> > application and define the function in different c file by including
> > the approaite flavor in C file.

Big issue with function pointers here would be DPDK MP model.
AFAIK,  rte_ring is quite popular mechanism for IPC between DPDK apps.
To support such model, we'll need to split rte_ring data into 'shared'
and 'private' and initialize private one for every process that is going to use it.
That sounds like a massive change, and I am not sure the required effort will worth it. 
BTW, if user just calls API functions without trying to access structure internals directly,
I don't think it would be a big difference for him what is inside:
indirect function call or inlined switch(...) {}.  

> This would also be a good time to consider the tradeoffs of the
> heavy use of inlining that is done in rte_ring vs the impact that
> has on API/ABI stability.

Yes, hiding rte_ring implementation inside .c would help a lot
in terms of ABI maintenance and would make our future life easier.
The question is what is the price for it in terms of performance,
and are we ready to pay it. Not to mention that it would cause
changes in many other libs/apps...
So I think it should be a subject for a separate discussion.
But, agree it would be good at least to measure the performance
impact of such change.
If I'll have some spare cycles, will give it a try.
Meanwhile, can I ask Jerin and other guys to repeat tests from this RFC
on their HW? Before continuing discussion would probably be good to know
does the suggested patch work as expected across different platforms.
Thanks
Konstantin   

^ permalink raw reply	[relevance 3%]

* [dpdk-dev] [PATCH v2] doc: plan splitting the ethdev ops struct
      @ 2020-02-25 12:44  3% ` Ferruh Yigit
  2020-02-25 15:51  3%   ` Andrew Rybchenko
                     ` (2 more replies)
  2 siblings, 3 replies; 200+ results
From: Ferruh Yigit @ 2020-02-25 12:44 UTC (permalink / raw)
  To: Neil Horman, John McNamara, Marko Kovacevic
  Cc: dev, Ferruh Yigit, Jerin Jacob, David Marchand, Thomas Monjalon,
	Andrew Rybchenko

For the ABI compatibility it is better to hide internal data structures
from the application as much as possible. But because of some inline
functions 'struct eth_dev_ops' can't be hidden completely.

Plan is to split the 'struct eth_dev_ops' into two as ones used by
inline functions and ones not used, and hide the second part that not
used by inline functions completely to the application.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
---
Cc: David Marchand <david.marchand@redhat.com>
Cc: Thomas Monjalon <thomas@monjalon.net>
Cc: Andrew Rybchenko <arybchenko@solarflare.com>

v2:
* Add target date for the work
* Give more detail on what will be done
---
 doc/guides/rel_notes/deprecation.rst | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 99d81564a..ff612a615 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -86,6 +86,17 @@ Deprecation Notices
   In 19.11 PMDs will still update the field even when the offload is not
   enabled.
 
+* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
+  Currently the ``struct eth_dev_ops`` struct is accessible by the application
+  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
+  access the struct directly. The struct will be separate in two, the ops used
+  by inline functions still will be accessible to user but rest will be hidden.
+  Initial split will be done in 20.05 with adding reserved fields for the struct
+  used by inline functions, and by putting new struct reference into public one
+  to not increase the size of ``struct rte_eth_dev``, proper split will be done
+  in 20.11 by moving inline dev_ops function to next to Rx/Tx burst functions and
+  hiding rest.
+
 * cryptodev: support for using IV with all sizes is added, J0 still can
   be used but only when IV length in following structs ``rte_crypto_auth_xform``,
   ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
-- 
2.24.1


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] doc: plan splitting the ethdev ops struct
  @ 2020-02-25 12:42  0%   ` Ferruh Yigit
  0 siblings, 0 replies; 200+ results
From: Ferruh Yigit @ 2020-02-25 12:42 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: Neil Horman, John McNamara, Marko Kovacevic, dpdk-dev,
	David Marchand, Thomas Monjalon, Andrew Rybchenko

On 2/18/2020 5:07 AM, Jerin Jacob wrote:
> On Mon, Feb 17, 2020 at 9:08 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>
>> For the ABI compatibility it is better to hide internal data structures
>> from the application as much as possible. But because of some inline
>> functions 'struct eth_dev_ops' can't be hidden completely.
>>
>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
>> inline functions and ones not used, and hide the second part that not
>> used by inline functions completely to the application.
> 
> It is a good improvement.  IMO, If anything used in fast-path it
> should be in ``struct rte_eth_dev``
> and rest can completely be moved to internal. In this case, if
> `rte_eth_tx_descriptor_status`
> not used on fastpath, Maybe we don't need to maintain the inline
> status and move completely
> to .c file.

Moving fast-past dev_ops to ``struct rte_eth_dev`` makes sense, also suggested
by Andrew, and will hide the rest.

Those inline dev_ops are datapath related so may be better to keep them as
inline, but not really sure about their users and how much they care about minor
performance impact if we chose to convert them into regular functions.

> 
> Those may be specifics of the work. In general, this change looks good to me.
> 
> Acked-by: Jerin Jacob <jerinj@marvell.com>
> 
> 
> 
> 
> 
>>
>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>> ---
>> Cc: David Marchand <david.marchand@redhat.com>
>> Cc: Thomas Monjalon <thomas@monjalon.net>
>> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
>> ---
>>  doc/guides/rel_notes/deprecation.rst | 6 ++++++
>>  1 file changed, 6 insertions(+)
>>
>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>> index dfcca87ab..2aa431028 100644
>> --- a/doc/guides/rel_notes/deprecation.rst
>> +++ b/doc/guides/rel_notes/deprecation.rst
>> @@ -72,6 +72,12 @@ Deprecation Notices
>>    In 19.11 PMDs will still update the field even when the offload is not
>>    enabled.
>>
>> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
>> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
>> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
>> +  access the struct directly. The struct will be separate in two, the ops used
>> +  by inline functions still will be accessible to user but rest will be hidden.
>> +
>>  * cryptodev: support for using IV with all sizes is added, J0 still can
>>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
>>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
>> --
>> 2.24.1
>>


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: plan splitting the ethdev ops struct
  2020-02-25 10:35  0%     ` Andrew Rybchenko
  2020-02-25 11:07  3%       ` Ananyev, Konstantin
@ 2020-02-25 12:28  3%       ` Ferruh Yigit
  1 sibling, 0 replies; 200+ results
From: Ferruh Yigit @ 2020-02-25 12:28 UTC (permalink / raw)
  To: Andrew Rybchenko, Stephen Hemminger
  Cc: Neil Horman, John McNamara, Marko Kovacevic, dev, David Marchand,
	Thomas Monjalon, Kinsella, Ray, Olivier MATZ

On 2/25/2020 10:35 AM, Andrew Rybchenko wrote:
> On 2/21/20 1:40 PM, Ferruh Yigit wrote:
>> On 2/18/2020 6:01 AM, Stephen Hemminger wrote:
>>> On Mon, 17 Feb 2020 15:38:05 +0000
>>> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>>
>>>> For the ABI compatibility it is better to hide internal data structures
>>>> from the application as much as possible. But because of some inline
>>>> functions 'struct eth_dev_ops' can't be hidden completely.
>>>>
>>>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
>>>> inline functions and ones not used, and hide the second part that not
>>>> used by inline functions completely to the application.
>>>>
>>>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>>>> ---
>>>> Cc: David Marchand <david.marchand@redhat.com>
>>>> Cc: Thomas Monjalon <thomas@monjalon.net>
>>>> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
>>>> ---
>>>>  doc/guides/rel_notes/deprecation.rst | 6 ++++++
>>>>  1 file changed, 6 insertions(+)
>>>>
>>>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>>>> index dfcca87ab..2aa431028 100644
>>>> --- a/doc/guides/rel_notes/deprecation.rst
>>>> +++ b/doc/guides/rel_notes/deprecation.rst
>>>> @@ -72,6 +72,12 @@ Deprecation Notices
>>>>    In 19.11 PMDs will still update the field even when the offload is not
>>>>    enabled.
>>>>  
>>>> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
>>>> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
>>>> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
>>>> +  access the struct directly. The struct will be separate in two, the ops used
>>>> +  by inline functions still will be accessible to user but rest will be hidden.
>>>> +
>>>>  * cryptodev: support for using IV with all sizes is added, J0 still can
>>>>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
>>>>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
>>>
>>> Good luck, truely hiding internals is hard. The mbuf structure is already split but not really
>>> hidden at all (just look at dwarf output). It doesn't make sense to do it unless
>>> you can really hide it.
>>
>> I believe this can be done, only following [1] dev_ops are used by inline
>> functions, rest can be moved into separate struct and moved into ethdev driver
>> looking header.
>>
>> [1]
>> rx_queue_count
>> rx_descriptor_done
>> rx_descriptor_status
>> tx_descriptor_status
> 
> I think having 3 places (if I understand the intention
> correctly) with ethdev callbacks is too much. 

Yes, this is the intention.

> So, I think
> that these ops should be simply moved to nearby Tx/Rx
> burst and Tx prepare callbacks (e.g. move into inline_ops
> structure which is located at the beginning of rte_eth_dev
> in order to preserve 3 existing callback location).

I think this is reasonable, but this can be done only in 20.11 with ABI break.

What do you think doing the initial hide in 20.05 with three places and do
proper splitting in 20.11 as suggested above.

Or it is possible to drop the interim work and do the all changes in 20.11, not
sure.


> 
> Also I'd consider to deprecate and remove rx_queue_count
> and rx_descriptor_done.

+1 to deprecate the 'rx_descriptor_done', we have already 'rx_descriptor_status'
& 'tx_descriptor_status' to replace the functionality.

@Thomas, @Ray, can you please remind how deprecation was done, is it marking
API, 'rte_eth_rx_descriptor_done', as deprecated in 20.11 and removing it in
21.11? If so I guess deprecation notice should be send before 20.11? (And make
sure all PMDs did the switch before 20.11)


Not sure about 'rx_queue_count', if any application may need it or not.

> 
>>>
>>> I would attack the rte_device stuff first. Make rte_device opaque to the application
>>> that would help for future versions. Then work backwards to rte_tehtdev.
>>>
> 


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 20:52  0%       ` Honnappa Nagarahalli
@ 2020-02-25 11:45  0%         ` Ananyev, Konstantin
  0 siblings, 0 replies; 200+ results
From: Ananyev, Konstantin @ 2020-02-25 11:45 UTC (permalink / raw)
  To: Honnappa Nagarahalli, Stephen Hemminger, Jerin Jacob
  Cc: dpdk-dev, Olivier Matz, nd, nd


> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Stephen Hemminger
> > Sent: Monday, February 24, 2020 1:35 PM
> > To: Jerin Jacob <jerinjacobk@gmail.com>
> > Cc: Konstantin Ananyev <konstantin.ananyev@intel.com>; dpdk-dev
> > <dev@dpdk.org>; Olivier Matz <olivier.matz@6wind.com>
> > Subject: Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
> >
> > On Mon, 24 Feb 2020 23:29:57 +0530
> > Jerin Jacob <jerinjacobk@gmail.com> wrote:
> >
> > > On Mon, Feb 24, 2020 at 10:29 PM Stephen Hemminger
> > > <stephen@networkplumber.org> wrote:
> > > >
> > > > On Mon, 24 Feb 2020 11:35:09 +0000
> > > > Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:
> > > >
> > > > > Upfront note - that RFC is not a complete patch.
> > > > > It introduces an ABI breakage, plus it doesn't update ring_elem
> > > > > code properly, etc.
> > > > > I plan to deal with all these things in later versions.
> > > > > Right now I seek an initial feedback about proposed ideas.
> > > > > Would also ask people to repeat performance tests (see below) on
> > > > > their platforms to confirm the impact.
> > > > >
> > > > > More and more customers use(/try to use) DPDK based apps within
> > > > > overcommitted systems (multiple acttive threads over same pysical
> > cores):
> > > > > VM, container deployments, etc.
> > > > > One quite common problem they hit: Lock-Holder-Preemption with
> > rte_ring.
> > > > > LHP is quite a common problem for spin-based sync primitives
> > > > > (spin-locks, etc.) on overcommitted systems.
> > > > > The situation gets much worse when some sort of fair-locking
> > > > > technique is used (ticket-lock, etc.).
> > > > > As now not only lock-owner but also lock-waiters scheduling order
> > > > > matters a lot.
> > > > > This is a well-known problem for kernel within VMs:
> > > > > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > > > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > > > > The problem with rte_ring is that while head accusion is sort of
> > > > > un-fair locking, waiting on tail is very similar to ticket lock
> > > > > schema - tail has to be updated in particular order.
> > > > > That makes current rte_ring implementation to perform really pure
> > > > > on some overcommited scenarios.
> > > >
> > > > Rather than reform rte_ring to fit this scenario, it would make more
> > > > sense to me to introduce another primitive. The current lockless
> > > > ring performs very well for the isolated thread model that DPDK was
> > > > built around. This looks like a case of customers violating the
> > > > usage model of the DPDK and then being surprised at the fallout.
> > >
> > > I agree with Stephen here.
> > >
> > > I think, adding more runtime check in the enqueue() and dequeue() will
> > > have a bad effect on the low-end cores too.
> > > But I agree with the problem statement that in the virtualization use
> > > case, It may be possible to have N virtual cores runs on a physical
> > > core.
> > >
> > > IMO, The best solution would be keeping the ring API same and have a
> > > different flavor in "compile-time". Something like liburcu did for
> > > accommodating different flavors.
> > >
> > > i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The
> > > application can simply include ONE header file in a C file based on
> > > the flavor.
> > > If need both at runtime. Need to have function pointer or so in the
> > > application and define the function in different c file by including
> > > the approaite flavor in C file.
> >
> > This would also be a good time to consider the tradeoffs of the heavy use of
> > inlining that is done in rte_ring vs the impact that has on API/ABI stability.
> >
> I was working on few requirements in rte_ring library for RCU defer APIs. RFC is at https://patchwork.dpdk.org/cover/66020/.

Yep, noticed your patch, seems we sort of collided here.
As I understand you patch aims to provide functionality similar to my HTS one.
Will try to look at yours one in next fee days, hopefully we can end-up with
some common denominator.
Konstantin




^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: plan splitting the ethdev ops struct
  2020-02-25 11:07  3%       ` Ananyev, Konstantin
@ 2020-02-25 11:19  0%         ` Andrew Rybchenko
  0 siblings, 0 replies; 200+ results
From: Andrew Rybchenko @ 2020-02-25 11:19 UTC (permalink / raw)
  To: Ananyev, Konstantin, Yigit, Ferruh, Stephen Hemminger
  Cc: Neil Horman, Mcnamara, John, Kovacevic, Marko, dev,
	David Marchand, Thomas Monjalon

Hi Konstantin,

On 2/25/20 2:07 PM, Ananyev, Konstantin wrote:
> Hi Andew, 
>
>> On 2/21/20 1:40 PM, Ferruh Yigit wrote:
>>> On 2/18/2020 6:01 AM, Stephen Hemminger wrote:
>>>> On Mon, 17 Feb 2020 15:38:05 +0000
>>>> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>>>
>>>>> For the ABI compatibility it is better to hide internal data structures
>>>>> from the application as much as possible. But because of some inline
>>>>> functions 'struct eth_dev_ops' can't be hidden completely.
>>>>>
>>>>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
>>>>> inline functions and ones not used, and hide the second part that not
>>>>> used by inline functions completely to the application.
>>>>>
>>>>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>>>>> ---
>>>>> Cc: David Marchand <david.marchand@redhat.com>
>>>>> Cc: Thomas Monjalon <thomas@monjalon.net>
>>>>> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
>>>>> ---
>>>>>  doc/guides/rel_notes/deprecation.rst | 6 ++++++
>>>>>  1 file changed, 6 insertions(+)
>>>>>
>>>>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>>>>> index dfcca87ab..2aa431028 100644
>>>>> --- a/doc/guides/rel_notes/deprecation.rst
>>>>> +++ b/doc/guides/rel_notes/deprecation.rst
>>>>> @@ -72,6 +72,12 @@ Deprecation Notices
>>>>>    In 19.11 PMDs will still update the field even when the offload is not
>>>>>    enabled.
>>>>>
>>>>> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
>>>>> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
>>>>> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
>>>>> +  access the struct directly. The struct will be separate in two, the ops used
>>>>> +  by inline functions still will be accessible to user but rest will be hidden.
>>>>> +
>>>>>  * cryptodev: support for using IV with all sizes is added, J0 still can
>>>>>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
>>>>>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
>>>> Good luck, truely hiding internals is hard. The mbuf structure is already split but not really
>>>> hidden at all (just look at dwarf output). It doesn't make sense to do it unless
>>>> you can really hide it.
>>> I believe this can be done, only following [1] dev_ops are used by inline
>>> functions, rest can be moved into separate struct and moved into ethdev driver
>>> looking header.
>>>
>>> [1]
>>> rx_queue_count
>>> rx_descriptor_done
>>> rx_descriptor_status
>>> tx_descriptor_status
>> I think having 3 places (if I understand the intention
>> correctly) with ethdev callbacks is too much. So, I think
>> that these ops should be simply moved to nearby Tx/Rx
>> burst and Tx prepare callbacks (e.g. move into inline_ops
>> structure which is located at the beginning of rte_eth_dev
>> in order to preserve 3 existing callback location).
> If you are going to change ABI anyway,  would it be worth to consider 
> moving rx/tx burst/prepare functions to be per queue,
> instead of per device? 

I'm thinking about it from time to time. In general I like the idea.
The only question I have if there is a demand for queues with
different offloads which could result in different Rx/Tx callbacks.
Also I'm not sure that it is doable without performance degradation
at all, but hopefully it will be tiny.

>> Also I'd consider to deprecate and remove rx_queue_count
>> and rx_descriptor_done.
>>
>>>> I would attack the rte_device stuff first. Make rte_device opaque to the application
>>>> that would help for future versions. Then work backwards to rte_tehtdev.
>>>>


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: plan splitting the ethdev ops struct
  2020-02-25 10:35  0%     ` Andrew Rybchenko
@ 2020-02-25 11:07  3%       ` Ananyev, Konstantin
  2020-02-25 11:19  0%         ` Andrew Rybchenko
  2020-02-25 12:28  3%       ` Ferruh Yigit
  1 sibling, 1 reply; 200+ results
From: Ananyev, Konstantin @ 2020-02-25 11:07 UTC (permalink / raw)
  To: Andrew Rybchenko, Yigit, Ferruh, Stephen Hemminger
  Cc: Neil Horman, Mcnamara, John, Kovacevic, Marko, dev,
	David Marchand, Thomas Monjalon


Hi Andew, 

> On 2/21/20 1:40 PM, Ferruh Yigit wrote:
> > On 2/18/2020 6:01 AM, Stephen Hemminger wrote:
> >> On Mon, 17 Feb 2020 15:38:05 +0000
> >> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> >>
> >>> For the ABI compatibility it is better to hide internal data structures
> >>> from the application as much as possible. But because of some inline
> >>> functions 'struct eth_dev_ops' can't be hidden completely.
> >>>
> >>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
> >>> inline functions and ones not used, and hide the second part that not
> >>> used by inline functions completely to the application.
> >>>
> >>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> >>> ---
> >>> Cc: David Marchand <david.marchand@redhat.com>
> >>> Cc: Thomas Monjalon <thomas@monjalon.net>
> >>> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
> >>> ---
> >>>  doc/guides/rel_notes/deprecation.rst | 6 ++++++
> >>>  1 file changed, 6 insertions(+)
> >>>
> >>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> >>> index dfcca87ab..2aa431028 100644
> >>> --- a/doc/guides/rel_notes/deprecation.rst
> >>> +++ b/doc/guides/rel_notes/deprecation.rst
> >>> @@ -72,6 +72,12 @@ Deprecation Notices
> >>>    In 19.11 PMDs will still update the field even when the offload is not
> >>>    enabled.
> >>>
> >>> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
> >>> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
> >>> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
> >>> +  access the struct directly. The struct will be separate in two, the ops used
> >>> +  by inline functions still will be accessible to user but rest will be hidden.
> >>> +
> >>>  * cryptodev: support for using IV with all sizes is added, J0 still can
> >>>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
> >>>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
> >>
> >> Good luck, truely hiding internals is hard. The mbuf structure is already split but not really
> >> hidden at all (just look at dwarf output). It doesn't make sense to do it unless
> >> you can really hide it.
> >
> > I believe this can be done, only following [1] dev_ops are used by inline
> > functions, rest can be moved into separate struct and moved into ethdev driver
> > looking header.
> >
> > [1]
> > rx_queue_count
> > rx_descriptor_done
> > rx_descriptor_status
> > tx_descriptor_status
> 
> I think having 3 places (if I understand the intention
> correctly) with ethdev callbacks is too much. So, I think
> that these ops should be simply moved to nearby Tx/Rx
> burst and Tx prepare callbacks (e.g. move into inline_ops
> structure which is located at the beginning of rte_eth_dev
> in order to preserve 3 existing callback location).

If you are going to change ABI anyway,  would it be worth to consider 
moving rx/tx burst/prepare functions to be per queue,
instead of per device? 

> 
> Also I'd consider to deprecate and remove rx_queue_count
> and rx_descriptor_done.
> 
> >>
> >> I would attack the rte_device stuff first. Make rte_device opaque to the application
> >> that would help for future versions. Then work backwards to rte_tehtdev.
> >>


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] doc: deprecate using MAX values as array size
  2020-02-24  6:18  0%   ` Akhil Goyal
@ 2020-02-25 11:03  0%     ` Thomas Monjalon
  0 siblings, 0 replies; 200+ results
From: Thomas Monjalon @ 2020-02-25 11:03 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Neil Horman, John McNamara, Marko Kovacevic, dev,
	Bruce Richardson, Konstantin Ananyev, David Marchand,
	Andrew Rybchenko, Ori Kam, Akhil Goyal

> > > Adding the deprecation notice as reminder for next ABI breakage release
> > > (20.11).
> > > This one time breakage is required to be able to extend enum/define
> > > without breaking ABI.
> > >
> > > Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> > > ---
> > > +* lib: will fix extending some enum/define breaking the ABI. There are
> > multiple
> > > +  samples in DPDK that enum/define terminated with a ``.*MAX.*`` value
> > which is
> > > +  used by iterators, and arrays holding these values are sized with this
> > > +  ``.*MAX.*`` value. So extending this enum/define increases the ``.*MAX.*``
> > > +  value which increases the size of the array and depending on how/where the
> > > +  array is used this may break the ABI.
> > > +  ``RTE_ETH_FLOW_MAX`` is one sample of the mentioned case, adding a
> > new flow
> > > +  type will break the ABI because of ``flex_mask[RTE_ETH_FLOW_MAX]``
> > array
> > > +  usage in following public struct hierarchy:
> > > +  ``rte_eth_fdir_flex_conf -> rte_fdir_conf -> rte_eth_conf (in the middle)``.
> > > +  Need to identify this kind of usages and fix in 20.11, otherwise this blocks
> > > +  us extending existing enum/define.
> > > +  One solution can be using a fixed size array instead of ``.*MAX.*`` value.
> > 
> We admit that the issue is there and we can discuss the possible solutions for this issue.
> 
> For the deprecation notice.
> Acked-by: Akhil Goyal <akhil.goyal@nxp.com>

I think we'll need a new coding style guideline to avoid shuch issue in future.
Anyway, about fixing the issue in 20.11,
Acked-by: Thomas Monjalon <thomas@monjalon.net>



^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: plan splitting the ethdev ops struct
  @ 2020-02-25 10:35  0%     ` Andrew Rybchenko
  2020-02-25 11:07  3%       ` Ananyev, Konstantin
  2020-02-25 12:28  3%       ` Ferruh Yigit
  0 siblings, 2 replies; 200+ results
From: Andrew Rybchenko @ 2020-02-25 10:35 UTC (permalink / raw)
  To: Ferruh Yigit, Stephen Hemminger
  Cc: Neil Horman, John McNamara, Marko Kovacevic, dev, David Marchand,
	Thomas Monjalon

On 2/21/20 1:40 PM, Ferruh Yigit wrote:
> On 2/18/2020 6:01 AM, Stephen Hemminger wrote:
>> On Mon, 17 Feb 2020 15:38:05 +0000
>> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>>
>>> For the ABI compatibility it is better to hide internal data structures
>>> from the application as much as possible. But because of some inline
>>> functions 'struct eth_dev_ops' can't be hidden completely.
>>>
>>> Plan is to split the 'struct eth_dev_ops' into two as ones used by
>>> inline functions and ones not used, and hide the second part that not
>>> used by inline functions completely to the application.
>>>
>>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>>> ---
>>> Cc: David Marchand <david.marchand@redhat.com>
>>> Cc: Thomas Monjalon <thomas@monjalon.net>
>>> Cc: Andrew Rybchenko <arybchenko@solarflare.com>
>>> ---
>>>  doc/guides/rel_notes/deprecation.rst | 6 ++++++
>>>  1 file changed, 6 insertions(+)
>>>
>>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>>> index dfcca87ab..2aa431028 100644
>>> --- a/doc/guides/rel_notes/deprecation.rst
>>> +++ b/doc/guides/rel_notes/deprecation.rst
>>> @@ -72,6 +72,12 @@ Deprecation Notices
>>>    In 19.11 PMDs will still update the field even when the offload is not
>>>    enabled.
>>>  
>>> +* ethdev: Split the ``struct eth_dev_ops`` struct to hide it as much as possible.
>>> +  Currently the ``struct eth_dev_ops`` struct is accessible by the application
>>> +  because some inline functions, like ``rte_eth_tx_descriptor_status()``,
>>> +  access the struct directly. The struct will be separate in two, the ops used
>>> +  by inline functions still will be accessible to user but rest will be hidden.
>>> +
>>>  * cryptodev: support for using IV with all sizes is added, J0 still can
>>>    be used but only when IV length in following structs ``rte_crypto_auth_xform``,
>>>    ``rte_crypto_aead_xform`` is set to zero. When IV length is greater or equal
>>
>> Good luck, truely hiding internals is hard. The mbuf structure is already split but not really
>> hidden at all (just look at dwarf output). It doesn't make sense to do it unless
>> you can really hide it.
> 
> I believe this can be done, only following [1] dev_ops are used by inline
> functions, rest can be moved into separate struct and moved into ethdev driver
> looking header.
> 
> [1]
> rx_queue_count
> rx_descriptor_done
> rx_descriptor_status
> tx_descriptor_status

I think having 3 places (if I understand the intention
correctly) with ethdev callbacks is too much. So, I think
that these ops should be simply moved to nearby Tx/Rx
burst and Tx prepare callbacks (e.g. move into inline_ops
structure which is located at the beginning of rte_eth_dev
in order to preserve 3 existing callback location).

Also I'd consider to deprecate and remove rx_queue_count
and rx_descriptor_done.

>>
>> I would attack the rte_device stuff first. Make rte_device opaque to the application
>> that would help for future versions. Then work backwards to rte_tehtdev.
>>


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH v2 0/7] vfio/pci: SR-IOV support
  @ 2020-02-25  2:33  0% ` Tian, Kevin
  2020-03-05 17:33  3%   ` Alex Williamson
  2020-03-05  6:38  0% ` Vamsi Krishna Attunuru
  1 sibling, 1 reply; 200+ results
From: Tian, Kevin @ 2020-02-25  2:33 UTC (permalink / raw)
  To: Alex Williamson, kvm
  Cc: linux-pci, linux-kernel, dev, mtosatti, thomas, bluca,
	jerinjacobk, Richardson, Bruce, cohuck, Jason Wang

> From: Alex Williamson
> Sent: Thursday, February 20, 2020 2:54 AM
> 
> Changes since v1 are primarily to patch 3/7 where the commit log is
> rewritten, along with option parsing and failure logging based on
> upstream discussions.  The primary user visible difference is that
> option parsing is now much more strict.  If a vf_token option is
> provided that cannot be used, we generate an error.  As a result of
> this, opening a PF with a vf_token option will serve as a mechanism of
> setting the vf_token.  This seems like a more user friendly API than
> the alternative of sometimes requiring the option (VFs in use) and
> sometimes rejecting it, and upholds our desire that the option is
> always either used or rejected.
> 
> This also means that the VFIO_DEVICE_FEATURE ioctl is not the only
> means of setting the VF token, which might call into question whether
> we absolutely need this new ioctl.  Currently I'm keeping it because I
> can imagine use cases, for example if a hypervisor were to support
> SR-IOV, the PF device might be opened without consideration for a VF
> token and we'd require the hypservisor to close and re-open the PF in
> order to set a known VF token, which is impractical.
> 
> Series overview (same as provided with v1):

Thanks for doing this! 

> 
> The synopsis of this series is that we have an ongoing desire to drive
> PCIe SR-IOV PFs from userspace with VFIO.  There's an immediate need
> for this with DPDK drivers and potentially interesting future use

Can you provide a link to the DPDK discussion? 

> cases in virtualization.  We've been reluctant to add this support
> previously due to the dependency and trust relationship between the
> VF device and PF driver.  Minimally the PF driver can induce a denial
> of service to the VF, but depending on the specific implementation,
> the PF driver might also be responsible for moving data between VFs
> or have direct access to the state of the VF, including data or state
> otherwise private to the VF or VF driver.

Just a loud thinking. While the motivation of VF token sounds reasonable
to me, I'm curious why the same concern is not raised in other usages.
For example, there is no such design in virtio framework, where the
virtio device could also be restarted, putting in separate process (vhost-user),
and even in separate VM (virtio-vhost-user), etc. Of course the para-
virtualized attribute of virtio implies some degree of trust, but as you
mentioned many SR-IOV implementations support VF->PF communication
which also implies some level of trust. It's perfectly fine if VFIO just tries
to do better than other sub-systems, but knowing how other people
tackle the similar problem may make the whole picture clearer. 😊

+Jason.

> 
> To help resolve these concerns, we introduce a VF token into the VFIO
> PCI ABI, which acts as a shared secret key between drivers.  The
> userspace PF driver is required to set the VF token to a known value
> and userspace VF drivers are required to provide the token to access
> the VF device.  If a PF driver is restarted with VF drivers in use, it
> must also provide the current token in order to prevent a rogue
> untrusted PF driver from replacing a known driver.  The degree to
> which this new token is considered secret is left to the userspace
> drivers, the kernel intentionally provides no means to retrieve the
> current token.

I'm wondering whether the token idea can be used beyond SR-IOV, e.g.
(1) we may allow vfio user space to manage Scalable IOV in the future,
which faces the similar challenge between the PF and mdev; (2) the
token might be used as a canonical way to replace off-tree acs-override
workaround, say, allowing the admin to assign devices within the 
same iommu group to different VMs which trust each other. I'm not
sure how much complexity will be further introduced, but it's greatly
appreciated if you can help think a bit and if feasible abstract some 
logic in vfio core layer for such potential usages...

> 
> Note that the above token is only required for this new model where
> both the PF and VF devices are usable through vfio-pci.  Existing
> models of VFIO drivers where the PF is used without SR-IOV enabled
> or the VF is bound to a userspace driver with an in-kernel, host PF
> driver are unaffected.
> 
> The latter configuration above also highlights a new inverted scenario
> that is now possible, a userspace PF driver with in-kernel VF drivers.
> I believe this is a scenario that should be allowed, but should not be
> enabled by default.  This series includes code to set a default
> driver_override for VFs sourced from a vfio-pci user owned PF, such
> that the VFs are also bound to vfio-pci.  This model is compatible
> with tools like driverctl and allows the system administrator to
> decide if other bindings should be enabled.  The VF token interface
> above exists only between vfio-pci PF and VF drivers, once a VF is
> bound to another driver, the administrator has effectively pronounced
> the device as trusted.  The vfio-pci driver will note alternate
> binding in dmesg for logging and debugging purposes.
> 
> Please review, comment, and test.  The example QEMU implementation
> provided with the RFC is still current for this version.  Thanks,
> 
> Alex
> 
> RFC:
> https://lore.kernel.org/lkml/158085337582.9445.17682266437583505502.stg
> it@gimli.home/
> v1:
> https://lore.kernel.org/lkml/158145472604.16827.15751375540102298130.st
> git@gimli.home/
> 
> ---
> 
> Alex Williamson (7):
>       vfio: Include optional device match in vfio_device_ops callbacks
>       vfio/pci: Implement match ops
>       vfio/pci: Introduce VF token
>       vfio: Introduce VFIO_DEVICE_FEATURE ioctl and first user
>       vfio/pci: Add sriov_configure support
>       vfio/pci: Remove dev_fmt definition
>       vfio/pci: Cleanup .probe() exit paths
> 
> 
>  drivers/vfio/pci/vfio_pci.c         |  383
> +++++++++++++++++++++++++++++++++--
>  drivers/vfio/pci/vfio_pci_private.h |   10 +
>  drivers/vfio/vfio.c                 |   20 +-
>  include/linux/vfio.h                |    4
>  include/uapi/linux/vfio.h           |   37 +++
>  5 files changed, 426 insertions(+), 28 deletions(-)


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 17:59  0%   ` Jerin Jacob
  2020-02-24 19:35  3%     ` Stephen Hemminger
@ 2020-02-25  0:58  0%     ` Honnappa Nagarahalli
  2020-02-25 15:14  0%       ` Ananyev, Konstantin
  1 sibling, 1 reply; 200+ results
From: Honnappa Nagarahalli @ 2020-02-25  0:58 UTC (permalink / raw)
  To: Jerin Jacob, Stephen Hemminger
  Cc: Konstantin Ananyev, dpdk-dev, Olivier Matz, Honnappa Nagarahalli, nd, nd

<snip>

> 
> On Mon, Feb 24, 2020 at 10:29 PM Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Mon, 24 Feb 2020 11:35:09 +0000
> > Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:
> >
> > > Upfront note - that RFC is not a complete patch.
> > > It introduces an ABI breakage, plus it doesn't update ring_elem code
> > > properly, etc.
> > > I plan to deal with all these things in later versions.
> > > Right now I seek an initial feedback about proposed ideas.
> > > Would also ask people to repeat performance tests (see below) on
> > > their platforms to confirm the impact.
> > >
> > > More and more customers use(/try to use) DPDK based apps within
> > > overcommitted systems (multiple acttive threads over same pysical cores):
> > > VM, container deployments, etc.
> > > One quite common problem they hit: Lock-Holder-Preemption with
> rte_ring.
> > > LHP is quite a common problem for spin-based sync primitives
> > > (spin-locks, etc.) on overcommitted systems.
> > > The situation gets much worse when some sort of fair-locking
> > > technique is used (ticket-lock, etc.).
> > > As now not only lock-owner but also lock-waiters scheduling order
> > > matters a lot.
> > > This is a well-known problem for kernel within VMs:
> > > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
These slides seem to indicate that the problems are mitigated through the Hypervisor configuration. Do we still need to address the issues?

> > > The problem with rte_ring is that while head accusion is sort of
> > > un-fair locking, waiting on tail is very similar to ticket lock
> > > schema - tail has to be updated in particular order.
> > > That makes current rte_ring implementation to perform really pure on
> > > some overcommited scenarios.
> >
> > Rather than reform rte_ring to fit this scenario, it would make more
> > sense to me to introduce another primitive. The current lockless ring
> > performs very well for the isolated thread model that DPDK was built
> > around. This looks like a case of customers violating the usage model
> > of the DPDK and then being surprised at the fallout.
> 
> I agree with Stephen here.
> 
> I think, adding more runtime check in the enqueue() and dequeue() will have a
> bad effect on the low-end cores too.
> But I agree with the problem statement that in the virtualization use case, It
> may be possible to have N virtual cores runs on a physical core.
It is hard to imagine that there are data plane applications deployed in such environments. Wouldn't this affect the performance terribly?

> 
> IMO, The best solution would be keeping the ring API same and have a
> different flavor in "compile-time". Something like liburcu did for
> accommodating different flavors.
> 
> i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The application
> can simply include ONE header file in a C file based on the flavor.
> If need both at runtime. Need to have function pointer or so in the application
> and define the function in different c file by including the approaite flavor in C
> file.
> 
> #include <urcu-qsbr.h> /* QSBR RCU flavor */ #include <urcu-bp.h> /*
> Bulletproof RCU flavor */
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> >

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 19:35  3%     ` Stephen Hemminger
@ 2020-02-24 20:52  0%       ` Honnappa Nagarahalli
  2020-02-25 11:45  0%         ` Ananyev, Konstantin
  2020-02-25 13:41  3%       ` Ananyev, Konstantin
  1 sibling, 1 reply; 200+ results
From: Honnappa Nagarahalli @ 2020-02-24 20:52 UTC (permalink / raw)
  To: Stephen Hemminger, Jerin Jacob
  Cc: Konstantin Ananyev, dpdk-dev, Olivier Matz, Honnappa Nagarahalli, nd, nd



> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Stephen Hemminger
> Sent: Monday, February 24, 2020 1:35 PM
> To: Jerin Jacob <jerinjacobk@gmail.com>
> Cc: Konstantin Ananyev <konstantin.ananyev@intel.com>; dpdk-dev
> <dev@dpdk.org>; Olivier Matz <olivier.matz@6wind.com>
> Subject: Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
> 
> On Mon, 24 Feb 2020 23:29:57 +0530
> Jerin Jacob <jerinjacobk@gmail.com> wrote:
> 
> > On Mon, Feb 24, 2020 at 10:29 PM Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On Mon, 24 Feb 2020 11:35:09 +0000
> > > Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:
> > >
> > > > Upfront note - that RFC is not a complete patch.
> > > > It introduces an ABI breakage, plus it doesn't update ring_elem
> > > > code properly, etc.
> > > > I plan to deal with all these things in later versions.
> > > > Right now I seek an initial feedback about proposed ideas.
> > > > Would also ask people to repeat performance tests (see below) on
> > > > their platforms to confirm the impact.
> > > >
> > > > More and more customers use(/try to use) DPDK based apps within
> > > > overcommitted systems (multiple acttive threads over same pysical
> cores):
> > > > VM, container deployments, etc.
> > > > One quite common problem they hit: Lock-Holder-Preemption with
> rte_ring.
> > > > LHP is quite a common problem for spin-based sync primitives
> > > > (spin-locks, etc.) on overcommitted systems.
> > > > The situation gets much worse when some sort of fair-locking
> > > > technique is used (ticket-lock, etc.).
> > > > As now not only lock-owner but also lock-waiters scheduling order
> > > > matters a lot.
> > > > This is a well-known problem for kernel within VMs:
> > > > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > > > The problem with rte_ring is that while head accusion is sort of
> > > > un-fair locking, waiting on tail is very similar to ticket lock
> > > > schema - tail has to be updated in particular order.
> > > > That makes current rte_ring implementation to perform really pure
> > > > on some overcommited scenarios.
> > >
> > > Rather than reform rte_ring to fit this scenario, it would make more
> > > sense to me to introduce another primitive. The current lockless
> > > ring performs very well for the isolated thread model that DPDK was
> > > built around. This looks like a case of customers violating the
> > > usage model of the DPDK and then being surprised at the fallout.
> >
> > I agree with Stephen here.
> >
> > I think, adding more runtime check in the enqueue() and dequeue() will
> > have a bad effect on the low-end cores too.
> > But I agree with the problem statement that in the virtualization use
> > case, It may be possible to have N virtual cores runs on a physical
> > core.
> >
> > IMO, The best solution would be keeping the ring API same and have a
> > different flavor in "compile-time". Something like liburcu did for
> > accommodating different flavors.
> >
> > i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The
> > application can simply include ONE header file in a C file based on
> > the flavor.
> > If need both at runtime. Need to have function pointer or so in the
> > application and define the function in different c file by including
> > the approaite flavor in C file.
> 
> This would also be a good time to consider the tradeoffs of the heavy use of
> inlining that is done in rte_ring vs the impact that has on API/ABI stability.
> 
I was working on few requirements in rte_ring library for RCU defer APIs. RFC is at https://patchwork.dpdk.org/cover/66020/. 

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 17:59  0%   ` Jerin Jacob
@ 2020-02-24 19:35  3%     ` Stephen Hemminger
  2020-02-24 20:52  0%       ` Honnappa Nagarahalli
  2020-02-25 13:41  3%       ` Ananyev, Konstantin
  2020-02-25  0:58  0%     ` Honnappa Nagarahalli
  1 sibling, 2 replies; 200+ results
From: Stephen Hemminger @ 2020-02-24 19:35 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: Konstantin Ananyev, dpdk-dev, Olivier Matz

On Mon, 24 Feb 2020 23:29:57 +0530
Jerin Jacob <jerinjacobk@gmail.com> wrote:

> On Mon, Feb 24, 2020 at 10:29 PM Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Mon, 24 Feb 2020 11:35:09 +0000
> > Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:
> >  
> > > Upfront note - that RFC is not a complete patch.
> > > It introduces an ABI breakage, plus it doesn't update ring_elem
> > > code properly, etc.
> > > I plan to deal with all these things in later versions.
> > > Right now I seek an initial feedback about proposed ideas.
> > > Would also ask people to repeat performance tests (see below)
> > > on their platforms to confirm the impact.
> > >
> > > More and more customers use(/try to use) DPDK based apps within
> > > overcommitted systems (multiple acttive threads over same pysical cores):
> > > VM, container deployments, etc.
> > > One quite common problem they hit: Lock-Holder-Preemption with rte_ring.
> > > LHP is quite a common problem for spin-based sync primitives
> > > (spin-locks, etc.) on overcommitted systems.
> > > The situation gets much worse when some sort of
> > > fair-locking technique is used (ticket-lock, etc.).
> > > As now not only lock-owner but also lock-waiters scheduling
> > > order matters a lot.
> > > This is a well-known problem for kernel within VMs:
> > > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > > The problem with rte_ring is that while head accusion is sort of
> > > un-fair locking, waiting on tail is very similar to ticket lock schema -
> > > tail has to be updated in particular order.
> > > That makes current rte_ring implementation to perform
> > > really pure on some overcommited scenarios.  
> >
> > Rather than reform rte_ring to fit this scenario, it would make
> > more sense to me to introduce another primitive. The current lockless
> > ring performs very well for the isolated thread model that DPDK
> > was built around. This looks like a case of customers violating
> > the usage model of the DPDK and then being surprised at the fallout.  
> 
> I agree with Stephen here.
> 
> I think, adding more runtime check in the enqueue() and dequeue() will
> have a bad effect on the low-end cores too.
> But I agree with the problem statement that in the virtualization use
> case, It may be possible to have N virtual cores runs on a physical
> core.
> 
> IMO, The best solution would be keeping the ring API same and have a
> different flavor in "compile-time". Something like
> liburcu did for accommodating different flavors.
> 
> i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The
> application can simply include ONE header file in a C file based on
> the flavor.
> If need both at runtime. Need to have function pointer or so in the
> application and define the function in different c file by including
> the approaite flavor in C file.

This would also be a good time to consider the tradeoffs of the
heavy use of inlining that is done in rte_ring vs the impact that
has on API/ABI stability.



^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 16:59  0% ` Stephen Hemminger
@ 2020-02-24 17:59  0%   ` Jerin Jacob
  2020-02-24 19:35  3%     ` Stephen Hemminger
  2020-02-25  0:58  0%     ` Honnappa Nagarahalli
  0 siblings, 2 replies; 200+ results
From: Jerin Jacob @ 2020-02-24 17:59 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Konstantin Ananyev, dpdk-dev, Olivier Matz

On Mon, Feb 24, 2020 at 10:29 PM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Mon, 24 Feb 2020 11:35:09 +0000
> Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:
>
> > Upfront note - that RFC is not a complete patch.
> > It introduces an ABI breakage, plus it doesn't update ring_elem
> > code properly, etc.
> > I plan to deal with all these things in later versions.
> > Right now I seek an initial feedback about proposed ideas.
> > Would also ask people to repeat performance tests (see below)
> > on their platforms to confirm the impact.
> >
> > More and more customers use(/try to use) DPDK based apps within
> > overcommitted systems (multiple acttive threads over same pysical cores):
> > VM, container deployments, etc.
> > One quite common problem they hit: Lock-Holder-Preemption with rte_ring.
> > LHP is quite a common problem for spin-based sync primitives
> > (spin-locks, etc.) on overcommitted systems.
> > The situation gets much worse when some sort of
> > fair-locking technique is used (ticket-lock, etc.).
> > As now not only lock-owner but also lock-waiters scheduling
> > order matters a lot.
> > This is a well-known problem for kernel within VMs:
> > http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> > https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> > The problem with rte_ring is that while head accusion is sort of
> > un-fair locking, waiting on tail is very similar to ticket lock schema -
> > tail has to be updated in particular order.
> > That makes current rte_ring implementation to perform
> > really pure on some overcommited scenarios.
>
> Rather than reform rte_ring to fit this scenario, it would make
> more sense to me to introduce another primitive. The current lockless
> ring performs very well for the isolated thread model that DPDK
> was built around. This looks like a case of customers violating
> the usage model of the DPDK and then being surprised at the fallout.

I agree with Stephen here.

I think, adding more runtime check in the enqueue() and dequeue() will
have a bad effect on the low-end cores too.
But I agree with the problem statement that in the virtualization use
case, It may be possible to have N virtual cores runs on a physical
core.

IMO, The best solution would be keeping the ring API same and have a
different flavor in "compile-time". Something like
liburcu did for accommodating different flavors.

i.e urcu-qsbr.h and urcu-bp.h will identical definition of API. The
application can simply include ONE header file in a C file based on
the flavor.
If need both at runtime. Need to have function pointer or so in the
application and define the function in different c file by including
the approaite flavor in C file.

#include <urcu-qsbr.h> /* QSBR RCU flavor */
#include <urcu-bp.h> /* Bulletproof RCU flavor */













>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [RFC 0/6] New sync modes for ring
  2020-02-24 11:35  2% [dpdk-dev] [RFC 0/6] New sync modes for ring Konstantin Ananyev
@ 2020-02-24 16:59  0% ` Stephen Hemminger
  2020-02-24 17:59  0%   ` Jerin Jacob
  2020-03-25 20:43  0% ` Honnappa Nagarahalli
  2020-03-31 16:43  3% ` [dpdk-dev] [PATCH v1 0/8] " Konstantin Ananyev
  2 siblings, 1 reply; 200+ results
From: Stephen Hemminger @ 2020-02-24 16:59 UTC (permalink / raw)
  To: Konstantin Ananyev; +Cc: dev, olivier.matz

On Mon, 24 Feb 2020 11:35:09 +0000
Konstantin Ananyev <konstantin.ananyev@intel.com> wrote:

> Upfront note - that RFC is not a complete patch.
> It introduces an ABI breakage, plus it doesn't update ring_elem
> code properly, etc.
> I plan to deal with all these things in later versions.
> Right now I seek an initial feedback about proposed ideas.
> Would also ask people to repeat performance tests (see below)
> on their platforms to confirm the impact.
> 
> More and more customers use(/try to use) DPDK based apps within
> overcommitted systems (multiple acttive threads over same pysical cores):
> VM, container deployments, etc.
> One quite common problem they hit: Lock-Holder-Preemption with rte_ring.
> LHP is quite a common problem for spin-based sync primitives
> (spin-locks, etc.) on overcommitted systems.
> The situation gets much worse when some sort of
> fair-locking technique is used (ticket-lock, etc.).
> As now not only lock-owner but also lock-waiters scheduling
> order matters a lot.
> This is a well-known problem for kernel within VMs:
> http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
> https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
> The problem with rte_ring is that while head accusion is sort of
> un-fair locking, waiting on tail is very similar to ticket lock schema -
> tail has to be updated in particular order.
> That makes current rte_ring implementation to perform
> really pure on some overcommited scenarios.

Rather than reform rte_ring to fit this scenario, it would make
more sense to me to introduce another primitive. The current lockless
ring performs very well for the isolated thread model that DPDK
was built around. This looks like a case of customers violating
the usage model of the DPDK and then being surprised at the fallout.


^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [RFC 0/6] New sync modes for ring
@ 2020-02-24 11:35  2% Konstantin Ananyev
  2020-02-24 16:59  0% ` Stephen Hemminger
                   ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Konstantin Ananyev @ 2020-02-24 11:35 UTC (permalink / raw)
  To: dev; +Cc: olivier.matz, Konstantin Ananyev

Upfront note - that RFC is not a complete patch.
It introduces an ABI breakage, plus it doesn't update ring_elem
code properly, etc.
I plan to deal with all these things in later versions.
Right now I seek an initial feedback about proposed ideas.
Would also ask people to repeat performance tests (see below)
on their platforms to confirm the impact.

More and more customers use(/try to use) DPDK based apps within
overcommitted systems (multiple acttive threads over same pysical cores):
VM, container deployments, etc.
One quite common problem they hit: Lock-Holder-Preemption with rte_ring.
LHP is quite a common problem for spin-based sync primitives
(spin-locks, etc.) on overcommitted systems.
The situation gets much worse when some sort of
fair-locking technique is used (ticket-lock, etc.).
As now not only lock-owner but also lock-waiters scheduling
order matters a lot.
This is a well-known problem for kernel within VMs:
http://www-archive.xenproject.org/files/xensummitboston08/LHP.pdf
https://www.cs.hs-rm.de/~kaiser/events/wamos2017/Slides/selcuk.pdf
The problem with rte_ring is that while head accusion is sort of
un-fair locking, waiting on tail is very similar to ticket lock schema -
tail has to be updated in particular order.
That makes current rte_ring implementation to perform
really pure on some overcommited scenarios.
While it is probably not possible to completely resolve this problem in
userspace only (without some kernel communication/intervention),
removing fairness in tail update can mitigate it significantly.
So this RFC proposes two new optional ring synchronization modes:
1) Head/Tail Sync (HTS) mode
In that mode enqueue/dequeue operation is fully serialized:
    only one thread at a time is allowed to perform given op.
    As another enhancement provide ability to split enqueue/dequeue
    operation into two phases:
      - enqueue/dequeue start
      - enqueue/dequeue finish
    That allows user to inspect objects in the ring without removing
    them from it (aka MT safe peek).
2) Relaxed Tail Sync (RTS)
The main difference from original MP/MC algorithm is that
tail value is increased not by every thread that finished enqueue/dequeue,
but only by the last one.
That allows threads to avoid spinning on ring tail value,
leaving actual tail value change to the last thread in the update queue.

Test results on IA (see below) show significant improvements
for average enqueue/dequeue op times on overcommitted systems.
For 'classic' DPDK deployments (one thread per core) original MP/MC
algorithm still shows best numbers, though for 64-bit target
RTS numbers are not that far away.
Numbers were produced by ring_stress_*autotest
(first patch in these series).

X86_64 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     8.00       8.15    8.99
2thread@2core(--lcores=6-8)                     19.14      19.61   20.35
4thread@4core(--lcores=6-10)                    29.43      29.79   31.82
8thread@8core(--lcores=6-14)                    110.59     192.81  119.50
16thread@16core(--lcores=6-22)                  461.03     813.12  495.59
32thread/@32core(--lcores='6-22,55-70')         982.90     1972.38 1160.51

2thread@1core(--lcores='6,(10-11)@7'            20140.50   23.58   25.14
4thread@2core(--lcores='6,(10-11)@7,(20-21)@8'  153680.60  76.88   80.05
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  280314.32  294.72  318.79
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 643176.59  1144.02 1175.14
32thread@2core(--lcores='6,(10-25)@7,(30-45)@8' 4264238.80 4627.48 4892.68

8thread@2core(--lcores='6,(10-17)@(7,8))'       321085.98  298.59  307.47
16thread@4core(--lcores='6,(20-35)@(7-10))'     1900705.61 575.35  678.29
32thread@4core(--lcores='6,(20-51)@(7-10))'     5510445.85 2164.36 2714.12

i686 @ Intel(R) Xeon(R) Platinum 8160 CPU @ 2.10GHz
DEQ+ENQ average cycles/obj

                                                MP/MC      HTS     RTS
1thread@1core(--lcores=6-7)                     7.85       12.13   11.31
2thread@2core(--lcores=6-8)                     17.89      24.52   21.86
8thread@8core(--lcores=6-14)                    32.58      354.20  54.58
32thread/@32core(--lcores='6-22,55-70')         813.77     6072.41 2169.91

2thread@1core(--lcores='6,(10-11)@7'            16095.00   36.06   34.74
8thread@2core(--lcores='6,(10-13)@7,(20-23)@8'  1140354.54 346.61  361.57
16thread@2core(--lcores='6,(10-17)@7,(20-27)@8' 1920417.86 1314.90 1416.65

8thread@2core(--lcores='6,(10-17)@(7,8))'       594358.61  332.70  357.74
32thread@4core(--lcores='6,(20-51)@(7-10))'     5319896.86 2836.44 3028.87

Konstantin Ananyev (6):
  test/ring: add contention stress test
  ring: rework ring layout to allow new sync schemes
  ring: introduce RTS ring mode
  test/ring: add contention stress test for RTS ring
  ring: introduce HTS ring mode
  test/ring: add contention stress test for HTS ring

 app/test/Makefile                      |   3 +
 app/test/meson.build                   |   3 +
 app/test/test_pdump.c                  |   6 +-
 app/test/test_ring_hts_stress.c        |  28 ++
 app/test/test_ring_rts_stress.c        |  28 ++
 app/test/test_ring_stress.c            |  27 ++
 app/test/test_ring_stress.h            | 477 +++++++++++++++++++
 lib/librte_pdump/rte_pdump.c           |   2 +-
 lib/librte_port/rte_port_ring.c        |  12 +-
 lib/librte_ring/Makefile               |   4 +-
 lib/librte_ring/meson.build            |   4 +-
 lib/librte_ring/rte_ring.c             |  84 +++-
 lib/librte_ring/rte_ring.h             | 619 +++++++++++++++++++++++--
 lib/librte_ring/rte_ring_elem.h        |   8 +-
 lib/librte_ring/rte_ring_hts_generic.h | 228 +++++++++
 lib/librte_ring/rte_ring_rts_generic.h | 240 ++++++++++
 16 files changed, 1721 insertions(+), 52 deletions(-)
 create mode 100644 app/test/test_ring_hts_stress.c
 create mode 100644 app/test/test_ring_rts_stress.c
 create mode 100644 app/test/test_ring_stress.c
 create mode 100644 app/test/test_ring_stress.h
 create mode 100644 lib/librte_ring/rte_ring_hts_generic.h
 create mode 100644 lib/librte_ring/rte_ring_rts_generic.h

-- 
2.17.1


^ permalink raw reply	[relevance 2%]

* Re: [dpdk-dev] ABI version of experimental libraries
  2020-02-21 16:57  4%     ` Thomas Monjalon
@ 2020-02-24  9:32  4%       ` Ray Kinsella
  0 siblings, 0 replies; 200+ results
From: Ray Kinsella @ 2020-02-24  9:32 UTC (permalink / raw)
  To: Thomas Monjalon, dev



On 21/02/2020 16:57, Thomas Monjalon wrote:
> 19/02/2020 14:50, Ray Kinsella:
>> On 19/02/2020 12:43, Thomas Monjalon wrote:
>>> 19/02/2020 12:43, Neil Horman:
>>>> On Tue, Feb 18, 2020 at 10:50:09AM +0100, Thomas Monjalon wrote:
>>>>> 18/02/2020 10:42, Bruce Richardson:
>>>>>> On Tue, Feb 18, 2020 at 12:15:56AM +0100, Thomas Monjalon wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> I would like to remind everybody our mistake when defining ABI versions.
>>>>>>> It has been "fixed" in this commit:
>>>>>>> http://git.dpdk.org/dpdk/commit/?id=f26c2b39
>>>>>>>
>>>>>>> Please let's think about the consequence for the experimental libraries.
>>>>>>>
>>>>>>> In DPDK 19.11, we use the ABI version 0.200 with soname 0.20 In DPDK
>>>>>>> 20.02, we use the ABI version 0.2001 with soname 0.201 Numbers are
>>>>>>> increasing, that's fine.  When we'll switch to the new major ABI and use
>>>>>>> a normal numbering: In DPDK 20.11, we will use the ABI version 0.210 with
>>>>>>> soname 0.21 Numbers are dropping.
>>>>>>>
>>>>>>> In short, for experimental libs, ABI 20.1 > ABI 21.0
>>>>>>>
>>>>>>> Are we OK with this or do we prefer reverting to normal numbering for
>>>>>>> experimental libraries in DPDK 20.02?
>>>>>>>
>>>>>> Personally, I would not be too concerned about the verions of experimental
>>>>>> libs, so long as they don't conflict across versions and have some
>>>>>> similarity to the major ABI version for the release.
>>>>>
>>>>> You think sorting of the version numbers is not important?
>>>>> If we don't care comparing experimental version numbers,
>>>>> then OK, let's drop this patch. But please we need a small vote.
>>>>>
>>>>> Note: there would be no problem if we did not vote for having
>>>>> a special numbering for pure experimental libraries (I am still against).
>>>>>
>>>> I don't understand.  Why would we change the ABI_VERSION at all in an LTS release at
>>>> all?  This operation is meant to take an an experimental API and mark it as
>>>> stable by promoting its version number to the next major releases number.  As
>>>> such, in the LTS release, we should keep the soname the same, as there should be
>>>> no other ABI changes in the promoted API.
>>>
>>> The library version number is updated because we add new symbols.
>>>
>>>
>>
>> So while experimental library version numbers are not "important".
>> I do agree with Thomas they should be sane, increase and should have a consistent format.
>>
>> Should we always just pad them to 4 places as the simple solution?
>> i.e.
>>
>> DPDK 19.11 ... 0.20 (needs to remain 0.20).
>> DPDK 20.02 ... 0.2001
>> DPDK 20.11 ... 0.2100
>> DPDK 21.02 ... 0.2101 
> 
> A patch from Ferruh got merged.
> It is adding a dot to keep versioning consistent.
> 
> Marking this patch as rejected.
> 

Ferruh's was a better solution.  

^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH] doc: deprecate using MAX values as array size
    2020-02-24  6:18  0%   ` Akhil Goyal
@ 2020-02-24  8:51  0%   ` Andrew Rybchenko
  1 sibling, 0 replies; 200+ results
From: Andrew Rybchenko @ 2020-02-24  8:51 UTC (permalink / raw)
  To: Ferruh Yigit, Neil Horman, John McNamara, Marko Kovacevic
  Cc: dev, Thomas Monjalon, Bruce Richardson, Akhil Goyal,
	Konstantin Ananyev, David Marchand, Jerin Jacob, Ori Kam

On 2/21/20 1:25 PM, Ferruh Yigit wrote:
> On 1/30/2020 2:20 PM, Ferruh Yigit wrote:
>> Adding the deprecation notice as reminder for next ABI breakage release
>> (20.11).
>> This one time breakage is required to be able to extend enum/define
>> without breaking ABI.
>>
>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>> ---
>>  doc/guides/rel_notes/deprecation.rst | 14 ++++++++++++++
>>  1 file changed, 14 insertions(+)
>>
>> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
>> index dfcca87ab..99d81564a 100644
>> --- a/doc/guides/rel_notes/deprecation.rst
>> +++ b/doc/guides/rel_notes/deprecation.rst
>> @@ -38,6 +38,20 @@ Deprecation Notices
>>    remove it from the externally visible ABI and allow it to be updated in the
>>    future.
>>  
>> +* lib: will fix extending some enum/define breaking the ABI. There are multiple
>> +  samples in DPDK that enum/define terminated with a ``.*MAX.*`` value which is
>> +  used by iterators, and arrays holding these values are sized with this
>> +  ``.*MAX.*`` value. So extending this enum/define increases the ``.*MAX.*``
>> +  value which increases the size of the array and depending on how/where the
>> +  array is used this may break the ABI.
>> +  ``RTE_ETH_FLOW_MAX`` is one sample of the mentioned case, adding a new flow
>> +  type will break the ABI because of ``flex_mask[RTE_ETH_FLOW_MAX]`` array
>> +  usage in following public struct hierarchy:
>> +  ``rte_eth_fdir_flex_conf -> rte_fdir_conf -> rte_eth_conf (in the middle)``.
>> +  Need to identify this kind of usages and fix in 20.11, otherwise this blocks
>> +  us extending existing enum/define.
>> +  One solution can be using a fixed size array instead of ``.*MAX.*`` value.
>> +
>>  * dpaa2: removal of ``rte_dpaa2_memsegs`` structure which has been replaced
>>    by a pa-va search library. This structure was earlier being used for holding
>>    memory segments used by dpaa2 driver for faster pa->va translation. This
>>
> Reminder of this deprecation notice.

Acked-by: Andrew Rybchenko <arybchenko@oktetlabs.ru>



^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [dpdk-techboard] [PATCH] doc: deprecation notice to move igb_uio to a new repo
  @ 2020-02-24  7:03  0% ` Maxime Coquelin
  0 siblings, 0 replies; 200+ results
From: Maxime Coquelin @ 2020-02-24  7:03 UTC (permalink / raw)
  To: jerinj, dev, Neil Horman, John McNamara, Marko Kovacevic
  Cc: thomas, techboard, ferruh.yigit



On 1/30/20 5:58 PM, jerinj@marvell.com wrote:
> From: Jerin Jacob <jerinj@marvell.com>
> 
> Based on the tech board meeting held on 2019-11-06,
> It's been decided to move igb_uio kernel module to a new repository
> hosted by dpdk.org in v20.11 release.
> 
> http://mails.dpdk.org/archives/dev/2019-November/151763.html
> 
> Adding the deprecation notice for the same in advance.
> 
> Signed-off-by: Jerin Jacob <jerinj@marvell.com>
> ---
>  doc/guides/rel_notes/deprecation.rst | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
> index dfcca87ab..2b9d0113f 100644
> --- a/doc/guides/rel_notes/deprecation.rst
> +++ b/doc/guides/rel_notes/deprecation.rst
> @@ -38,6 +38,12 @@ Deprecation Notices
>    remove it from the externally visible ABI and allow it to be updated in the
>    future.
>  
> +* igb_uio: In the view of reducing the kernel dependency from the main tree,
> +  as a first step, The technical board has been decided to move ``igb_uio``
> +  kernel module to a new repository hosted by dpdk.org in v20.11 release.
> +  Minutes of Technical Board Meeting of `2019-11-06
> +  <http://mails.dpdk.org/archives/dev/2019-November/151763.html>`_.
> +
>  * dpaa2: removal of ``rte_dpaa2_memsegs`` structure which has been replaced
>    by a pa-va search library. This structure was earlier being used for holding
>    memory segments used by dpaa2 driver for faster pa->va translation. This
> 

Acked-by: Maxime Coquelin <maxime.coquelin@redhat.com>

Thanks,
Maxime


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] doc: deprecate using MAX values as array size
  @ 2020-02-24  6:18  0%   ` Akhil Goyal
  2020-02-25 11:03  0%     ` Thomas Monjalon
  2020-02-24  8:51  0%   ` Andrew Rybchenko
  1 sibling, 1 reply; 200+ results
From: Akhil Goyal @ 2020-02-24  6:18 UTC (permalink / raw)
  To: Ferruh Yigit, Neil Horman, John McNamara, Marko Kovacevic
  Cc: dev, Thomas Monjalon, Bruce Richardson, Konstantin Ananyev,
	David Marchand, Jerin Jacob, Andrew Rybchenko, Ori Kam


> 
> On 1/30/2020 2:20 PM, Ferruh Yigit wrote:
> > Adding the deprecation notice as reminder for next ABI breakage release
> > (20.11).
> > This one time breakage is required to be able to extend enum/define
> > without breaking ABI.
> >
> > Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> > ---
> >  doc/guides/rel_notes/deprecation.rst | 14 ++++++++++++++
> >  1 file changed, 14 insertions(+)
> >
> > diff --git a/doc/guides/rel_notes/deprecation.rst
> b/doc/guides/rel_notes/deprecation.rst
> > index dfcca87ab..99d81564a 100644
> > --- a/doc/guides/rel_notes/deprecation.rst
> > +++ b/doc/guides/rel_notes/deprecation.rst
> > @@ -38,6 +38,20 @@ Deprecation Notices
> >    remove it from the externally visible ABI and allow it to be updated in the
> >    future.
> >
> > +* lib: will fix extending some enum/define breaking the ABI. There are
> multiple
> > +  samples in DPDK that enum/define terminated with a ``.*MAX.*`` value
> which is
> > +  used by iterators, and arrays holding these values are sized with this
> > +  ``.*MAX.*`` value. So extending this enum/define increases the ``.*MAX.*``
> > +  value which increases the size of the array and depending on how/where the
> > +  array is used this may break the ABI.
> > +  ``RTE_ETH_FLOW_MAX`` is one sample of the mentioned case, adding a
> new flow
> > +  type will break the ABI because of ``flex_mask[RTE_ETH_FLOW_MAX]``
> array
> > +  usage in following public struct hierarchy:
> > +  ``rte_eth_fdir_flex_conf -> rte_fdir_conf -> rte_eth_conf (in the middle)``.
> > +  Need to identify this kind of usages and fix in 20.11, otherwise this blocks
> > +  us extending existing enum/define.
> > +  One solution can be using a fixed size array instead of ``.*MAX.*`` value.
> > +
> >  * dpaa2: removal of ``rte_dpaa2_memsegs`` structure which has been
> replaced
> >    by a pa-va search library. This structure was earlier being used for holding
> >    memory segments used by dpaa2 driver for faster pa->va translation. This
> >
> 
We admit that the issue is there and we can discuss the possible solutions for this issue.

For the deprecation notice.
Acked-by: Akhil Goyal <akhil.goyal@nxp.com>

^ permalink raw reply	[relevance 0%]

* [dpdk-dev] [PATCH v1] doc: update release notes for 20.02
@ 2020-02-23 10:59  8% John McNamara
  0 siblings, 0 replies; 200+ results
From: John McNamara @ 2020-02-23 10:59 UTC (permalink / raw)
  To: dev; +Cc: thomas, John McNamara

Fix grammar, spelling and formatting of DPDK 20.02 release notes.

Signed-off-by: John McNamara <john.mcnamara@intel.com>
---
 doc/guides/rel_notes/release_20_02.rst | 70 +++++++++++++++-------------------
 1 file changed, 31 insertions(+), 39 deletions(-)

diff --git a/doc/guides/rel_notes/release_20_02.rst b/doc/guides/rel_notes/release_20_02.rst
index dfebc46..8a493e4 100644
--- a/doc/guides/rel_notes/release_20_02.rst
+++ b/doc/guides/rel_notes/release_20_02.rst
@@ -74,7 +74,7 @@ New Features
   Added the new ``ionic`` net driver for Pensando Ethernet Network Adapters.
   See the :doc:`../nics/ionic` NIC guide for more details on this new driver.
 
-* **Updated Broadcom bnxt driver**
+* **Updated Broadcom bnxt driver.**
 
   Updated Broadcom bnxt driver with new features and improvements, including:
 
@@ -91,10 +91,10 @@ New Features
 
   Updated the Intel ice driver with new features and improvements, including:
 
-  * Added support for MAC rules on specific port.
+  * Added support for MAC rules on a specific port.
   * Added support for MAC/VLAN with TCP/UDP in switch rule.
   * Added support for 1/10G device.
-  * Added support for API rte_eth_tx_done_cleanup.
+  * Added support for API ``rte_eth_tx_done_cleanup``.
 
 * **Updated Intel iavf driver.**
 
@@ -105,7 +105,9 @@ New Features
 
 * **Updated the Intel ixgbe driver.**
 
-  * Added support for API rte_eth_tx_done_cleanup.
+  Updated ixgbe PMD with new features and improvements, including:
+
+  * Added support for API ``rte_eth_tx_done_cleanup()``.
   * Added support setting VF MAC address by PF driver.
   * Added support for setting the link to specific speed.
 
@@ -122,7 +124,7 @@ New Features
   * Extended PHY access AQ cmd.
   * Added support for reading LPI counters.
   * Added support for Energy Efficient Ethernet.
-  * Added support for API rte_eth_tx_done_cleanup.
+  * Added support for API ``rte_eth_tx_done_cleanup()``.
   * Added support for VF multiple queues interrupt.
   * Added support for setting the link to specific speed.
 
@@ -135,7 +137,7 @@ New Features
   * Removed limitation of matching on tagged/untagged packets (when using DV flow engine).
   * Added BlueField-2 integrated ConnectX-6 Dx device support.
 
-* **Add new vDPA PMD based on Mellanox devices**
+* **Add new vDPA PMD based on Mellanox devices.**
 
   Added a new Mellanox vDPA  (``mlx5_vdpa``) PMD.
   See the :doc:`../vdpadevs/mlx5` guide for more details on this driver.
@@ -155,6 +157,8 @@ New Features
 
 * **Added algorithms to cryptodev API.**
 
+  Added new algorithms to the cryptodev API:
+
   * ECDSA (Elliptic Curve Digital Signature Algorithm) is added to
     asymmetric crypto library specifications.
   * ECPM (Elliptic Curve Point Multiplication) is added to
@@ -162,8 +166,8 @@ New Features
 
 * **Added synchronous Crypto burst API.**
 
-  A new API is introduced in crypto library to handle synchronous cryptographic
-  operations allowing to achieve performance gain for cryptodevs which use
+  A new API has been introduced in the crypto library to handle synchronous cryptographic
+  operations allowing it to achieve performance gains for cryptodevs which use
   CPU based acceleration, such as Intel AES-NI. An implementation for aesni_gcm
   cryptodev is provided. The IPsec example application and ipsec library itself
   were changed to allow utilization of this new feature.
@@ -174,7 +178,7 @@ New Features
   (generation) and cipher-hash (verification) requests (e.g. SNOW3G + ZUC or
   ZUC + AES CTR) in QAT PMD possible when running on GEN3 QAT hardware.
   Such algorithm combinations are not supported on GEN1/GEN2 hardware
-  and executing the request returns RTE_CRYPTO_OP_STATUS_INVALID_SESSION.
+  and executing the request returns ``RTE_CRYPTO_OP_STATUS_INVALID_SESSION``.
 
 * **Queue-pairs are now thread-safe on Intel QuickAssist Technology (QAT) PMD.**
 
@@ -185,34 +189,35 @@ New Features
 
 * **Updated the ZUC PMD.**
 
-  * Transistioned underlying library from libSSO ZUC to intel-ipsec-mb
+  * Transitioned underlying library from libSSO ZUC to intel-ipsec-mb
     library (minimum version required 0.53).
   * Removed dynamic library limitation, so PMD can be built as a shared
     object now.
 
 * **Updated the KASUMI PMD.**
 
-  * Transistioned underlying library from libSSO KASUMI to intel-ipsec-mb
+  * Transitioned underlying library from libSSO KASUMI to intel-ipsec-mb
     library (minimum version required 0.53).
 
 * **Updated the SNOW3G PMD.**
 
-  * Transistioned underlying library from libSSO SNOW3G to intel-ipsec-mb
+  * Transitioned underlying library from libSSO SNOW3G to intel-ipsec-mb
     library (minimum version required 0.53).
 
 * **Changed armv8 crypto PMD external dependency.**
 
-  armv8 crypto PMD now depends on Arm crypto library, and Marvell's
-  armv8 crypto library is not used anymore. Library name is changed
+  Changed armv8 crypto PMD external dependency. The
+  armv8 crypto PMD now depends on the Arm crypto library, and Marvell's
+  armv8 crypto library is not used anymore. The library name has been changed
   from armv8_crypto to AArch64crypto.
 
 * **Added inline IPsec support to Marvell OCTEON TX2 PMD.**
 
-  Added inline IPsec support to Marvell OCTEON TX2 PMD. With the feature,
-  applications would be able to offload entire IPsec offload to the hardware.
+  Added inline IPsec support to Marvell OCTEON TX2 PMD. With this feature,
+  applications will be able to offload entire IPsec offload to the hardware.
   For the configured sessions, hardware will do the lookup and perform
-  decryption and IPsec transformation. For the outbound path, application
-  can submit a plain packet to the PMD, and it would be sent out on wire
+  decryption and IPsec transformation. For the outbound path, applications
+  can submit a plain packet to the PMD, and it will be sent out on the wire
   after doing encryption and IPsec transformation of the packet.
 
 * **Added Marvell OCTEON TX2 End Point rawdev PMD.**
@@ -222,7 +227,7 @@ New Features
 
 * **Added event mode to l3fwd sample application.**
 
-  Add event device support for ``l3fwd`` sample application. It demonstrates
+  Added event device support for the ``l3fwd`` sample application. It demonstrates
   usage of poll and event mode IO mechanism under a single application.
 
 * **Added cycle-count mode to the compression performance tool.**
@@ -232,8 +237,8 @@ New Features
 
 * **Added OpenWrt howto guide.**
 
-  Added document describes how to enable DPDK on OpenWrt in both virtual and
-  physical machine.
+  Added document which describes how to enable DPDK on OpenWrt in both virtual and
+  physical machines.
 
 
 Removed Items
@@ -250,7 +255,7 @@ Removed Items
 
 * **Disabled building all the Linux kernel modules by default.**
 
-  In order to remove the build time dependency with Linux kernel,
+  In order to remove the build time dependency on the Linux kernel,
   the Technical Board decided to disable all the kernel modules
   by default from 20.02 version.
 
@@ -259,8 +264,8 @@ Removed Items
   The internal tail write coalescing feature was removed as not compatible with
   dual-thread feature. It was replaced with a threshold feature. At busy times
   if only a small number of packets can be enqueued, each enqueue causes
-  an expensive MMIO write. These MMIO write occurrences can be optimised by using
-  the new threshold parameter on process start. Please see qat documentation for
+  an expensive MMIO write. These MMIO write occurrences can be optimized by using
+  the new threshold parameter on process start. Please see QAT documentation for
   more details.
 
 
@@ -279,6 +284,8 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =========================================================
 
+* No changes in this release.
+
 
 ABI Changes
 -----------
@@ -298,21 +305,6 @@ ABI Changes
 * No change, kept ABI v20. DPDK 20.02 is compatible with DPDK 19.11.
 
 
-Known Issues
-------------
-
-.. This section should contain new known issues in this release. Sample format:
-
-   * **Add title in present tense with full stop.**
-
-     Add a short 1-2 sentence description of the known issue
-     in the present tense. Add information on any known workarounds.
-
-   This section is a comment. Do not overwrite or remove it.
-   Also, make sure to start the actual text at the margin.
-   =========================================================
-
-
 Tested Platforms
 ----------------
 
-- 
2.7.5


^ permalink raw reply	[relevance 8%]

* Re: [dpdk-dev] [PATCH v3] cmdline: increase maximum line length
  @ 2020-02-22 15:28  3%   ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-02-22 15:28 UTC (permalink / raw)
  To: Wisam Jaddo
  Cc: dev, Raslan, Thomas Monjalon, Olivier Matz, Iremonger, Bernard,
	dpdk stable

This patch is flagged as an ABI breakage:
https://travis-ci.com/ovsrobot/dpdk/jobs/289313318#L2273


On Thu, Feb 20, 2020 at 3:53 PM Wisam Jaddo <wisamm@mellanox.com> wrote:
>
> This increase due to the usage of cmdline in dpdk applications
> as config commands such as testpmd do for rte_flow rules creation.
>
> The current size of buffer is not enough to fill
> many cases of rte_flow commands validation/creation.
>
> rte_flow now can have outer items, inner items, modify
> actions, meta data actions, duplicate action, fate action and
> more in one single rte flow, thus 512 char will not be enough
> to validate such rte flow rules.
>
> Such change shouldn't affect the memory since the cmdline
> reading again using the same buffer.

I don't get your point here.


> Cc: stable@dpdk.org

This is not a fix.


-- 
David Marchand


^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH v4] doc: alias to experimental tag for stable apis
  @ 2020-02-21 17:11  0%   ` Ferruh Yigit
  2020-02-25 14:22  0%   ` Kevin Traynor
  1 sibling, 0 replies; 200+ results
From: Ferruh Yigit @ 2020-02-21 17:11 UTC (permalink / raw)
  To: Ray Kinsella, dev
  Cc: john.mcnamara, nhorman, marko.kovacevic, bruce.richardson

On 2/18/2020 10:46 AM, Ray Kinsella wrote:
> When a maintainer is promoting an API to become part of the next major ABI
> version by removing the experimental tag, possibly a few releases in
> advance of the declaration of the next ABI version. The maintainer may
> choose to offer an alias to the experimental tag, as removing the tag
> before the declaration of the next major ABI version, would cause an ABI
> breakage for applications using the API.
> 
> Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
> ---
>  doc/guides/contributing/abi_policy.rst | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/doc/guides/contributing/abi_policy.rst b/doc/guides/contributing/abi_policy.rst
> index 05ca959..7ae7de7 100644
> --- a/doc/guides/contributing/abi_policy.rst
> +++ b/doc/guides/contributing/abi_policy.rst
> @@ -159,6 +159,11 @@ The requirements for changing the ABI are:
>       ``experimental``, as described in the section on :ref:`Experimental APIs
>       and Libraries <experimental_apis>`.
>  
> +   - In situations in which an ``experimental`` API has been stable for some
> +     time. When promoting the API to become part of the next ABI version, the
> +     maintainer may choose to provide an alias to the ``experimental`` tag, so
> +     as not to break consuming applications.
> +
>  #. If a newly proposed API functionally replaces an existing one, when the new
>     API becomes non-experimental, then the old one is marked with
>     ``__rte_deprecated``.
> @@ -317,6 +322,11 @@ not required. Though, an API should remain in experimental state for at least
>  one release. Thereafter, the normal process of posting patch for review to
>  mailing list can be followed.
>  
> +After the experimental tag has been formally removed, a tree/sub-tree maintainer
> +may choose to offer an alias to the experimental tag so as not to break
> +applications using the API. The alias is then dropped at the declaration of next
> +major ABI version.
> +
>  Libraries
>  ~~~~~~~~~
>  
> 

This leaves the decision to author/maintainer, I am more for making this a
requirement, but at least this enables it and better than nothing ;)

Acked-by: Ferruh Yigit <ferruh.yigit@intel.com>

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] ABI version of experimental libraries
  @ 2020-02-21 16:57  4%     ` Thomas Monjalon
  2020-02-24  9:32  4%       ` Ray Kinsella
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-02-21 16:57 UTC (permalink / raw)
  To: dev; +Cc: Ray Kinsella

19/02/2020 14:50, Ray Kinsella:
> On 19/02/2020 12:43, Thomas Monjalon wrote:
> > 19/02/2020 12:43, Neil Horman:
> >> On Tue, Feb 18, 2020 at 10:50:09AM +0100, Thomas Monjalon wrote:
> >>> 18/02/2020 10:42, Bruce Richardson:
> >>>> On Tue, Feb 18, 2020 at 12:15:56AM +0100, Thomas Monjalon wrote:
> >>>>> Hi,
> >>>>>
> >>>>> I would like to remind everybody our mistake when defining ABI versions.
> >>>>> It has been "fixed" in this commit:
> >>>>> http://git.dpdk.org/dpdk/commit/?id=f26c2b39
> >>>>>
> >>>>> Please let's think about the consequence for the experimental libraries.
> >>>>>
> >>>>> In DPDK 19.11, we use the ABI version 0.200 with soname 0.20 In DPDK
> >>>>> 20.02, we use the ABI version 0.2001 with soname 0.201 Numbers are
> >>>>> increasing, that's fine.  When we'll switch to the new major ABI and use
> >>>>> a normal numbering: In DPDK 20.11, we will use the ABI version 0.210 with
> >>>>> soname 0.21 Numbers are dropping.
> >>>>>
> >>>>> In short, for experimental libs, ABI 20.1 > ABI 21.0
> >>>>>
> >>>>> Are we OK with this or do we prefer reverting to normal numbering for
> >>>>> experimental libraries in DPDK 20.02?
> >>>>>
> >>>> Personally, I would not be too concerned about the verions of experimental
> >>>> libs, so long as they don't conflict across versions and have some
> >>>> similarity to the major ABI version for the release.
> >>>
> >>> You think sorting of the version numbers is not important?
> >>> If we don't care comparing experimental version numbers,
> >>> then OK, let's drop this patch. But please we need a small vote.
> >>>
> >>> Note: there would be no problem if we did not vote for having
> >>> a special numbering for pure experimental libraries (I am still against).
> >>>
> >> I don't understand.  Why would we change the ABI_VERSION at all in an LTS release at
> >> all?  This operation is meant to take an an experimental API and mark it as
> >> stable by promoting its version number to the next major releases number.  As
> >> such, in the LTS release, we should keep the soname the same, as there should be
> >> no other ABI changes in the promoted API.
> > 
> > The library version number is updated because we add new symbols.
> > 
> > 
> 
> So while experimental library version numbers are not "important".
> I do agree with Thomas they should be sane, increase and should have a consistent format.
> 
> Should we always just pad them to 4 places as the simple solution?
> i.e.
> 
> DPDK 19.11 ... 0.20 (needs to remain 0.20).
> DPDK 20.02 ... 0.2001
> DPDK 20.11 ... 0.2100
> DPDK 21.02 ... 0.2101 

A patch from Ferruh got merged.
It is adding a dot to keep versioning consistent.

Marking this patch as rejected.



^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [dpdk-ci] [PATCH 4/4] ci: reorganise Travis jobs
  @ 2020-02-20 19:38  0%             ` Jeremy Plsek
  0 siblings, 0 replies; 200+ results
From: Jeremy Plsek @ 2020-02-20 19:38 UTC (permalink / raw)
  To: David Marchand
  Cc: ci, Thomas Monjalon, dev, Michael Santana, Aaron Conole,
	Bruce Richardson

[-- Attachment #1: Type: text/plain, Size: 3853 bytes --]

On Thu, Feb 20, 2020 at 11:02 AM David Marchand
<david.marchand@redhat.com> wrote:
>
> On Thu, Feb 20, 2020 at 3:35 PM Aaron Conole <aconole@redhat.com> wrote:
> >
> > David Marchand <david.marchand@redhat.com> writes:
> >
> > > On Thu, Feb 20, 2020 at 11:42 AM Thomas Monjalon <thomas@monjalon.net> wrote:
> > >>
> > >> 19/02/2020 22:39, Aaron Conole:
> > >> > David Marchand <david.marchand@redhat.com> writes:
> > >> >
> > >> > > Let's prune the jobs list to limit the amount of time spent by the robot
> > >> > > in Travis.
> > >> > >
> > >> > > Since meson enables automatically the relevant components, there is not
> > >> > > much gain in testing with extra_packages vs required_packages only.
> > >> > >
> > >> > > For a given arch/compiler/env combination, compilation is first tested
> > >> > > in all jobs that run tests or build the docs or run the ABI checks.
> > >> > > In the same context, for jobs that accumulates running tests, building
> > >> > > the docs etc..., those steps are independent and can be split to save
> > >> > > some cpu on Travis.
> > >> > >
> > >> > > With this, we go down from 21 to 15 jobs.
> > >> > >
> > >> > > Note: this patch requires a flush of the existing caches in Travis.
> > >> > >
> > >> > > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > >> > > ---
> > >> >
> > >> > In general, I think the idea with required vs. extra was to have a build
> > >> > that did the minimum required, and one that did all the packages (to
> > >> > allow a minimum vs. full DPDK).
> > >> >
> > >> > At least, that's from
> > >> > http://mails.dpdk.org/archives/dev/2019-January/124007.html
> > >>
> > >> I think the benefit of a minimum build is to have a quick report,
> > >> and easy to setup.
> > >
> > > Yes, Travis serves as a first gate when submitting patches.
> > > But since Travis is best effort/free, we can't have a full coverage.
> > >
> > >
> > >> > Not sure if that's still something anyone cares about.
> > >>
> > >> Given that Travis knows how to satisfy the dependencies,
> > >> and that we must wait for all jobs to finish,
> > >> I don't see any benefit of a minimal setup.
> > >
> > > This minimal setup also tests that dpdk dependencies are correct.
> > > If a change makes something rely on libX and libX is in the packages
> > > always installed in Travis, the missing dependency would not get
> > > caught.
> > >
> > > But here, this adds too many jobs.
> > >
> > > UNH, Intel and other CIs should step in and fill this kind of gap.
> >
> > Okay, makes sense to me.  Are one of these CI providers offering to
> > cover this?
>
> Maybe it is already covered, the best is to ask, so sending to ci@dpdk.org.
>
> For the CI guys, which packages are installed on the systems/vms that
> do compilation tests?

For our compile tests, we compile with pretty much all dpdk
dependencies that can easily be installed from the distro's repository
(the dependencies we installed are based on the meson output). The
thought process was to test compiling as much of dpdk as possible
(with constraints mentioned before).

Here are the dependencies we install on some of the setups:

Ubuntu 18.04: make gcc ninja-build pkg-config libnuma-dev
librdmacm-dev librdmacm1 rdma-core libelf-dev libmnl-dev libpcap-dev
libcrypto++-dev libjansson-dev
(meson installed with pip)

CentOS 8 and Fedora 31: diffutils gcc make ninja-build meson
pkg-config numactl-devel librdmacm rdma-core-devel
elfutils-libelf-devel libmnl-devel libpcap-devel jansson-devel

openSuse Leap 15: gcc make ninja pkg-config libnuma-devel librdmacm1
rdma-core-devel libelf-devel libmnl-devel libpcap-devel
libjansson-devel
(meson installed with pip)

> Is it possible to have a summary of the different setups?
>
I've attached an overview/summary of what we do at the UNH-IOL DPDK
Community Lab.
>
> Thanks.

>
> --
> David Marchand
>

[-- Attachment #2: DPDK Lab Summary February 2020.pdf --]
[-- Type: application/pdf, Size: 846111 bytes --]

^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] build: fix experimental library versioning
  @ 2020-02-21 16:41  0%   ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-02-21 16:41 UTC (permalink / raw)
  To: Ferruh Yigit
  Cc: Thomas Monjalon, Neil Horman, Bruce Richardson, dev, Kinsella,
	Ray, Luca Boccassi, Kevin Traynor

On Thu, Feb 20, 2020 at 8:55 PM Ferruh Yigit <ferruh.yigit@intel.com> wrote:
>
> The problem occurred when workaround that makes soname two digits
> applied. With this change for the ABI version "20.0.1" the experimental
> library version become ".so.2001".
> After workaround removed in ABI version 21.0, the experimental library
> version will become ".so.210".
> "2001" is bigger value than "201" although it is a previous version of
> the library version, this can break the version comparisons.
>
> To fix this, introducing a temporary sub level versioning for the
> experimental libraries, so that minor version comparison will continue
> to work.
>
> After change experimental libraries will follow below versioning:
>
> DPDK version  ABI version  soname       library name
> ------------  -----------  ------       ------------
> DPDK 19.11     20.0        .so.0.200    .so.0.200
> DPDK 20.02     20.0.1      .so.0.200.1  .so.0.200.1
> DPDK 20.05     20.0.2      .so.0.200.2  .so.0.200.2
> DPDK 20.11     21.0        .so.0.210    .so.0.210
> DPDK 21.02     21.1        .so.0.211    .so.0.211
>
> Note: After workaround removed in DPDK 20.11 and soname switch back to
> single digit this patch won't work and needs to be updated.
>
> Fixes: f26c2b39b271 ("build: fix soname info for 19.11 compatibility")
>
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>

Acked-by: Luca Boccassi <bluca@debian.org>
Acked-by: Ray Kinsella <mdr@ashroe.eu>


Applied.

-- 
David Marchand


^ permalink raw reply	[relevance 0%]

* Re: [dpdk-dev] [PATCH] devtools: skip experimental libraries in ABI check
  2020-02-21 16:30  4%   ` Thomas Monjalon
@ 2020-02-21 16:40  4%     ` David Marchand
  0 siblings, 0 replies; 200+ results
From: David Marchand @ 2020-02-21 16:40 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Ferruh Yigit, Dodji Seketeli

On Fri, Feb 21, 2020 at 5:30 PM Thomas Monjalon <thomas@monjalon.net> wrote:
>
> 21/02/2020 17:13, Ferruh Yigit:
> > On 2/21/2020 4:10 PM, David Marchand wrote:
> > > We don't provide ABI compatibility for experimental libraries.
> > > Skip those libraries by catching a soname containing a version starting
> > > with '0.'.
> >
> > I am not familiar with the script and how libabigail works, but +1 to the idea.
> >
> > >
> > > Align the special case for the glue libraries by using the soname too.
> > > Once libabigail has support for it, we will have a single type of rule.
> > >
> > > Fixes: 777014e56d07 ("devtools: add ABI checks")
> > >
> > > Signed-off-by: David Marchand <david.marchand@redhat.com>
>
> Acked-by: Thomas Monjalon <thomas@monjalon.net>

Applied.



--
David Marchand


^ permalink raw reply	[relevance 4%]

* Re: [dpdk-dev] [PATCH 0/4] Extend --lcores to run on cores > RTE_MAX_LCORE
  @ 2020-02-21 16:38  3%           ` Stephen Hemminger
  0 siblings, 0 replies; 200+ results
From: Stephen Hemminger @ 2020-02-21 16:38 UTC (permalink / raw)
  To: Aaron Conole
  Cc: David Marchand, Song, Keesang, ktraynor, bluca, Thomas Monjalon,
	dev, ferruh.yigit, bruce.richardson, honnappa.nagarahalli, drc,
	stable, Grimm, Jon, Hollingsworth, Brent

On Fri, 21 Feb 2020 09:48:58 -0500
Aaron Conole <aconole@redhat.com> wrote:

> David Marchand <david.marchand@redhat.com> writes:
> 
> > On Fri, Feb 21, 2020 at 9:19 AM Song, Keesang <Keesang.Song@amd.com> wrote:  
> >>
> >> [AMD Official Use Only - Internal Distribution Only]  
> >
> > Please, get this header removed.
> > This is a public mailing list.
> >
> >  
> >> Thanks Thomas for bringing this up.
> >> I consider this is not a new feature, but rather a fix to address
> >> the issue with statically assigned maximum lcore limit on
> >> high-density CPU platform such as AMD Epyc.
> >> As I see a lot of DPDK adopters are still using LTS 18.11 & 19.11,
> >> and they have 1~2 yrs of lifetime left, we like to backport this to
> >> LTS 18.11 & 19.11 at least.  
> >
> > It is not a fix.
> >
> > The use of static arrays is a design choice that goes back to the
> > early days in dpdk.
> > The addition of --lcores came in after this, but it was introduced for
> > a different use case than placing lcores on any physical core.
> > And there was no claim that a core > RTE_MAX_LCORE would be usable.
> >
> >
> > When testing on a new hardware, it is normal to observe some limitations.
> > Running DPDK on those platforms should be possible: "should be"
> > because I do not have access to this hardware and saw neither tests
> > reports nor performance numbers.
> > Before this patch, the limitation is that on Epyc, cores >
> > RTE_MAX_LCORE are not usable.
> >
> >
> > Now, this change is quite constrained.
> > If we backport it, I don't expect issues in the main dpdk components
> > (based on code review and ovs tests with a RTE_MAX_LCORE set to 16 on
> > a 24 cores system).
> > There might be issues in some examples or not widely used library
> > which uses a physical core id instead of a lcore id.
> >
> >
> > This is the same recurring question "do we allow new features in a
> > stable branch?".  
> 
> Usually, the answer is 'no'.  But we do allow some "new" things to be
> backported (pci ids, etc) that might be required to enable older
> functionality.  Additionally, I'm sure if some feature were required to
> mitigate a CVE, we'd rather favor backporting it.
> 
> I guess we could pose a litmus test:
> 
>   1. Is the problem this feature solves so widespread that it needs to
>      be addressed ASAP?
>   2. Is there a known workaround to the problem this is solving?
>   3. How intrusive is the feature?
>   4. Is it shown to be stable in the mainline (number of fixes, testing,
>      etc)?
>   5. Is it constrained enough that we know we can support it with even
>      higher priority than other things?
> 
> Probably other questions that will need to be asked.
> 
> And even in that list of question, I'm not sure I'd be able to advocate
> backporting this in the upstream branches - it hasn't had much testing.
> It's unstable.  It's "difficult" to use.  It is not widespread that
> people have so many cores.  The workaround is much simpler than
> supporting this (recompile).
> 
> >
> > --
> > David Marchand  
> 

RTE_MAX_LCORES is exposed in API/ABI to application.
Many applications use that to size internal data structures.
Having rte_lcore_id() potentially return a larger value would cause
out of bounds access (and crash) in that application.

^ permalink raw reply	[relevance 3%]

* Re: [dpdk-dev] [PATCH] devtools: skip experimental libraries in ABI check
  @ 2020-02-21 16:30  4%   ` Thomas Monjalon
  2020-02-21 16:40  4%     ` David Marchand
  0 siblings, 1 reply; 200+ results
From: Thomas Monjalon @ 2020-02-21 16:30 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, Ferruh Yigit, dodji

21/02/2020 17:13, Ferruh Yigit:
> On 2/21/2020 4:10 PM, David Marchand wrote:
> > We don't provide ABI compatibility for experimental libraries.
> > Skip those libraries by catching a soname containing a version starting
> > with '0.'.
> 
> I am not familiar with the script and how libabigail works, but +1 to the idea.
> 
> > 
> > Align the special case for the glue libraries by using the soname too.
> > Once libabigail has support for it, we will have a single type of rule.
> > 
> > Fixes: 777014e56d07 ("devtools: add ABI checks")
> > 
> > Signed-off-by: David Marchand <david.marchand@redhat.com>

Acked-by: Thomas Monjalon <thomas@monjalon.net>



^ permalink raw reply	[relevance 4%]

Results 6201-6400 of ~18000   |  | reverse | sort options + mbox downloads above
-- links below jump to the message on this page --
2019-12-02 15:35     [dpdk-dev] [PATCH 0/4] Extend --lcores to run on cores > RTE_MAX_LCORE David Marchand
2020-01-21  0:24     ` Thomas Monjalon
2020-02-21  8:04       ` Thomas Monjalon
2020-02-21  8:19         ` Song, Keesang
2020-02-21  9:40           ` David Marchand
2020-02-21 14:48             ` Aaron Conole
2020-02-21 16:38  3%           ` Stephen Hemminger
2019-12-20 15:20     [dpdk-dev] [PATCH] add ABI checks David Marchand
2020-02-04 12:44     ` [dpdk-dev] [PATCH v2 4/4] " Trahe, Fiona
2020-02-04 15:52       ` Trahe, Fiona
2020-02-04 15:59         ` Thomas Monjalon
2020-02-04 17:46           ` Trahe, Fiona
2020-02-13 14:51             ` Kusztal, ArkadiuszX
2020-03-16 12:57  8%           ` Trahe, Fiona
2020-03-16 13:09  4%             ` Thomas Monjalon
2020-03-17 13:27  4%               ` Kusztal, ArkadiuszX
2020-03-17 15:10  4%                 ` Thomas Monjalon
2020-03-17 19:10  4%                   ` Kusztal, ArkadiuszX
2020-01-30 14:20     [dpdk-dev] [PATCH] doc: deprecate using MAX values as array size Ferruh Yigit
2020-02-21 10:25     ` Ferruh Yigit
2020-02-24  6:18  0%   ` Akhil Goyal
2020-02-25 11:03  0%     ` Thomas Monjalon
2020-02-24  8:51  0%   ` Andrew Rybchenko
2020-02-25 13:52  0% ` David Marchand
2020-02-25 14:53  0% ` David Marchand
2020-01-30 16:58     [dpdk-dev] [PATCH] doc: deprecation notice to move igb_uio to a new repo jerinj
2020-02-24  7:03  0% ` [dpdk-dev] [dpdk-techboard] " Maxime Coquelin
2020-02-05 15:17     [dpdk-dev] [PATCH] doc: alias to experimental tag for stable apis Ray Kinsella
2020-02-18 10:46     ` [dpdk-dev] [PATCH v4] " Ray Kinsella
2020-02-21 17:11  0%   ` Ferruh Yigit
2020-02-25 14:22  0%   ` Kevin Traynor
2020-02-25 15:35  0% ` [dpdk-dev] [PATCH] " Neil Horman
2020-02-25 17:57  0%   ` David Marchand
2020-02-14  5:54     [dpdk-dev] Questions about rte_timer APIs Honnappa Nagarahalli
2020-02-25 23:56  3% ` Honnappa Nagarahalli
2020-02-26 16:57  0%   ` Carrillo, Erik G
2020-02-27 16:58  0%     ` Honnappa Nagarahalli
2020-02-17 15:38     [dpdk-dev] [PATCH] doc: plan splitting the ethdev ops struct Ferruh Yigit
2020-02-18  5:07     ` Jerin Jacob
2020-02-25 12:42  0%   ` Ferruh Yigit
2020-02-18  6:01     ` Stephen Hemminger
2020-02-21 10:40       ` Ferruh Yigit
2020-02-25 10:35  0%     ` Andrew Rybchenko
2020-02-25 11:07  3%       ` Ananyev, Konstantin
2020-02-25 11:19  0%         ` Andrew Rybchenko
2020-02-25 12:28  3%       ` Ferruh Yigit
2020-02-25 12:44  3% ` [dpdk-dev] [PATCH v2] " Ferruh Yigit
2020-02-25 15:51  3%   ` Andrew Rybchenko
2020-02-25 16:13  3%     ` Ferruh Yigit
2020-02-25 16:41  0%       ` Andrew Rybchenko
2020-02-25 18:13  0%   ` David Marchand
2020-02-25 18:18  0%     ` Ferruh Yigit
2020-03-04  9:57  4%   ` [dpdk-dev] [PATCH v3] " Ferruh Yigit
2020-02-17 23:15     [dpdk-dev] ABI version of experimental libraries Thomas Monjalon
2020-02-19 12:43     ` Thomas Monjalon
2020-02-19 13:50       ` Ray Kinsella
2020-02-21 16:57  4%     ` Thomas Monjalon
2020-02-24  9:32  4%       ` Ray Kinsella
2020-02-19 18:53     [dpdk-dev] [PATCH v2 0/7] vfio/pci: SR-IOV support Alex Williamson
2020-02-25  2:33  0% ` Tian, Kevin
2020-03-05 17:33  3%   ` Alex Williamson
2020-03-06  9:21  0%     ` Tian, Kevin
2020-03-05  6:38  0% ` Vamsi Krishna Attunuru
2020-02-19 19:41     [dpdk-dev] [PATCH 0/4] Reorganise Travis jobs David Marchand
2020-02-19 19:41     ` [dpdk-dev] [PATCH 4/4] ci: reorganise " David Marchand
2020-02-19 21:39       ` Aaron Conole
2020-02-20 10:42         ` Thomas Monjalon
2020-02-20 12:22           ` David Marchand
2020-02-20 14:35             ` Aaron Conole
2020-02-20 16:01               ` David Marchand
2020-02-20 19:38  0%             ` [dpdk-dev] [dpdk-ci] " Jeremy Plsek
2020-02-20 13:18     [dpdk-dev] [PATCH] lib/cmdline_rdline: increase command line buf size Wisam Jaddo
2020-02-20 14:53     ` [dpdk-dev] [PATCH v3] cmdline: increase maximum line length Wisam Jaddo
2020-02-22 15:28  3%   ` David Marchand
2020-02-20 19:50     [dpdk-dev] ABI version of experimental libraries Ferruh Yigit
2020-02-20 19:54     ` [dpdk-dev] [PATCH] build: fix experimental library versioning Ferruh Yigit
2020-02-21 16:41  0%   ` David Marchand
2020-02-21 16:10     [dpdk-dev] [PATCH] devtools: skip experimental libraries in ABI check David Marchand
2020-02-21 16:13     ` Ferruh Yigit
2020-02-21 16:30  4%   ` Thomas Monjalon
2020-02-21 16:40  4%     ` David Marchand
2020-02-22 21:08     [dpdk-dev] [dpdk-announce] release candidate 20.02-rc4 Thomas Monjalon
2020-02-25  9:58     ` Ali Alnubani
2020-02-25 14:37  4%   ` Xu, Qian Q
2020-02-25 14:44  0%     ` Thomas Monjalon
2020-02-25 15:27  0%       ` Raslan Darawsheh
2020-02-23 10:59  8% [dpdk-dev] [PATCH v1] doc: update release notes for 20.02 John McNamara
2020-02-24 11:35  2% [dpdk-dev] [RFC 0/6] New sync modes for ring Konstantin Ananyev
2020-02-24 16:59  0% ` Stephen Hemminger
2020-02-24 17:59  0%   ` Jerin Jacob
2020-02-24 19:35  3%     ` Stephen Hemminger
2020-02-24 20:52  0%       ` Honnappa Nagarahalli
2020-02-25 11:45  0%         ` Ananyev, Konstantin
2020-02-25 13:41  3%       ` Ananyev, Konstantin
2020-02-27 10:31  0%         ` Jerin Jacob
2020-02-28  0:17  0%           ` David Christensen
2020-02-25  0:58  0%     ` Honnappa Nagarahalli
2020-02-25 15:14  0%       ` Ananyev, Konstantin
2020-03-25 20:43  0% ` Honnappa Nagarahalli
2020-03-26  1:50  3%   ` Ananyev, Konstantin
2020-03-30 21:29  0%     ` Honnappa Nagarahalli
2020-03-30 23:37  0%       ` Honnappa Nagarahalli
2020-03-31 17:21  0%         ` Ananyev, Konstantin
2020-03-31 16:43  3% ` [dpdk-dev] [PATCH v1 0/8] " Konstantin Ananyev
2020-04-02 22:09  3%   ` [dpdk-dev] [PATCH v2 0/9] " Konstantin Ananyev
2020-04-02 22:09  1%     ` [dpdk-dev] [PATCH v2 3/9] ring: introduce RTS ring mode Konstantin Ananyev
2020-04-03 17:42  3%     ` [dpdk-dev] [PATCH v3 0/9] New sync modes for ring Konstantin Ananyev
2020-04-03 17:42           ` [dpdk-dev] [PATCH v3 2/9] ring: prepare ring to allow new sync schemes Konstantin Ananyev
2020-04-08  4:59  3%         ` Honnappa Nagarahalli
2020-04-03 17:42  1%       ` [dpdk-dev] [PATCH v3 3/9] ring: introduce RTS ring mode Konstantin Ananyev
2020-04-04 17:27  0%         ` Wang, Haiyue
2020-04-08  5:00  0%         ` Honnappa Nagarahalli
2020-02-25 22:59  4% [dpdk-dev] [dpdk-announce] DPDK 20.02 released Thomas Monjalon
2020-02-26 13:38 10% [dpdk-dev] [PATCH] version: 20.05-rc0 David Marchand
2020-02-26 13:55  0% ` Thomas Monjalon
2020-02-26 14:01  0%   ` David Marchand
2020-02-27 11:17  3%     ` Bruce Richardson
2020-02-27 11:23  3%       ` David Marchand
2020-02-27 11:26  4%         ` Thomas Monjalon
2020-02-27 11:01  0%   ` David Marchand
2020-02-27 11:31  0%     ` David Marchand
2020-02-29 10:27     [dpdk-dev] [dpdk v1] net/mlx5: fix possible building error xiangxia.m.yue
2020-03-01 17:09     ` Ali Alnubani
2020-03-02  0:22  3%   ` Tonghao Zhang
2020-03-02  7:35  0%     ` Ali Alnubani
2020-03-02  8:13  0%       ` Tonghao Zhang
2020-03-02  1:57     [dpdk-dev] [PATCH] mempool: sort the rte_mempool_ops by name xiangxia.m.yue
2020-03-06 13:36     ` [dpdk-dev] [PATCH dpdk-dev v3] " xiangxia.m.yue
2020-03-06 13:37       ` Jerin Jacob
2020-03-07 12:51         ` Andrew Rybchenko
2020-03-07 12:54           ` Andrew Rybchenko
2020-03-09  3:01             ` Tonghao Zhang
2020-03-09  8:27  3%           ` Olivier Matz
2020-03-09  8:55  0%             ` Tonghao Zhang
2020-03-09  9:05  0%               ` Olivier Matz
2020-03-09 13:15  0%               ` David Marchand
2020-03-16  7:43  0%                 ` Tonghao Zhang
2020-03-16  7:55  0%                   ` Olivier Matz
2020-03-24  9:35  0%             ` Andrew Rybchenko
2020-03-24 12:41  0%               ` Tonghao Zhang
2020-03-02 14:58     [dpdk-dev] [PATCH 00/16] NXP DPAAx fixes and enhancements Hemant Agrawal
2020-03-02 13:01  3% ` David Marchand
2020-03-05  9:06  3%   ` Hemant Agrawal (OSS)
2020-03-05  9:09  3%     ` David Marchand
2020-03-05  9:19  0%       ` Hemant Agrawal (OSS)
2020-03-06 10:12  3%         ` David Marchand
2020-03-10 10:36  3%           ` Dodji Seketeli
2020-04-07 10:25  3%             ` Hemant Agrawal
2020-04-07 12:20  0%               ` Thomas Monjalon
2020-04-08  7:20  4%               ` Dodji Seketeli
2020-04-08  7:52  0%                 ` Dodji Seketeli
2020-03-02 14:58     ` [dpdk-dev] [PATCH 11/16] net/dpaa: enable Tx queue taildrop Hemant Agrawal
2020-03-03 17:02       ` Ferruh Yigit
2020-03-05  6:49         ` Gagandeep Singh
2020-03-05 14:14  3%       ` Ferruh Yigit
2020-03-03 16:27     [dpdk-dev] [PATCH v1] mbuf: replace zero-length marker with unnamed union Gavin Hu
2020-03-07 15:56     ` [dpdk-dev] [PATCH v2] " Gavin Hu
2020-03-09  8:55       ` Ferruh Yigit
2020-03-09  9:45         ` Gavin Hu
2020-03-09 11:29           ` Ferruh Yigit
2020-03-09 13:30             ` Morten Brørup
2020-03-11  7:50               ` Gavin Hu
2020-03-11  9:04                 ` Morten Brørup
2020-03-11 12:07                   ` Bruce Richardson
2020-03-13  9:22                     ` Gavin Hu
2020-04-07 17:13                       ` Kevin Traynor
2020-04-08 15:04                         ` Gavin Hu
2020-04-08 15:22  3%                       ` [dpdk-dev] [dpdk-stable] " David Marchand
2020-03-05  8:53  4% [dpdk-dev] DPDK techboard minutes of February 26 Thomas Monjalon
2020-03-06 16:41     [dpdk-dev] [PATCH 0/4] Introduce IF proxy library Andrzej Ostruszka
2020-03-10 11:10     ` [dpdk-dev] [PATCH v2 " Andrzej Ostruszka
2020-03-25  8:08  3%   ` David Marchand
2020-03-25 11:11  4%     ` Morten Brørup
2020-03-26 17:42  3%       ` Andrzej Ostruszka
2020-03-26 12:41  3%     ` Andrzej Ostruszka
2020-03-30 19:23  3%       ` Andrzej Ostruszka
2020-03-09 14:14     [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
2020-03-09 14:14  1% ` [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework Haiyue Wang
2020-03-10  6:50     ` [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-10  6:50  1%   ` [dpdk-dev] [PATCH v2 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-16  5:52     ` [dpdk-dev] [PATCH v3 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-16  5:52  1%   ` [dpdk-dev] [PATCH v3 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-26  3:03     ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-26  3:03  1%   ` [dpdk-dev] [PATCH v4 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-26  7:15     ` [dpdk-dev] [PATCH v5 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-26  7:15  1%   ` [dpdk-dev] [PATCH v5 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-27  2:56     ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-27  2:56  1%   ` [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
     [not found]     <mailman.2366.1582638587.2727.dev@dpdk.org>
     [not found]     ` <d8993cb75592406a993e3119d45e906a@intel.com>
2020-03-10  2:55  0%   ` [dpdk-dev] dev Digest, Vol 288, Issue 27 Zhang, XiX
2020-03-10  6:50     [dpdk-dev] [PATCH] lib/librte_net/rte_ether.h:changed RTE_ETHER_MAX_LEN Muhammad Ahmad
2020-03-10 15:18  3% ` Stephen Hemminger
2020-03-11 21:58  2% [dpdk-dev] [PATCH v3 0/7] vfio/pci: SR-IOV support Alex Williamson
2020-03-19  6:32  0% ` Tian, Kevin
2020-03-19 13:11  0%   ` Alex Williamson
2020-03-12  7:44     [dpdk-dev] [PATCH v2 00/10] generic rte atomic APIs deprecate proposal Phil Yang
2020-03-17  1:17     ` [dpdk-dev] [PATCH v3 00/12] " Phil Yang
2020-03-17  1:17       ` [dpdk-dev] [PATCH v3 07/12] service: remove rte prefix from static functions Phil Yang
2020-04-03 11:57  3%     ` Van Haaren, Harry
2020-04-08 10:14  0%       ` Phil Yang
2020-04-08 10:36  0%         ` Van Haaren, Harry
2020-04-08 10:49  0%           ` Phil Yang
2020-03-12 17:20     [dpdk-dev] [PATCH 0/7] checking for owned ports in portmask Stephen Hemminger
2020-03-16 16:09     ` [dpdk-dev] [PATCH v2 0/6] check " Stephen Hemminger
2020-03-16 16:09       ` [dpdk-dev] [PATCH v2 1/6] rte_ethdev: add function to check if device is owned Stephen Hemminger
2020-04-01 21:42         ` Thomas Monjalon
2020-04-01 22:24  3%       ` Stephen Hemminger
2020-04-02  8:04  3%         ` Thomas Monjalon
2020-03-18 19:02     [dpdk-dev] [PATCH v1 00/32] DPDK Trace support jerinj
2020-03-25 21:15  1% ` [dpdk-dev] [PATCH v2 " jerinj
2020-03-29 14:43  1%   ` [dpdk-dev] [PATCH v3 00/33] " jerinj
2020-04-01  8:18  3%     ` David Marchand
2020-04-01 10:04  0%       ` Jerin Jacob
2020-04-01 14:12  0%         ` David Marchand
2020-04-01 14:16  0%           ` Thomas Monjalon
2020-04-03 15:36  1%     ` [dpdk-dev] [PATCH v4 " jerinj
2020-03-18 20:41  3% [dpdk-dev] [PATCH] cryptodev: version rte_cryptodev_info_get function Arek Kusztal
2020-03-19  8:28  4% [dpdk-dev] [PATCH] doc: prefer https when pointing to dpdk.org David Marchand
2020-03-19 10:46  0% ` [dpdk-dev] [dpdk-stable] " Kevin Traynor
2020-03-19 14:44  3% [dpdk-dev] [PATCH] devtools: fix check symbol change script Nithin Dabilpuram
2020-03-19 14:56  0% ` David Marchand
2020-03-19 15:40  0%   ` Neil Horman
2020-03-19 15:45  0%     ` [dpdk-dev] [EXT] " Nithin Dabilpuram
2020-03-19 18:59  0%       ` Neil Horman
2020-03-19 15:49  0%     ` [dpdk-dev] " Bing Zhao
2020-03-22 14:37  0% ` Jerin Jacob
2020-03-23 11:56  3% ` [dpdk-dev] [PATCH v2] " Nithin Dabilpuram
2020-03-23 13:19  0%   ` David Marchand
2020-03-19 17:44     [dpdk-dev] [PATCH v1] usertools/dpdk-setup.sh: fix dpdk-setup's behaviour on non-alphanumeric inputs Sarosh Arif
2020-03-19 18:20  3% ` Stephen Hemminger
2020-03-20  0:12  1% [dpdk-dev] [PATCH] eal: reorganize directories layout Thomas Monjalon
2020-03-27  1:15     ` [dpdk-dev] [PATCH v2 0/8] " Thomas Monjalon
2020-03-27  1:15  3%   ` [dpdk-dev] [PATCH v2 6/8] eal: move common header files Thomas Monjalon
2020-03-20 16:41  3% [dpdk-dev] [RFC] ring: make ring implementation non-inlined Konstantin Ananyev
2020-03-20 17:54  0% ` Stephen Hemminger
2020-03-21  1:03  0%   ` Ananyev, Konstantin
2020-03-25 21:09  4% ` Jerin Jacob
2020-03-26  0:28  0%   ` Ananyev, Konstantin
2020-03-26  8:04  4%   ` Morten Brørup
2020-03-31 23:25  5%     ` Thomas Monjalon
2020-03-24 11:49     [dpdk-dev] [PATCH 00/17] Add CPU flags Kevin Laatz
2020-03-25 11:10     ` [dpdk-dev] [PATCH v2] eal/cpuflags: add x86 based cpu flags Kevin Laatz
2020-03-27 12:24  3%   ` David Marchand
2020-03-27 13:18  5%     ` Van Haaren, Harry
2020-03-27 15:04  0%       ` David Marchand
2020-03-27 13:44  0%     ` Neil Horman
2020-03-27 14:15  4%       ` Thomas Monjalon
2020-03-27 14:32  3%         ` Van Haaren, Harry
2020-03-27 14:36  3%           ` Ray Kinsella
2020-03-27 15:19  3%             ` Thomas Monjalon
2020-03-29  6:47     [dpdk-dev] [PATCH v1 0/4] add RegEx class Ori Kam
2020-04-04 14:27     ` [dpdk-dev] [EXT] [PATCH v1 4/4] regexdev: implement regex rte level functions Pavan Nikhilesh Bhagavatula
2020-04-05 15:04       ` Ori Kam
2020-04-06 11:16  3%     ` Thomas Monjalon
2020-04-06 12:33  3%       ` Pavan Nikhilesh Bhagavatula
2020-04-06 13:14  3%         ` Thomas Monjalon
2020-04-06 13:20  0%           ` Jerin Jacob
2020-04-06 13:22  0%           ` Pavan Nikhilesh Bhagavatula
2020-04-06 13:36  0%             ` Thomas Monjalon
2020-04-06 13:50  0%               ` Pavan Nikhilesh Bhagavatula
2020-04-06 14:00  0%                 ` Thomas Monjalon
2020-04-06 18:53  0%                   ` Ori Kam
2020-03-30  4:10     [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management Dmitry Kozlyuk
2020-03-30  4:10  3% ` [dpdk-dev] [RFC PATCH 7/9] eal/windows: fix rte_page_sizes with Clang on Windows Dmitry Kozlyuk
2020-03-31 12:01  1% [dpdk-dev] [PATCH v1] doc: use svg file type for ice nic Haiyue Wang
2020-03-31 12:06  1% ` [dpdk-dev] [PATCH v2] doc: use svg file type for ice Haiyue Wang
2020-04-01  5:44  1% ` [dpdk-dev] [PATCH v3] doc: use svg file type for ice PMD Haiyue Wang
2020-03-31 17:05  7% [dpdk-dev] /validate-abi.sh complains [PATCH v1 3/8] ring: introduce RTS ring mode Ananyev, Konstantin
2020-03-31 19:22  8% ` Thomas Monjalon
2020-03-31 19:24  4%   ` Thomas Monjalon
2020-04-01 12:52  4%     ` Neil Horman
2020-04-06 14:02  4%       ` Thomas Monjalon
2020-04-06 14:36  4%         ` Neil Horman
2020-04-07  7:32  4%           ` Ray Kinsella
2020-04-07 11:31  4%             ` Neil Horman
2020-04-01  6:38  9% ` David Marchand
2020-04-02 12:36  4%   ` Ananyev, Konstantin
2020-04-02 13:13  4%     ` Dodji Seketeli
2020-04-02 14:27  4%     ` David Marchand
2020-04-02 15:25  4%       ` Ananyev, Konstantin
2020-04-01  9:33     [dpdk-dev] [RFC] ethdev: use special speed for virtual Ethernet devices Morten Brørup
2020-04-02 13:50     ` [dpdk-dev] [RFC] ethdev: use special speed for virtual Ethernetdevices Morten Brørup
2020-04-02 20:41       ` Ivan Dyukov
     [not found]         ` <CGME20200402205851eucas1p15d9b25f7e5238379754bd0959b04adc8@eucas1p1.samsung.com>
2020-04-02 20:58           ` Thomas Monjalon
2020-04-03  8:05             ` Ivan Dyukov
2020-04-03  9:45  3%           ` Morten Brørup
2020-04-03 11:01  0%             ` Thomas Monjalon
2020-04-03 16:36     [dpdk-dev] [PATCH v2 0/4] introduce multi-function processing support David Coyle
2020-04-06 14:28     ` Ferruh Yigit
2020-04-07 11:27       ` Coyle, David
2020-04-07 18:05  2%     ` Trahe, Fiona
2020-04-06 19:34 38% [dpdk-dev] [PATCH] Remove abi_versioning.sh from tree Neil Horman
2020-04-07  7:36  4% ` David Marchand
2020-04-07 11:33  0%   ` Neil Horman
2020-04-07 11:40  0%     ` David Marchand
2020-04-07 11:58  5%     ` Thomas Monjalon
2020-04-07 19:52  3%       ` Neil Horman
2020-04-08 14:34  0%       ` Ray Kinsella
2020-04-08 14:50  0%   ` Ray Kinsella
2020-04-08 14:49  0% ` Ray Kinsella

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).