Netdev List
 help / color / mirror / Atom feed
* Re: [BUG BISECT] NFSv4 client fails on Flush Journal to Persistent Storage
From: Krzysztof Kozlowski @ 2018-06-07 11:22 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, J. Bruce Fields, Jeff Layton,
	David S. Miller, linux-nfs, netdev, linux-kernel,
	linux-samsung-soc@vger.kernel.org
In-Reply-To: <CAJKOXPd2rntNOpU1quR9Zm_J22+=pEaj4ZTC_tdZ0zcRYUciFg@mail.gmail.com>

On Thu, Jun 7, 2018 at 1:19 PM, Krzysztof Kozlowski <krzk@kernel.org> wrote:
> Hi,
>
> When booting my boards under recent linux-next, I see failures of systemd:
>
> [FAILED] Failed to start Flush Journal to Persistent Storage.
> See 'systemctl status systemd-journal-flush.service' for details.
>          Starting Create Volatile Files and Directories...
> [**    ] A start job is running for Create V… [  223.209289] nfs:
> server 192.168.1.10 not responding, still trying
> [  223.209377] nfs: server 192.168.1.10 not responding, still trying
>
> Effectively the boards fails to boot. Example is here:
> https://krzk.eu/#/builders/1/builds/2157
>
> This was bisected to:
> commit 37ac86c3a76c113619b7d9afe0251bbfc04cb80a
> Author: Chuck Lever <chuck.lever@oracle.com>
> Date:   Fri May 4 15:34:53 2018 -0400
>
>     SUNRPC: Initialize rpc_rqst outside of xprt->reserve_lock
>
>     alloc_slot is a transport-specific op, but initializing an rpc_rqst
>     is common to all transports. In addition, the only part of initial-
>     izing an rpc_rqst that needs serialization is getting a fresh XID.
>
>     Move rpc_rqst initialization to common code in preparation for
>     adding a transport-specific alloc_slot to xprtrdma.
>
>     Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>     Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
>
>
> Bisect log attached. Full configuration:
> 1. exynos_defconfig
> 2. ARMv7, octa-core, Exynos5422 and Exynos4412 (Odroid XU3, U3 and others)
> 3. NFSv4 client (from Raspberry Pi)
>
> Let me know if you need any more information.

Ah, I forgot maybe the most important information in reproducment -
client uses NFS root (NFSv4).

Best regards,
Krzysztof

^ permalink raw reply

* [BUG BISECT] NFSv4 client fails on Flush Journal to Persistent Storage
From: Krzysztof Kozlowski @ 2018-06-07 11:19 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, J. Bruce Fields, Jeff Layton,
	David S. Miller, linux-nfs, netdev, linux-kernel,
	linux-samsung-soc@vger.kernel.org

[-- Attachment #1: Type: text/plain, Size: 1514 bytes --]

Hi,

When booting my boards under recent linux-next, I see failures of systemd:

[FAILED] Failed to start Flush Journal to Persistent Storage.
See 'systemctl status systemd-journal-flush.service' for details.
         Starting Create Volatile Files and Directories...
[**    ] A start job is running for Create V… [  223.209289] nfs:
server 192.168.1.10 not responding, still trying
[  223.209377] nfs: server 192.168.1.10 not responding, still trying

Effectively the boards fails to boot. Example is here:
https://krzk.eu/#/builders/1/builds/2157

This was bisected to:
commit 37ac86c3a76c113619b7d9afe0251bbfc04cb80a
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Fri May 4 15:34:53 2018 -0400

    SUNRPC: Initialize rpc_rqst outside of xprt->reserve_lock

    alloc_slot is a transport-specific op, but initializing an rpc_rqst
    is common to all transports. In addition, the only part of initial-
    izing an rpc_rqst that needs serialization is getting a fresh XID.

    Move rpc_rqst initialization to common code in preparation for
    adding a transport-specific alloc_slot to xprtrdma.

    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>


Bisect log attached. Full configuration:
1. exynos_defconfig
2. ARMv7, octa-core, Exynos5422 and Exynos4412 (Odroid XU3, U3 and others)
3. NFSv4 client (from Raspberry Pi)

Let me know if you need any more information.

Best regards,
Krzysztof

[-- Attachment #2: log.txt --]
[-- Type: text/plain, Size: 5666 bytes --]

git bisect start
# good: [c64d4419a17cfb39a5b573f9016cd02ade4c9a64] mtd: cfi_cmdset_0002: Change erase one block to enable XIP once
git bisect good c64d4419a17cfb39a5b573f9016cd02ade4c9a64
# good: [56c6855c81c8a6828b5d65aa974cd50f4b67760c] mtd: spi-nor: Add Micron MT25QU02 support
git bisect good 56c6855c81c8a6828b5d65aa974cd50f4b67760c
# bad: [2b70a7bd4673b6dcf2763888d0b172a40dd49434] Merge remote-tracking branch 'block/for-next'
git bisect bad 2b70a7bd4673b6dcf2763888d0b172a40dd49434
# bad: [25350cbeef4a3ec943754c4aa4c8ac1aaa64c7a2] Merge remote-tracking branch 'nand/nand/next'
git bisect bad 25350cbeef4a3ec943754c4aa4c8ac1aaa64c7a2
# good: [311da4975894aab7a4bb94aa83f38f052d7ffda4] Merge branch 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
git bisect good 311da4975894aab7a4bb94aa83f38f052d7ffda4
# bad: [7d470f95b4ccd3244759524f6cc9a76a2a34a9c6] Merge remote-tracking branch 'printk/for-next'
git bisect bad 7d470f95b4ccd3244759524f6cc9a76a2a34a9c6
# good: [8a3ab2f38f1669e3be6433a1f6b82a077b38c4c7] brcmfmac: trigger memory dump upon firmware halt signal
git bisect good 8a3ab2f38f1669e3be6433a1f6b82a077b38c4c7
# good: [7fa76d777ec53eeece1546b737a3b93b37639575] netdevsim: Add extack error message for devlink reload
git bisect good 7fa76d777ec53eeece1546b737a3b93b37639575
# bad: [1fe087da59fde2cce4cf8e0a1c78b3279fb7ea44] Merge remote-tracking branch 'fbdev/fbdev-for-next'
git bisect bad 1fe087da59fde2cce4cf8e0a1c78b3279fb7ea44
# bad: [9d85b2fee6616994759eb4599c886af510ded175] Merge remote-tracking branch 'pci/next'
git bisect bad 9d85b2fee6616994759eb4599c886af510ded175
# good: [13fbadcd512c225c907d6e8147fb48a88114bf03] Merge branch 'pci/sparc'
git bisect good 13fbadcd512c225c907d6e8147fb48a88114bf03
# good: [741f8e7ecc2c6414cff442ec8eb07dcfe4481533] Merge branch 'lorenzo/pci/hv'
git bisect good 741f8e7ecc2c6414cff442ec8eb07dcfe4481533
# good: [1c2bef0a3fd14287a66edd7ead57fd2e439485a2] Merge branch 'lorenzo/pci/rcar'
git bisect good 1c2bef0a3fd14287a66edd7ead57fd2e439485a2
# good: [e52d38f4abf49f8b63a6ad0ce21e5f495c15897f] Merge branch 'lorenzo/pci/rockchip'
git bisect good e52d38f4abf49f8b63a6ad0ce21e5f495c15897f
# good: [73144d77cb87d60b4bcab6992a62d6787b09dcf0] Merge branch 'lorenzo/pci/vmd'
git bisect good 73144d77cb87d60b4bcab6992a62d6787b09dcf0
# good: [82e1719c4cd65bd7f7847d6c02376cfca3d5e793] PCI: Clean up whitespace in quirks.c
git bisect good 82e1719c4cd65bd7f7847d6c02376cfca3d5e793
# good: [0ecda3a087462eb89c1d9227deea998d8cd014e8] Merge branch 'pci/kconfig'
git bisect good 0ecda3a087462eb89c1d9227deea998d8cd014e8
# good: [488ad6d3678beee65bcd74e6a9764bd7cee9d3d3] Merge branch 'pci/trivial'
git bisect good 488ad6d3678beee65bcd74e6a9764bd7cee9d3d3
# good: [885892fb378dc096693557ba4f2b875188619b36] mlx4_core: restore optimal ICM memory allocation
git bisect good 885892fb378dc096693557ba4f2b875188619b36
# good: [488ad6d3678beee65bcd74e6a9764bd7cee9d3d3] Merge branch 'pci/trivial'
git bisect good 488ad6d3678beee65bcd74e6a9764bd7cee9d3d3
# good: [0ecda3a087462eb89c1d9227deea998d8cd014e8] Merge branch 'pci/kconfig'
git bisect good 0ecda3a087462eb89c1d9227deea998d8cd014e8
# good: [82e1719c4cd65bd7f7847d6c02376cfca3d5e793] PCI: Clean up whitespace in quirks.c
git bisect good 82e1719c4cd65bd7f7847d6c02376cfca3d5e793
# good: [1c2bef0a3fd14287a66edd7ead57fd2e439485a2] Merge branch 'lorenzo/pci/rcar'
git bisect good 1c2bef0a3fd14287a66edd7ead57fd2e439485a2
# good: [87cb5ac9cece9f0f75d0532fa2afcbf871f6b72e] Merge remote-tracking branch 'arm-soc/for-next'
git bisect good 87cb5ac9cece9f0f75d0532fa2afcbf871f6b72e
# good: [64eec192d609531b0c173c5b4885832372fb2a4c] Merge remote-tracking branch 'powerpc/next'
git bisect good 64eec192d609531b0c173c5b4885832372fb2a4c
# good: [dd8c1fd2071de3a02ea60e3fa68be24c1e89945e] Merge remote-tracking branch 'jfs/jfs-next'
git bisect good dd8c1fd2071de3a02ea60e3fa68be24c1e89945e
# bad: [6125a3dab21f1939dae7e836105dea0c9c465db4] Merge remote-tracking branch 'orangefs/for-next'
git bisect bad 6125a3dab21f1939dae7e836105dea0c9c465db4
# good: [3f0b3cf46e0542ac4b4241c579b944b755d11b67] NFS: Filter cache invalidation when holding a delegation
git bisect good 3f0b3cf46e0542ac4b4241c579b944b755d11b67
# good: [28771950c592482ee86cb1c3b661688aec3c0d7d] svcrdma: Fix incorrect return value/type in svc_rdma_post_recvs
git bisect good 28771950c592482ee86cb1c3b661688aec3c0d7d
# bad: [8335640cf89faa0f4e39e73e314f3f3a22d776f3] xprtrdma: Add trace_xprtrdma_dma_map(mr)
git bisect bad 8335640cf89faa0f4e39e73e314f3f3a22d776f3
# bad: [0e0b854cfb3302b1907e9d3a927469b95710238f] xprtrdma: Clean up Receive trace points
git bisect bad 0e0b854cfb3302b1907e9d3a927469b95710238f
# bad: [0e0b854cfb3302b1907e9d3a927469b95710238f] xprtrdma: Clean up Receive trace points
git bisect bad 0e0b854cfb3302b1907e9d3a927469b95710238f
# good: [75bc37fefc4471e718ba8e651aa74673d4e0a9eb] Linux 4.17-rc4
git bisect good 75bc37fefc4471e718ba8e651aa74673d4e0a9eb
# bad: [0e0b854cfb3302b1907e9d3a927469b95710238f] xprtrdma: Clean up Receive trace points
git bisect bad 0e0b854cfb3302b1907e9d3a927469b95710238f
# good: [914fcad9873cbd46e3a4c3c31551b98b15a49079] xprtrdma: Fix max_send_wr computation
git bisect good 914fcad9873cbd46e3a4c3c31551b98b15a49079
# bad: [a9cde23ab7cdf5e4e93432dffd0e734267f2b745] SUNRPC: Add a ->free_slot transport callout
git bisect bad a9cde23ab7cdf5e4e93432dffd0e734267f2b745
# bad: [37ac86c3a76c113619b7d9afe0251bbfc04cb80a] SUNRPC: Initialize rpc_rqst outside of xprt->reserve_lock
git bisect bad 37ac86c3a76c113619b7d9afe0251bbfc04cb80a
# first bad commit: [37ac86c3a76c113619b7d9afe0251bbfc04cb80a] SUNRPC: Initialize rpc_rqst outside of xprt->reserve_lock

^ permalink raw reply

* [PATCH v4] selftests: add headers_install to lib.mk
From: Anders Roxell @ 2018-06-07 11:09 UTC (permalink / raw)
  To: yamada.masahiro, michal.lkml, shuah, bamv2005, brgl, pbonzini,
	akpm, rppt, aarcange
  Cc: linux-kbuild, linux-kernel, linux-kselftest, netdev,
	Anders Roxell
In-Reply-To: <20180413090351.25662-1-anders.roxell@linaro.org>

If the kernel headers aren't installed we can't build all the tests.
Add a new make target rule 'khdr' in the file lib.mk to generate the
kernel headers and that gets include for every test-dir Makefile that
includes lib.mk If the testdir in turn have its own sub-dirs the
top_srcdir needs to be set to the linux-rootdir to be able to generate
the kernel headers.

Signed-off-by: Anders Roxell <anders.roxell@linaro.org>
Reviewed-by: Fathi Boudra <fathi.boudra@linaro.org>
---
 Makefile                                           | 14 +-------------
 scripts/subarch.include                            | 13 +++++++++++++
 tools/testing/selftests/android/Makefile           |  2 +-
 tools/testing/selftests/android/ion/Makefile       |  2 ++
 tools/testing/selftests/futex/functional/Makefile  |  1 +
 tools/testing/selftests/gpio/Makefile              |  7 ++-----
 tools/testing/selftests/kvm/Makefile               |  7 ++-----
 tools/testing/selftests/lib.mk                     | 12 ++++++++++++
 tools/testing/selftests/net/Makefile               |  1 +
 .../selftests/networking/timestamping/Makefile     |  1 +
 tools/testing/selftests/vm/Makefile                |  4 ----
 11 files changed, 36 insertions(+), 28 deletions(-)
 create mode 100644 scripts/subarch.include

diff --git a/Makefile b/Makefile
index 6b9aea95ae3a..8050072300fa 100644
--- a/Makefile
+++ b/Makefile
@@ -286,19 +286,7 @@ KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
 KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
 export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
 
-# SUBARCH tells the usermode build what the underlying arch is.  That is set
-# first, and if a usermode build is happening, the "ARCH=um" on the command
-# line overrides the setting of ARCH below.  If a native build is happening,
-# then ARCH is assigned, getting whatever value it gets normally, and
-# SUBARCH is subsequently ignored.
-
-SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
-				  -e s/sun4u/sparc64/ \
-				  -e s/arm.*/arm/ -e s/sa110/arm/ \
-				  -e s/s390x/s390/ -e s/parisc64/parisc/ \
-				  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-				  -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
-				  -e s/riscv.*/riscv/)
+include scripts/subarch.include
 
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
diff --git a/scripts/subarch.include b/scripts/subarch.include
new file mode 100644
index 000000000000..650682821126
--- /dev/null
+++ b/scripts/subarch.include
@@ -0,0 +1,13 @@
+# SUBARCH tells the usermode build what the underlying arch is.  That is set
+# first, and if a usermode build is happening, the "ARCH=um" on the command
+# line overrides the setting of ARCH below.  If a native build is happening,
+# then ARCH is assigned, getting whatever value it gets normally, and
+# SUBARCH is subsequently ignored.
+
+SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
+				  -e s/sun4u/sparc64/ \
+				  -e s/arm.*/arm/ -e s/sa110/arm/ \
+				  -e s/s390x/s390/ -e s/parisc64/parisc/ \
+				  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+				  -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
+				  -e s/riscv.*/riscv/)
diff --git a/tools/testing/selftests/android/Makefile b/tools/testing/selftests/android/Makefile
index 72c25a3cb658..d9a725478375 100644
--- a/tools/testing/selftests/android/Makefile
+++ b/tools/testing/selftests/android/Makefile
@@ -6,7 +6,7 @@ TEST_PROGS := run.sh
 
 include ../lib.mk
 
-all:
+all: khdr
 	@for DIR in $(SUBDIRS); do		\
 		BUILD_TARGET=$(OUTPUT)/$$DIR;	\
 		mkdir $$BUILD_TARGET  -p;	\
diff --git a/tools/testing/selftests/android/ion/Makefile b/tools/testing/selftests/android/ion/Makefile
index e03695287f76..88cfe88e466f 100644
--- a/tools/testing/selftests/android/ion/Makefile
+++ b/tools/testing/selftests/android/ion/Makefile
@@ -10,6 +10,8 @@ $(TEST_GEN_FILES): ipcsocket.c ionutils.c
 
 TEST_PROGS := ion_test.sh
 
+KSFT_KHDR_INSTALL := 1
+top_srcdir = ../../../../..
 include ../../lib.mk
 
 $(OUTPUT)/ionapp_export: ionapp_export.c ipcsocket.c ionutils.c
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
index ff8feca49746..ad1eeb14fda7 100644
--- a/tools/testing/selftests/futex/functional/Makefile
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -18,6 +18,7 @@ TEST_GEN_FILES := \
 
 TEST_PROGS := run.sh
 
+top_srcdir = ../../../../..
 include ../../lib.mk
 
 $(TEST_GEN_FILES): $(HEADERS)
diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
index 1bbb47565c55..4665cdbf1a8d 100644
--- a/tools/testing/selftests/gpio/Makefile
+++ b/tools/testing/selftests/gpio/Makefile
@@ -21,11 +21,8 @@ endef
 CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
 LDLIBS += -lmount -I/usr/include/libmount
 
-$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
+$(BINARIES):| khdr
+$(BINARIES): ../../../gpio/gpio-utils.o
 
 ../../../gpio/gpio-utils.o:
 	make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
-
-../../../../usr/include/linux/gpio.h:
-	make -C ../../../.. headers_install INSTALL_HDR_PATH=$(shell pwd)/../../../../usr/
-
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index d9d00319b07c..bcb69380bbab 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -32,9 +32,6 @@ $(LIBKVM_OBJ): $(OUTPUT)/%.o: %.c
 $(OUTPUT)/libkvm.a: $(LIBKVM_OBJ)
 	$(AR) crs $@ $^
 
-$(LINUX_HDR_PATH):
-	make -C $(top_srcdir) headers_install
-
-all: $(STATIC_LIBS) $(LINUX_HDR_PATH)
+all: $(STATIC_LIBS)
 $(TEST_GEN_PROGS): $(STATIC_LIBS)
-$(TEST_GEN_PROGS) $(LIBKVM_OBJ): | $(LINUX_HDR_PATH)
+$(STATIC_LIBS):| khdr
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index 17ab36605a8e..0a8e75886224 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -16,8 +16,20 @@ TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS))
 TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED))
 TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES))
 
+top_srcdir ?= ../../../..
+include $(top_srcdir)/scripts/subarch.include
+ARCH		?= $(SUBARCH)
+
 all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES)
 
+.PHONY: khdr
+khdr:
+	make ARCH=$(ARCH) -C $(top_srcdir) headers_install
+
+ifdef KSFT_KHDR_INSTALL
+$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES):| khdr
+endif
+
 .ONESHELL:
 define RUN_TEST_PRINT_RESULT
 	TEST_HDR_MSG="selftests: "`basename $$PWD`:" $$BASENAME_TEST";	\
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 663e11e85727..d515dabc6b0d 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -15,6 +15,7 @@ TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx
 TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
 TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict
 
+KSFT_KHDR_INSTALL := 1
 include ../lib.mk
 
 $(OUTPUT)/reuseport_bpf_numa: LDFLAGS += -lnuma
diff --git a/tools/testing/selftests/networking/timestamping/Makefile b/tools/testing/selftests/networking/timestamping/Makefile
index a728040edbe1..14cfcf006936 100644
--- a/tools/testing/selftests/networking/timestamping/Makefile
+++ b/tools/testing/selftests/networking/timestamping/Makefile
@@ -5,6 +5,7 @@ TEST_PROGS := hwtstamp_config rxtimestamp timestamping txtimestamp
 
 all: $(TEST_PROGS)
 
+top_srcdir = ../../../../..
 include ../../lib.mk
 
 clean:
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index fdefa2295ddc..58759454b1d0 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -25,10 +25,6 @@ TEST_PROGS := run_vmtests
 
 include ../lib.mk
 
-$(OUTPUT)/userfaultfd: ../../../../usr/include/linux/kernel.h
 $(OUTPUT)/userfaultfd: LDLIBS += -lpthread
 
 $(OUTPUT)/mlock-random-test: LDLIBS += -lcap
-
-../../../../usr/include/linux/kernel.h:
-	make -C ../../../.. headers_install
-- 
2.17.1

^ permalink raw reply related

* Re: [PATCH v3] selftests: add headers_install to lib.mk
From: Anders Roxell @ 2018-06-07 11:07 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: Masahiro Yamada, Michal Marek, Shuah Khan, Bamvor Zhang, brgl,
	Paolo Bonzini, Andrew Morton, Mike Rapoport, aarcange,
	linux-kbuild, Linux Kernel Mailing List, linux-kselftest,
	Networking, alexei.starovoitov
In-Reply-To: <1a021bf3-cf93-aa12-c5a8-1ea6c7900fbb@iogearbox.net>

On 14 May 2018 at 21:20, Daniel Borkmann <daniel@iogearbox.net> wrote:
> On 05/14/2018 01:58 PM, Anders Roxell wrote:
>> If the kernel headers aren't installed we can't build all the tests.
>> Add a new make target rule 'khdr' in the file lib.mk to generate the
>> kernel headers and that gets include for every test-dir Makefile that
>> includes lib.mk If the testdir in turn have its own sub-dirs the
>> top_srcdir needs to be set to the linux-rootdir to be able to generate
>> the kernel headers.
>>
>> Signed-off-by: Anders Roxell <anders.roxell@linaro.org>
>> Reviewed-by: Fathi Boudra <fathi.boudra@linaro.org>
>> ---
>>  Makefile                                          | 14 +-------------
>>  scripts/subarch.include                           | 13 +++++++++++++
>>  tools/testing/selftests/android/Makefile          |  2 +-
>>  tools/testing/selftests/android/ion/Makefile      |  1 +
>>  tools/testing/selftests/bpf/Makefile              |  5 ++---
>>  tools/testing/selftests/futex/functional/Makefile |  1 +
>>  tools/testing/selftests/gpio/Makefile             |  7 ++-----
>>  tools/testing/selftests/kvm/Makefile              |  7 ++-----
>>  tools/testing/selftests/lib.mk                    | 10 ++++++++++
>>  tools/testing/selftests/vm/Makefile               |  4 ----
>>  10 files changed, 33 insertions(+), 31 deletions(-)
>>  create mode 100644 scripts/subarch.include
> [...]
>> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
>> index 438d4f93875b..9741609a0eb1 100644
>> --- a/tools/testing/selftests/bpf/Makefile
>> +++ b/tools/testing/selftests/bpf/Makefile
>> @@ -16,9 +16,8 @@ LDLIBS += -lcap -lelf -lrt -lpthread
>>  TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
>>  all: $(TEST_CUSTOM_PROGS)
>>
>> -$(TEST_CUSTOM_PROGS): urandom_read
>> -
>> -urandom_read: urandom_read.c
>> +$(TEST_CUSTOM_PROGS):| khdr
>> +$(TEST_CUSTOM_PROGS): urandom_read.c
>>       $(CC) -o $(TEST_CUSTOM_PROGS) -static $<
>>
>>  # Order correspond to 'make run_tests' order
>
> Can you elaborate on the error in BPF you're seeing that would force a
> headers_install for it?

BPF shouldn't be affected, a new revision of the patch does not touch
the bpf/Makefile.
I will send out a patch soon.

Cheers,
Anders

> Some people are running the tools/ infrastructure
> (incl. BPF kselftests) outside of kernel tree where this dependency would
> break their setup. Why BPF bits cannot be fixed otherwise?
>
> Thanks,
> Daniel

^ permalink raw reply

* Re: [RFC net-next] ipv4: Don't promote secondaries when flushing addresses
From: Michal Kubecek @ 2018-06-07 11:00 UTC (permalink / raw)
  To: netdev; +Cc: Jakub Sitnicki
In-Reply-To: <20180607101301.30439-1-jkbs@redhat.com>

On Thu, Jun 07, 2018 at 12:13:01PM +0200, Jakub Sitnicki wrote:
> Promoting secondary addresses on address removal makes flushing all
> addresses from a device with 1000's of them slow. This is because we
> cannot take down the secondary addresses when we are removing the
> primary one, which would make it faster.
> 
> However, the userspace, when performing a flush, will in the end remove
> all the addresses regardless of secondary address promotion taking
> place. Unfortunately the kernel currently cannot distinguish between a
> single address removal and a flush of all addresses.
> 
> To help with this case introduce a IFA_F_FLUSH flag that can be used by
> userspace to signal that a removal operation is being done because of a
> flush. When the flag is set, don't bother with secondary address
> promotion as we expect that secondary addresses will be removed soon as
> well.

Unless you intend to use the flag to allow deleting a specific address
with its secondaries (overriding promote_secondaries), maybe it would
be more practical to go even further and delete all addresses on the
interface if IFA_F_FLUSH is set so that userspace could delete all
addresses with one request.

Michal Kubecek

^ permalink raw reply

* [PATCH] selftests: bpf: fix urandom_read build issue
From: Anders Roxell @ 2018-06-07 10:57 UTC (permalink / raw)
  To: ast, daniel, shuah; +Cc: netdev, linux-kernel, linux-kselftest, Anders Roxell

gcc complains that urandom_read gets built twice.

gcc -o tools/testing/selftests/bpf/urandom_read
-static urandom_read.c -Wl,--build-id
gcc -Wall -O2 -I../../../include/uapi -I../../../lib -I../../../lib/bpf
-I../../../../include/generated  -I../../../include    urandom_read.c
urandom_read -lcap -lelf -lrt -lpthread -o
tools/testing/selftests/bpf/urandom_read
gcc: fatal error: input file
‘tools/testing/selftests/bpf/urandom_read’ is the
same as output file
compilation terminated.
../lib.mk:110: recipe for target
'tools/testing/selftests/bpf/urandom_read' failed
To fix this issue remove the urandom_read target and so target
TEST_CUSTOM_PROGS gets used.

Fixes: 81f77fd0deeb ("bpf: add selftest for stackmap with BPF_F_STACK_BUILD_ID")
Signed-off-by: Anders Roxell <anders.roxell@linaro.org>
---
 tools/testing/selftests/bpf/Makefile | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 607ed8729c06..67285591ffd7 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -16,10 +16,8 @@ LDLIBS += -lcap -lelf -lrt -lpthread
 TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
 all: $(TEST_CUSTOM_PROGS)
 
-$(TEST_CUSTOM_PROGS): urandom_read
-
-urandom_read: urandom_read.c
-	$(CC) -o $(TEST_CUSTOM_PROGS) -static $< -Wl,--build-id
+$(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c
+	$(CC) -o $@ -static $< -Wl,--build-id
 
 # Order correspond to 'make run_tests' order
 TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
-- 
2.17.1

^ permalink raw reply related

* [RFC net-next] ipv4: Don't promote secondaries when flushing addresses
From: Jakub Sitnicki @ 2018-06-07 10:13 UTC (permalink / raw)
  To: netdev

Promoting secondary addresses on address removal makes flushing all
addresses from a device with 1000's of them slow. This is because we
cannot take down the secondary addresses when we are removing the
primary one, which would make it faster.

However, the userspace, when performing a flush, will in the end remove
all the addresses regardless of secondary address promotion taking
place. Unfortunately the kernel currently cannot distinguish between a
single address removal and a flush of all addresses.

To help with this case introduce a IFA_F_FLUSH flag that can be used by
userspace to signal that a removal operation is being done because of a
flush. When the flag is set, don't bother with secondary address
promotion as we expect that secondary addresses will be removed soon as
well.

Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>

---

A benchmark involving a flush of 40,000 addresses from a dummy device
shows a x4 speed-up of the 'flush' operation. 'ip' had to be modified to
set the IFA_F_FLUSH flag for RTM_DELADDR requests issued for the
'flush':

  # time $IP -stats addr flush dev dum0

Before:

  real    0m30.596s
  user    0m0.000s
  sys     0m30.567s

After:

  real    0m7.601s
  user    0m0.000s
  sys     0m7.569s

It's also worth noting that promote_secondaries sysctl param is enabled by
default since systemd 216 thus making it the new "normal" on some distros.


 include/uapi/linux/if_addr.h |  1 +
 net/ipv4/devinet.c           | 14 ++++++++++----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h
index ebaf5701c9db..19aab9a9cec5 100644
--- a/include/uapi/linux/if_addr.h
+++ b/include/uapi/linux/if_addr.h
@@ -54,6 +54,7 @@ enum {
 #define IFA_F_NOPREFIXROUTE	0x200
 #define IFA_F_MCAUTOJOIN	0x400
 #define IFA_F_STABLE_PRIVACY	0x800
+#define IFA_F_FLUSH		0x1000

 struct ifa_cacheinfo {
 	__u32	ifa_prefered;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index d7585ab1a77a..1f436e1e5222 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -331,13 +331,14 @@ int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
 }

 static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
-			 int destroy, struct nlmsghdr *nlh, u32 portid)
+			   int destroy, struct nlmsghdr *nlh, u32 portid,
+			   bool flush)
 {
 	struct in_ifaddr *promote = NULL;
 	struct in_ifaddr *ifa, *ifa1 = *ifap;
 	struct in_ifaddr *last_prim = in_dev->ifa_list;
 	struct in_ifaddr *prev_prom = NULL;
-	int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
+	int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev) && !flush;

 	ASSERT_RTNL();

@@ -437,7 +438,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 			 int destroy)
 {
-	__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
+	__inet_del_ifa(in_dev, ifap, destroy, NULL, 0, false);
 }

 static void check_lifetime(struct work_struct *work);
@@ -607,6 +608,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
 	struct in_device *in_dev;
 	struct ifaddrmsg *ifm;
 	struct in_ifaddr *ifa, **ifap;
+	bool flush = false;
 	int err = -EINVAL;

 	ASSERT_RTNL();
@@ -623,6 +625,9 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
 		goto errout;
 	}

+	if (tb[IFA_FLAGS])
+		flush = !!(nla_get_u32(tb[IFA_FLAGS]) & IFA_F_FLUSH);
+
 	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
 	     ifap = &ifa->ifa_next) {
 		if (tb[IFA_LOCAL] &&
@@ -639,7 +644,8 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,

 		if (ipv4_is_multicast(ifa->ifa_address))
 			ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
-		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
+		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid,
+			       flush);
 		return 0;
 	}

^ permalink raw reply related

* Re: [RFC v6 4/5] virtio_ring: add event idx support in packed ring
From: Jason Wang @ 2018-06-07  9:50 UTC (permalink / raw)
  To: Tiwei Bie, mst, virtualization, linux-kernel, netdev; +Cc: wexu, jfreimann
In-Reply-To: <20180605074046.20709-5-tiwei.bie@intel.com>



On 2018年06月05日 15:40, Tiwei Bie wrote:
>   static bool virtqueue_enable_cb_delayed_packed(struct virtqueue *_vq)
>   {
>   	struct vring_virtqueue *vq = to_vvq(_vq);
> +	u16 bufs, used_idx, wrap_counter;
>   
>   	START_USE(vq);
>   
>   	/* We optimistically turn back on interrupts, then check if there was
>   	 * more to do. */
> +	/* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
> +	 * either clear the flags bit or point the event index at the next
> +	 * entry. Always update the event index to keep code simple. */
> +

Maybe for packed ring, it's time to treat event index separately to 
avoid a virtio_wmb() for event idx is off.

> +	/* TODO: tune this threshold */
> +	if (vq->next_avail_idx < vq->last_used_idx)
> +		bufs = (vq->vring_packed.num + vq->next_avail_idx -
> +				vq->last_used_idx) * 3 / 4;
> +	else
> +		bufs = (vq->next_avail_idx - vq->last_used_idx) * 3 / 4;

vq->next_avail-idx could be equal to vq->last_usd_idx when the ring is 
full. Though virito-net is the only user now and it can guarantee this 
won't happen. But consider this is a core API, we should make sure it 
can work for any cases.

It looks to me that bufs is just vq->vring_packed.num - vq->num_free?

> +
> +	wrap_counter = vq->used_wrap_counter;
> +
> +	used_idx = vq->last_used_idx + bufs;
> +	if (used_idx >= vq->vring_packed.num) {
> +		used_idx -= vq->vring_packed.num;
> +		wrap_counter ^= 1;
> +	}
> +
> +	vq->vring_packed.driver->off_wrap = cpu_to_virtio16(_vq->vdev,
> +			used_idx | (wrap_counter << 15));
>   
>   	if (vq->event_flags_shadow == VRING_EVENT_F_DISABLE) {
> -		vq->event_flags_shadow = VRING_EVENT_F_ENABLE;
> +		/* We need to update event offset and event wrap
> +		 * counter first before updating event flags. */
> +		virtio_wmb(vq->weak_barriers);
> +		vq->event_flags_shadow = vq->event ? VRING_EVENT_F_DESC :
> +						     VRING_EVENT_F_ENABLE;
>   		vq->vring_packed.driver->flags = cpu_to_virtio16(_vq->vdev,
>   							vq->event_flags_shadow);
> -		/* We need to enable interrupts first before re-checking
> -		 * for more used buffers. */
> -		virtio_mb(vq->weak_barriers);
>   	}
>   
> +	/* We need to update event suppression structure first
> +	 * before re-checking for more used buffers. */
> +	virtio_mb(vq->weak_barriers);
> +
>   	if (more_used_packed(vq)) {
>   		END_USE(vq);
>   		return false;

I think what we need to to make sure the descriptor used_idx is used? 
Otherwise we may stop and restart qdisc too frequently?

Thanks

> -- 

^ permalink raw reply

* Re: [PATCH 0/5] can: enable multi-queue for SocketCAN devices
From: Oliver Hartkopp @ 2018-06-07  9:49 UTC (permalink / raw)
  To: Jonas Mark (BT-FIR/ENG1), Wolfgang Grandegger, Marc Kleine-Budde
  Cc: linux-can@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, hs@denx.de,
	ZHU Yi (BT-FIR/ENG1-Zhu)
In-Reply-To: <e8c47bca2ea64b5ab900f4f1e98bb405@de.bosch.com>



On 06/07/2018 10:06 AM, Jonas Mark (BT-FIR/ENG1) wrote:
> Hi Oliver,
> 
>>> The driver suite consists of three separate drivers. The following
>>> diagram illustrates the dependencies in layers.
>>>
>>>              /dev/companion       SocketCAN                User Space
>>> -------------------------------------------------------------------
>>>            +----------------+ +---------------+
>>>            | companion-char | | companion-can |
>>>            +----------------+ +---------------+
>>>            +----------------------------------+
>>>            |          companion-spi           |
>>>            +----------------------------------+
>>>            +----------------------------------+
>>>            |     standard SPI subsystem       |
>>>            +----------------------------------+          Linux Kernel
>>> -------------------------------------------------------------------
>>>                  | | | |      | |                            Hardware
>>>               CS-+ | | |      | +-BUSY
>>>               CLK--+ | |      +---REQUEST
>>>               MOSI---+ |
>>>               MISO-----+
>>>
>>> companion-spi
>>>      core.c: handles SPI, sysfs entry and interface to upper layer
>>>      protocol-manager.c: handles protocol with the SPI HW
>>>      queue-manager.c: handles buffering and packets scheduling
>>>
>>> companion-can
>>>      makes use of multi-queue support and allows to use tc to configure
>>>      the queuing discipline (e.g. mqprio). Together with the SO_PRIORITY
>>>      socket option this allows to specify the FIFO a CAN frame shall be
>>>      sent to.
>>>
>>> companion-char
>>>      handles messages to other undisclosed functionality beyond CAN.
> 
>>>    .../devicetree/bindings/spi/bosch,companion.txt    |   82 ++
>>>    drivers/char/Kconfig                               |    7 +
>>>    drivers/char/Makefile                              |    2 +
>>>    drivers/char/companion-char.c                      |  367 ++++++
>>>    drivers/net/can/Kconfig                            |    8 +
>>>    drivers/net/can/Makefile                           |    1 +
>>>    drivers/net/can/companion-can.c                    |  694 ++++++++++++
>>
>> Please place the companion driver in
>>
>> drivers/net/can/spi/companion.c
>>
>> It also makes more sense in the Kconfig structure.
>>
>> Probably this naming scheme also makes sense for
>>
>> linux/drivers/char/spi/companion.c
>>
>> then ...
>>
>> If not it should be named at least
>>
>> drivers/char/companion-spi.c
>>
>> or
>>
>> drivers/char/spi-companion.c
> 
> We intentionally left out the spi in the driver path / name because
> only the drivers/spi/companion/* driver knows that that it is connected
> to SPI. The others (drivers/net/can/companion-can.c and
> drivers/char/companion-char.c) only know the API. This could also be
> supplied by a driver which talks to the Companion via a different
> interface. Actually, we started with a UART connection but switched to
> SPI due to latency issues.

Ok, got it.

> Should we still change it?

At least I would then vote for

drivers/char/companion.c
drivers/net/can/companion.c

instead of

drivers/char/companion-char.c
drivers/net/can/companion-can.c

as you would have companion-users in different driver subsystems that 
are already clearly referenced by their path.

The modules itself should still be named with companion-can of course 
(as-is right now).

Btw.

+#define DRIVER_NAME     "bosch,companion-can"

+static const struct can_bittiming_const companion_can_bittiming_const = {
+	.name      = "bosch,companion",


Is there any reason why it's not only "companion-can" or "companion"?
The fact that the driver is provided by Bosch is visible in the source code.

Best regards,
Oliver


> 
>>>    drivers/net/can/dev.c                              |    8 +-
>>>    drivers/spi/Kconfig                                |    2 +
>>>    drivers/spi/Makefile                               |    2 +
>>>    drivers/spi/companion/Kconfig                      |    5 +
>>>    drivers/spi/companion/Makefile                     |    2 +
>>>    drivers/spi/companion/core.c                       | 1189 ++++++++++++++++++++
>>>    drivers/spi/companion/protocol-manager.c           | 1035 +++++++++++++++++
>>>    drivers/spi/companion/protocol-manager.h           |  348 ++++++
>>>    drivers/spi/companion/protocol.h                   |  273 +++++
>>>    drivers/spi/companion/queue-manager.c              |  146 +++
>>>    drivers/spi/companion/queue-manager.h              |  245 ++++
>>>    include/linux/can/dev.h                            |    7 +-
>>>    include/linux/companion.h                          |  258 +++++
>>>    20 files changed, 4677 insertions(+), 4 deletions(-)
>>>    create mode 100644
>> Documentation/devicetree/bindings/spi/bosch,companion.txt
>>>    create mode 100644 drivers/char/companion-char.c
>>>    create mode 100644 drivers/net/can/companion-can.c
>>>    create mode 100644 drivers/spi/companion/Kconfig
>>>    create mode 100644 drivers/spi/companion/Makefile
>>>    create mode 100644 drivers/spi/companion/core.c
>>>    create mode 100644 drivers/spi/companion/protocol-manager.c
>>>    create mode 100644 drivers/spi/companion/protocol-manager.h
>>>    create mode 100644 drivers/spi/companion/protocol.h
>>>    create mode 100644 drivers/spi/companion/queue-manager.c
>>>    create mode 100644 drivers/spi/companion/queue-manager.h
>>>    create mode 100644 include/linux/companion.h
> 
> Greetings,
> Mark
> 
> Building Technologies, Panel Software Fire (BT-FIR/ENG1)
> Bosch Sicherheitssysteme GmbH | Postfach 11 11 | 85626 Grasbrunn | GERMANY | www.boschsecurity.com
> 
> Sitz: Stuttgart, Registergericht: Amtsgericht Stuttgart HRB 23118
> Aufsichtsratsvorsitzender: Stefan Hartung; Geschäftsführung: Gert van Iperen, Andreas Bartz, Thomas Quante, Bernhard Schuster
> 

^ permalink raw reply

* [v3, 10/10] dpaa_eth: add the get_ts_info interface for ethtool
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

Added the get_ts_info interface for ethtool to check
the timestamping capability.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- Removed ifdef for hw timestamp.
Changes for v3:
	- None.
---
 drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c |   39 ++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
index 2f933b6..3184c8f 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
@@ -32,6 +32,9 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/string.h>
+#include <linux/of_platform.h>
+#include <linux/net_tstamp.h>
+#include <linux/fsl/ptp_qoriq.h>
 
 #include "dpaa_eth.h"
 #include "mac.h"
@@ -515,6 +518,41 @@ static int dpaa_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
 	return ret;
 }
 
+static int dpaa_get_ts_info(struct net_device *net_dev,
+			    struct ethtool_ts_info *info)
+{
+	struct device *dev = net_dev->dev.parent;
+	struct device_node *mac_node = dev->of_node;
+	struct device_node *fman_node = NULL, *ptp_node = NULL;
+	struct platform_device *ptp_dev = NULL;
+	struct qoriq_ptp *ptp = NULL;
+
+	info->phc_index = -1;
+
+	fman_node = of_get_parent(mac_node);
+	if (fman_node)
+		ptp_node = of_parse_phandle(fman_node, "ptimer-handle", 0);
+
+	if (ptp_node)
+		ptp_dev = of_find_device_by_node(ptp_node);
+
+	if (ptp_dev)
+		ptp = platform_get_drvdata(ptp_dev);
+
+	if (ptp)
+		info->phc_index = ptp->phc_index;
+
+	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+				SOF_TIMESTAMPING_RX_HARDWARE |
+				SOF_TIMESTAMPING_RAW_HARDWARE;
+	info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+			 (1 << HWTSTAMP_TX_ON);
+	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+			   (1 << HWTSTAMP_FILTER_ALL);
+
+	return 0;
+}
+
 const struct ethtool_ops dpaa_ethtool_ops = {
 	.get_drvinfo = dpaa_get_drvinfo,
 	.get_msglevel = dpaa_get_msglevel,
@@ -530,4 +568,5 @@ static int dpaa_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
 	.set_link_ksettings = dpaa_set_link_ksettings,
 	.get_rxnfc = dpaa_get_rxnfc,
 	.set_rxnfc = dpaa_set_rxnfc,
+	.get_ts_info = dpaa_get_ts_info,
 };
-- 
1.7.1

^ permalink raw reply related

* [v3, 08/10] fsl/fman: define frame description command UPD
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

Defined frame description command FM_FD_CMD_UPD for
prepended data updating.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- None.
Changes for v3:
	- None.
---
 drivers/net/ethernet/freescale/fman/fman.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fman/fman.h b/drivers/net/ethernet/freescale/fman/fman.h
index bfa02e0..935c317 100644
--- a/drivers/net/ethernet/freescale/fman/fman.h
+++ b/drivers/net/ethernet/freescale/fman/fman.h
@@ -41,6 +41,7 @@
 /* Frame queue Context Override */
 #define FM_FD_CMD_FCO                   0x80000000
 #define FM_FD_CMD_RPD                   0x40000000  /* Read Prepended Data */
+#define FM_FD_CMD_UPD			0x20000000  /* Update Prepended Data */
 #define FM_FD_CMD_DTC                   0x10000000  /* Do L4 Checksum */
 
 /* TX-Port: Unsupported Format */
-- 
1.7.1

^ permalink raw reply related

* RE: [v2, 09/10] dpaa_eth: add support for hardware timestamping
From: Y.b. Lu @ 2018-06-07  9:21 UTC (permalink / raw)
  To: Madalin-cristian Bucur, netdev@vger.kernel.org, Richard Cochran,
	Rob Herring, Shawn Guo, David S . Miller
  Cc: devicetree@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <AM6PR04MB40080865F823C7C57716818FEC640@AM6PR04MB4008.eurprd04.prod.outlook.com>

Hi Madalin,

> -----Original Message-----
> From: Madalin-cristian Bucur
> Sent: Thursday, June 7, 2018 4:24 PM
> To: Y.b. Lu <yangbo.lu@nxp.com>; netdev@vger.kernel.org; Richard Cochran
> <richardcochran@gmail.com>; Rob Herring <robh+dt@kernel.org>; Shawn
> Guo <shawnguo@kernel.org>; David S . Miller <davem@davemloft.net>
> Cc: devicetree@vger.kernel.org; linuxppc-dev@lists.ozlabs.org;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; Y.b. Lu
> <yangbo.lu@nxp.com>
> Subject: RE: [v2, 09/10] dpaa_eth: add support for hardware timestamping
> 
> > -----Original Message-----
> > From: Yangbo Lu [mailto:yangbo.lu@nxp.com]
> > Sent: Thursday, June 7, 2018 6:23 AM
> > Subject: [v2, 09/10] dpaa_eth: add support for hardware timestamping
> >
> > This patch is to add hardware timestamping support for dpaa_eth. On
> > Rx, timestamping is enabled for all frames. On Tx, we only instruct
> > the hardware to timestamp the frames marked accordingly by the stack.
> >
> > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> > ---
> > Changes for v2:
> > 	- Removed ifdef for timestamp code.
> > 	- Minor fixes for code style.
> > ---
> >  drivers/net/ethernet/freescale/dpaa/dpaa_eth.c |  101
> > ++++++++++++++++++++++-
> >  drivers/net/ethernet/freescale/dpaa/dpaa_eth.h |    3 +
> >  2 files changed, 99 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > index fd43f98..bd589ac 100644
> > --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> > @@ -1168,7 +1168,7 @@ static int dpaa_eth_init_tx_port(struct
> > fman_port *port, struct dpaa_fq *errq,
> >  	buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
> >  	buf_prefix_content.pass_prs_result = true;
> >  	buf_prefix_content.pass_hash_result = true;
> > -	buf_prefix_content.pass_time_stamp = false;
> > +	buf_prefix_content.pass_time_stamp = true;
> >  	buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
> >
> >  	params.specific_params.non_rx_params.err_fqid = errq->fqid; @@
> > -1210,7 +1210,7 @@ static int dpaa_eth_init_rx_port(struct fman_port
> > *port, struct dpaa_bp **bps,
> >  	buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
> >  	buf_prefix_content.pass_prs_result = true;
> >  	buf_prefix_content.pass_hash_result = true;
> > -	buf_prefix_content.pass_time_stamp = false;
> > +	buf_prefix_content.pass_time_stamp = true;
> >  	buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
> >
> >  	rx_p = &params.specific_params.rx_params;
> > @@ -1592,6 +1592,16 @@ static int dpaa_eth_refill_bpools(struct
> > dpaa_priv
> > *priv)
> >  	return 0;
> >  }
> >
> > +static int dpaa_get_tstamp_ns(struct net_device *net_dev, u64 *ns,
> > +			      struct fman_port *port, const void *data) {
> > +	if (!fman_port_get_tstamp_field(port, data, ns)) {
> > +		be64_to_cpus(ns);
> 
> Please move this endianness conversion in the fman API.

[Y.b. Lu] Ok. Will move to fman API in next version.

> 
> > +		return 0;
> > +	}
> > +	return -EINVAL;
> > +}
> > +
> >  /* Cleanup function for outgoing frame descriptors that were built on
> > Tx path,
> >   * either contiguous frames or scatter/gather ones.
> >   * Skb freeing is not handled here.
> > @@ -1607,14 +1617,29 @@ static int dpaa_eth_refill_bpools(struct
> > dpaa_priv
> > *priv)
> >  {
> >  	const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
> >  	struct device *dev = priv->net_dev->dev.parent;
> > +	struct skb_shared_hwtstamps shhwtstamps;
> >  	dma_addr_t addr = qm_fd_addr(fd);
> >  	const struct qm_sg_entry *sgt;
> >  	struct sk_buff **skbh, *skb;
> >  	int nr_frags, i;
> > +	u64 ns;
> >
> >  	skbh = (struct sk_buff **)phys_to_virt(addr);
> >  	skb = *skbh;
> >
> > +	if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags &
> > SKBTX_HW_TSTAMP) {
> > +		memset(&shhwtstamps, 0, sizeof(shhwtstamps));
> > +
> > +		if (!dpaa_get_tstamp_ns(priv->net_dev, &ns,
> > +					priv->mac_dev->port[TX],
> > +					(void *)skbh)) {
> > +			shhwtstamps.hwtstamp = ns_to_ktime(ns);
> > +			skb_tstamp_tx(skb, &shhwtstamps);
> > +		} else {
> > +			dev_warn(dev, "dpaa_get_tstamp_ns failed!\n");
> > +		}
> > +	}
> > +
> >  	if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
> >  		nr_frags = skb_shinfo(skb)->nr_frags;
> >  		dma_unmap_single(dev, addr, qm_fd_get_offset(fd) + @@ -2086,6
> > +2111,11 @@ static int dpaa_start_xmit(struct sk_buff *skb, struct
> > net_device *net_dev)
> >  	if (unlikely(err < 0))
> >  		goto skb_to_fd_failed;
> >
> > +	if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags &
> > SKBTX_HW_TSTAMP) {
> > +		fd.cmd |= FM_FD_CMD_UPD;
> 
> The fd.cmd field is big endian, please use this:
> 
> +		fd.cmd |= cpu_to_be32(FM_FD_CMD_UPD);
> 

[Y.b. Lu] Thanks a lot for pointing out this issue. This fixes TX timestamp issue on ARM platform.
By now, I have verified both PowerPC platform and ARM platform. The PTP clock driver and timestamping worked fine.
I will send out v3 patch-set for reviewing.

> > +		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
> > +	}
> > +
> >  	if (likely(dpaa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0))
> >  		return NETDEV_TX_OK;
> >
> > @@ -2227,6 +2257,7 @@ static enum qman_cb_dqrr_result
> > rx_default_dqrr(struct qman_portal *portal,
> >  						struct qman_fq *fq,
> >  						const struct qm_dqrr_entry
> > *dq)
> >  {
> > +	struct skb_shared_hwtstamps *shhwtstamps;
> >  	struct rtnl_link_stats64 *percpu_stats;
> >  	struct dpaa_percpu_priv *percpu_priv;
> >  	const struct qm_fd *fd = &dq->fd;
> > @@ -2240,6 +2271,7 @@ static enum qman_cb_dqrr_result
> > rx_default_dqrr(struct qman_portal *portal,
> >  	struct sk_buff *skb;
> >  	int *count_ptr;
> >  	void *vaddr;
> > +	u64 ns;
> >
> >  	fd_status = be32_to_cpu(fd->status);
> >  	fd_format = qm_fd_get_format(fd);
> > @@ -2304,6 +2336,18 @@ static enum qman_cb_dqrr_result
> > rx_default_dqrr(struct qman_portal *portal,
> >  	if (!skb)
> >  		return qman_cb_dqrr_consume;
> >
> > +	if (priv->rx_tstamp) {
> > +		shhwtstamps = skb_hwtstamps(skb);
> > +		memset(shhwtstamps, 0, sizeof(*shhwtstamps));
> > +
> > +		if (!dpaa_get_tstamp_ns(priv->net_dev, &ns,
> > +					priv->mac_dev->port[RX],
> > +					vaddr))
> > +			shhwtstamps->hwtstamp = ns_to_ktime(ns);
> > +		else
> > +			dev_warn(net_dev->dev.parent,
> > "dpaa_get_tstamp_ns failed!\n");
> > +	}
> > +
> >  	skb->protocol = eth_type_trans(skb, net_dev);
> >
> >  	if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use &&
> @@
> > -2523,11 +2567,58 @@ static int dpaa_eth_stop(struct net_device
> > *net_dev)
> >  	return err;
> >  }
> >
> > +static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq,
> > +int cmd) {
> > +	struct dpaa_priv *priv = netdev_priv(dev);
> > +	struct hwtstamp_config config;
> > +
> > +	if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
> > +		return -EFAULT;
> > +
> > +	switch (config.tx_type) {
> > +	case HWTSTAMP_TX_OFF:
> > +		/* Couldn't disable rx/tx timestamping separately.
> > +		 * Do nothing here.
> > +		 */
> > +		priv->tx_tstamp = false;
> > +		break;
> > +	case HWTSTAMP_TX_ON:
> > +		priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac,
> > true);
> > +		priv->tx_tstamp = true;
> > +		break;
> > +	default:
> > +		return -ERANGE;
> > +	}
> > +
> > +	if (config.rx_filter == HWTSTAMP_FILTER_NONE) {
> > +		/* Couldn't disable rx/tx timestamping separately.
> > +		 * Do nothing here.
> > +		 */
> > +		priv->rx_tstamp = false;
> > +	} else {
> > +		priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac,
> > true);
> > +		priv->rx_tstamp = true;
> > +		/* TS is set for all frame types, not only those requested */
> > +		config.rx_filter = HWTSTAMP_FILTER_ALL;
> > +	}
> > +
> > +	return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
> > +			-EFAULT : 0;
> > +}
> > +
> >  static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq,
> > int cmd)  {
> > -	if (!net_dev->phydev)
> > -		return -EINVAL;
> > -	return phy_mii_ioctl(net_dev->phydev, rq, cmd);
> > +	int ret = -EINVAL;
> > +
> > +	if (cmd == SIOCGMIIREG) {
> > +		if (net_dev->phydev)
> > +			return phy_mii_ioctl(net_dev->phydev, rq, cmd);
> > +	}
> > +
> > +	if (cmd == SIOCSHWTSTAMP)
> > +		return dpaa_ts_ioctl(net_dev, rq, cmd);
> > +
> > +	return ret;
> >  }
> >
> >  static const struct net_device_ops dpaa_ops = { diff --git
> > a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> > b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> > index bd94220..af320f8 100644
> > --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> > +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> > @@ -182,6 +182,9 @@ struct dpaa_priv {
> >
> >  	struct dpaa_buffer_layout buf_layout[2];
> >  	u16 rx_headroom;
> > +
> > +	bool tx_tstamp; /* Tx timestamping enabled */
> > +	bool rx_tstamp; /* Rx timestamping enabled */
> >  };
> >
> >  /* from dpaa_ethtool.c */
> > --
> > 1.7.1

^ permalink raw reply

* [v3, 09/10] dpaa_eth: add support for hardware timestamping
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to add hardware timestamping support
for dpaa_eth. On Rx, timestamping is enabled for
all frames. On Tx, we only instruct the hardware
to timestamp the frames marked accordingly by the
stack.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- Removed ifdef for timestamp code.
	- Minor fixes for code style.
Changes for v3:
	- Moved tstamp endianness conversion to fman API.
	- Fixed fm.cmd endianness.
---
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c |   88 ++++++++++++++++++++++--
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.h |    3 +
 2 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index fd43f98..6a1c58a 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1168,7 +1168,7 @@ static int dpaa_eth_init_tx_port(struct fman_port *port, struct dpaa_fq *errq,
 	buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
 	buf_prefix_content.pass_prs_result = true;
 	buf_prefix_content.pass_hash_result = true;
-	buf_prefix_content.pass_time_stamp = false;
+	buf_prefix_content.pass_time_stamp = true;
 	buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
 
 	params.specific_params.non_rx_params.err_fqid = errq->fqid;
@@ -1210,7 +1210,7 @@ static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps,
 	buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
 	buf_prefix_content.pass_prs_result = true;
 	buf_prefix_content.pass_hash_result = true;
-	buf_prefix_content.pass_time_stamp = false;
+	buf_prefix_content.pass_time_stamp = true;
 	buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
 
 	rx_p = &params.specific_params.rx_params;
@@ -1607,14 +1607,28 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv *priv)
 {
 	const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
 	struct device *dev = priv->net_dev->dev.parent;
+	struct skb_shared_hwtstamps shhwtstamps;
 	dma_addr_t addr = qm_fd_addr(fd);
 	const struct qm_sg_entry *sgt;
 	struct sk_buff **skbh, *skb;
 	int nr_frags, i;
+	u64 ns;
 
 	skbh = (struct sk_buff **)phys_to_virt(addr);
 	skb = *skbh;
 
+	if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
+		memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+
+		if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh,
+					  &ns)) {
+			shhwtstamps.hwtstamp = ns_to_ktime(ns);
+			skb_tstamp_tx(skb, &shhwtstamps);
+		} else {
+			dev_warn(dev, "fman_port_get_tstamp failed!\n");
+		}
+	}
+
 	if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
 		nr_frags = skb_shinfo(skb)->nr_frags;
 		dma_unmap_single(dev, addr, qm_fd_get_offset(fd) +
@@ -2086,6 +2100,11 @@ static int dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
 	if (unlikely(err < 0))
 		goto skb_to_fd_failed;
 
+	if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
+		fd.cmd |= cpu_to_be32(FM_FD_CMD_UPD);
+		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+	}
+
 	if (likely(dpaa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0))
 		return NETDEV_TX_OK;
 
@@ -2227,6 +2246,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
 						struct qman_fq *fq,
 						const struct qm_dqrr_entry *dq)
 {
+	struct skb_shared_hwtstamps *shhwtstamps;
 	struct rtnl_link_stats64 *percpu_stats;
 	struct dpaa_percpu_priv *percpu_priv;
 	const struct qm_fd *fd = &dq->fd;
@@ -2240,6 +2260,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
 	struct sk_buff *skb;
 	int *count_ptr;
 	void *vaddr;
+	u64 ns;
 
 	fd_status = be32_to_cpu(fd->status);
 	fd_format = qm_fd_get_format(fd);
@@ -2304,6 +2325,16 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
 	if (!skb)
 		return qman_cb_dqrr_consume;
 
+	if (priv->rx_tstamp) {
+		shhwtstamps = skb_hwtstamps(skb);
+		memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+
+		if (!fman_port_get_tstamp(priv->mac_dev->port[RX], vaddr, &ns))
+			shhwtstamps->hwtstamp = ns_to_ktime(ns);
+		else
+			dev_warn(net_dev->dev.parent, "fman_port_get_tstamp failed!\n");
+	}
+
 	skb->protocol = eth_type_trans(skb, net_dev);
 
 	if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use &&
@@ -2523,11 +2554,58 @@ static int dpaa_eth_stop(struct net_device *net_dev)
 	return err;
 }
 
+static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct dpaa_priv *priv = netdev_priv(dev);
+	struct hwtstamp_config config;
+
+	if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	switch (config.tx_type) {
+	case HWTSTAMP_TX_OFF:
+		/* Couldn't disable rx/tx timestamping separately.
+		 * Do nothing here.
+		 */
+		priv->tx_tstamp = false;
+		break;
+	case HWTSTAMP_TX_ON:
+		priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac, true);
+		priv->tx_tstamp = true;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	if (config.rx_filter == HWTSTAMP_FILTER_NONE) {
+		/* Couldn't disable rx/tx timestamping separately.
+		 * Do nothing here.
+		 */
+		priv->rx_tstamp = false;
+	} else {
+		priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac, true);
+		priv->rx_tstamp = true;
+		/* TS is set for all frame types, not only those requested */
+		config.rx_filter = HWTSTAMP_FILTER_ALL;
+	}
+
+	return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
+			-EFAULT : 0;
+}
+
 static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
 {
-	if (!net_dev->phydev)
-		return -EINVAL;
-	return phy_mii_ioctl(net_dev->phydev, rq, cmd);
+	int ret = -EINVAL;
+
+	if (cmd == SIOCGMIIREG) {
+		if (net_dev->phydev)
+			return phy_mii_ioctl(net_dev->phydev, rq, cmd);
+	}
+
+	if (cmd == SIOCSHWTSTAMP)
+		return dpaa_ts_ioctl(net_dev, rq, cmd);
+
+	return ret;
 }
 
 static const struct net_device_ops dpaa_ops = {
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
index bd94220..af320f8 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
@@ -182,6 +182,9 @@ struct dpaa_priv {
 
 	struct dpaa_buffer_layout buf_layout[2];
 	u16 rx_headroom;
+
+	bool tx_tstamp; /* Tx timestamping enabled */
+	bool rx_tstamp; /* Rx timestamping enabled */
 };
 
 /* from dpaa_ethtool.c */
-- 
1.7.1

^ permalink raw reply related

* [v3, 07/10] fsl/fman_port: support getting timestamp
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to add fman_port_get_tstamp() interface
to get timestamp.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- None.
Changes for v3:
	- Moved endianness conversion from dpaa to fman API.
---
 drivers/net/ethernet/freescale/fman/fman_port.c |   12 ++++++++++++
 drivers/net/ethernet/freescale/fman/fman_port.h |    2 ++
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c
index ce6e24c..dce860d 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.c
+++ b/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -1731,6 +1731,18 @@ int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset)
 }
 EXPORT_SYMBOL(fman_port_get_hash_result_offset);
 
+int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp)
+{
+	if (port->buffer_offsets.time_stamp_offset == ILLEGAL_BASE)
+		return -EINVAL;
+
+	*tstamp = be64_to_cpu(*(u64 *)(data +
+			port->buffer_offsets.time_stamp_offset));
+
+	return 0;
+}
+EXPORT_SYMBOL(fman_port_get_tstamp);
+
 static int fman_port_probe(struct platform_device *of_dev)
 {
 	struct fman_port *port;
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.h b/drivers/net/ethernet/freescale/fman/fman_port.h
index e86ca6a..9dbb69f 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.h
+++ b/drivers/net/ethernet/freescale/fman/fman_port.h
@@ -153,6 +153,8 @@ int fman_port_cfg_buf_prefix_content(struct fman_port *port,
 
 int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset);
 
+int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp);
+
 struct fman_port *fman_port_bind(struct device *dev);
 
 #endif /* __FMAN_PORT_H */
-- 
1.7.1

^ permalink raw reply related

* [v3, 06/10] fsl/fman: add set_tstamp interface
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to add set_tstamp interface for memac,
dtsec, and 10GEC controllers to configure HW timestamping.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- None.
Changes for v3:
	- None.
---
 drivers/net/ethernet/freescale/fman/fman_dtsec.c |   27 ++++++++++++++++++++++
 drivers/net/ethernet/freescale/fman/fman_dtsec.h |    1 +
 drivers/net/ethernet/freescale/fman/fman_memac.c |    5 ++++
 drivers/net/ethernet/freescale/fman/fman_memac.h |    1 +
 drivers/net/ethernet/freescale/fman/fman_tgec.c  |   21 +++++++++++++++++
 drivers/net/ethernet/freescale/fman/fman_tgec.h  |    1 +
 drivers/net/ethernet/freescale/fman/mac.c        |    3 ++
 drivers/net/ethernet/freescale/fman/mac.h        |    1 +
 8 files changed, 60 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
index 57b1e2b..1ca543a 100644
--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c
+++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
@@ -123,11 +123,13 @@
 #define DTSEC_ECNTRL_R100M		0x00000008
 #define DTSEC_ECNTRL_QSGMIIM		0x00000001
 
+#define TCTRL_TTSE			0x00000040
 #define TCTRL_GTS			0x00000020
 
 #define RCTRL_PAL_MASK			0x001f0000
 #define RCTRL_PAL_SHIFT			16
 #define RCTRL_GHTX			0x00000400
+#define RCTRL_RTSE			0x00000040
 #define RCTRL_GRS			0x00000020
 #define RCTRL_MPROM			0x00000008
 #define RCTRL_RSF			0x00000004
@@ -1136,6 +1138,31 @@ int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable)
 	return 0;
 }
 
+int dtsec_set_tstamp(struct fman_mac *dtsec, bool enable)
+{
+	struct dtsec_regs __iomem *regs = dtsec->regs;
+	u32 rctrl, tctrl;
+
+	if (!is_init_done(dtsec->dtsec_drv_param))
+		return -EINVAL;
+
+	rctrl = ioread32be(&regs->rctrl);
+	tctrl = ioread32be(&regs->tctrl);
+
+	if (enable) {
+		rctrl |= RCTRL_RTSE;
+		tctrl |= TCTRL_TTSE;
+	} else {
+		rctrl &= ~RCTRL_RTSE;
+		tctrl &= ~TCTRL_TTSE;
+	}
+
+	iowrite32be(rctrl, &regs->rctrl);
+	iowrite32be(tctrl, &regs->tctrl);
+
+	return 0;
+}
+
 int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr)
 {
 	struct dtsec_regs __iomem *regs = dtsec->regs;
diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.h b/drivers/net/ethernet/freescale/fman/fman_dtsec.h
index 1a689ad..5149d96 100644
--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.h
+++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.h
@@ -56,5 +56,6 @@ int dtsec_set_exception(struct fman_mac *dtsec,
 int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr);
 int dtsec_get_version(struct fman_mac *dtsec, u32 *mac_version);
 int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable);
+int dtsec_set_tstamp(struct fman_mac *dtsec, bool enable);
 
 #endif /* __DTSEC_H */
diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c
index 446a97b..bc6eb30 100644
--- a/drivers/net/ethernet/freescale/fman/fman_memac.c
+++ b/drivers/net/ethernet/freescale/fman/fman_memac.c
@@ -964,6 +964,11 @@ int memac_set_allmulti(struct fman_mac *memac, bool enable)
 	return 0;
 }
 
+int memac_set_tstamp(struct fman_mac *memac, bool enable)
+{
+	return 0; /* Always enabled. */
+}
+
 int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr)
 {
 	struct memac_regs __iomem *regs = memac->regs;
diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.h b/drivers/net/ethernet/freescale/fman/fman_memac.h
index b5a5033..b2c671e 100644
--- a/drivers/net/ethernet/freescale/fman/fman_memac.h
+++ b/drivers/net/ethernet/freescale/fman/fman_memac.h
@@ -58,5 +58,6 @@ int memac_set_exception(struct fman_mac *memac,
 int memac_add_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr);
 int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr);
 int memac_set_allmulti(struct fman_mac *memac, bool enable);
+int memac_set_tstamp(struct fman_mac *memac, bool enable);
 
 #endif /* __MEMAC_H */
diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.c b/drivers/net/ethernet/freescale/fman/fman_tgec.c
index 284735d..4070593 100644
--- a/drivers/net/ethernet/freescale/fman/fman_tgec.c
+++ b/drivers/net/ethernet/freescale/fman/fman_tgec.c
@@ -44,6 +44,7 @@
 #define TGEC_TX_IPG_LENGTH_MASK	0x000003ff
 
 /* Command and Configuration Register (COMMAND_CONFIG) */
+#define CMD_CFG_EN_TIMESTAMP		0x00100000
 #define CMD_CFG_NO_LEN_CHK		0x00020000
 #define CMD_CFG_PAUSE_IGNORE		0x00000100
 #define CMF_CFG_CRC_FWD			0x00000040
@@ -588,6 +589,26 @@ int tgec_set_allmulti(struct fman_mac *tgec, bool enable)
 	return 0;
 }
 
+int tgec_set_tstamp(struct fman_mac *tgec, bool enable)
+{
+	struct tgec_regs __iomem *regs = tgec->regs;
+	u32 tmp;
+
+	if (!is_init_done(tgec->cfg))
+		return -EINVAL;
+
+	tmp = ioread32be(&regs->command_config);
+
+	if (enable)
+		tmp |= CMD_CFG_EN_TIMESTAMP;
+	else
+		tmp &= ~CMD_CFG_EN_TIMESTAMP;
+
+	iowrite32be(tmp, &regs->command_config);
+
+	return 0;
+}
+
 int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr)
 {
 	struct tgec_regs __iomem *regs = tgec->regs;
diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.h b/drivers/net/ethernet/freescale/fman/fman_tgec.h
index cbbd3b4..3bfd106 100644
--- a/drivers/net/ethernet/freescale/fman/fman_tgec.h
+++ b/drivers/net/ethernet/freescale/fman/fman_tgec.h
@@ -52,5 +52,6 @@ int tgec_set_exception(struct fman_mac *tgec,
 int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr);
 int tgec_get_version(struct fman_mac *tgec, u32 *mac_version);
 int tgec_set_allmulti(struct fman_mac *tgec, bool enable);
+int tgec_set_tstamp(struct fman_mac *tgec, bool enable);
 
 #endif /* __TGEC_H */
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 7b5b95f..a847b9c 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -471,6 +471,7 @@ static void setup_dtsec(struct mac_device *mac_dev)
 	mac_dev->set_rx_pause		= dtsec_accept_rx_pause_frames;
 	mac_dev->set_exception		= dtsec_set_exception;
 	mac_dev->set_allmulti		= dtsec_set_allmulti;
+	mac_dev->set_tstamp		= dtsec_set_tstamp;
 	mac_dev->set_multi		= set_multi;
 	mac_dev->start			= start;
 	mac_dev->stop			= stop;
@@ -490,6 +491,7 @@ static void setup_tgec(struct mac_device *mac_dev)
 	mac_dev->set_rx_pause		= tgec_accept_rx_pause_frames;
 	mac_dev->set_exception		= tgec_set_exception;
 	mac_dev->set_allmulti		= tgec_set_allmulti;
+	mac_dev->set_tstamp		= tgec_set_tstamp;
 	mac_dev->set_multi		= set_multi;
 	mac_dev->start			= start;
 	mac_dev->stop			= stop;
@@ -509,6 +511,7 @@ static void setup_memac(struct mac_device *mac_dev)
 	mac_dev->set_rx_pause		= memac_accept_rx_pause_frames;
 	mac_dev->set_exception		= memac_set_exception;
 	mac_dev->set_allmulti		= memac_set_allmulti;
+	mac_dev->set_tstamp		= memac_set_tstamp;
 	mac_dev->set_multi		= set_multi;
 	mac_dev->start			= start;
 	mac_dev->stop			= stop;
diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethernet/freescale/fman/mac.h
index b520cec..824a81a 100644
--- a/drivers/net/ethernet/freescale/fman/mac.h
+++ b/drivers/net/ethernet/freescale/fman/mac.h
@@ -68,6 +68,7 @@ struct mac_device {
 	int (*set_promisc)(struct fman_mac *mac_dev, bool enable);
 	int (*change_addr)(struct fman_mac *mac_dev, enet_addr_t *enet_addr);
 	int (*set_allmulti)(struct fman_mac *mac_dev, bool enable);
+	int (*set_tstamp)(struct fman_mac *mac_dev, bool enable);
 	int (*set_multi)(struct net_device *net_dev,
 			 struct mac_device *mac_dev);
 	int (*set_rx_pause)(struct fman_mac *mac_dev, bool en);
-- 
1.7.1

^ permalink raw reply related

* [v3, 05/10] arm64: dts: fsl: move ptp timer out of fman
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to move ptp timer node out of fman.
Because ptp timer will be probed by ptp_qoriq driver,
it should be an independent device in case of conflict
memory mapping.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- Fixed address-cells for ptp-timer.
Changes for v3:
	- None.
---
 arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi
index 4dd0676..a56a408 100644
--- a/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi
+++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi
@@ -11,13 +11,14 @@ fman0: fman@1a00000 {
 	#size-cells = <1>;
 	cell-index = <0>;
 	compatible = "fsl,fman";
-	ranges = <0x0 0x0 0x1a00000 0x100000>;
-	reg = <0x0 0x1a00000 0x0 0x100000>;
+	ranges = <0x0 0x0 0x1a00000 0xfe000>;
+	reg = <0x0 0x1a00000 0x0 0xfe000>;
 	interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
 		     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 	clocks = <&clockgen 3 0>;
 	clock-names = "fmanclk";
 	fsl,qman-channel-range = <0x800 0x10>;
+	ptimer-handle = <&ptp_timer0>;
 
 	muram@0 {
 		compatible = "fsl,fman-muram";
@@ -73,9 +74,10 @@ fman0: fman@1a00000 {
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xfd000 0x1000>;
 	};
+};
 
-	ptp_timer0: ptp-timer@fe000 {
-		compatible = "fsl,fman-ptp-timer";
-		reg = <0xfe000 0x1000>;
-	};
+ptp_timer0: ptp-timer@1afe000 {
+	compatible = "fsl,fman-ptp-timer";
+	reg = <0x0 0x1afe000 0x0 0x1000>;
+	interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
 };
-- 
1.7.1

^ permalink raw reply related

* [v3, 04/10] powerpc/mpc85xx: move ptp timer out of fman in dts
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to move ptp timer node out of fman.
Because ptp timer will be probed by ptp_qoriq driver,
it should be an independent device in case of conflict
memory mapping.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- None.
Changes for v3:
	- None.
---
 arch/powerpc/boot/dts/fsl/qoriq-fman-0.dtsi   |   14 ++++++++------
 arch/powerpc/boot/dts/fsl/qoriq-fman-1.dtsi   |   14 ++++++++------
 arch/powerpc/boot/dts/fsl/qoriq-fman3-0.dtsi  |   14 ++++++++------
 arch/powerpc/boot/dts/fsl/qoriq-fman3-1.dtsi  |   14 ++++++++------
 arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi |   14 ++++++++------
 5 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman-0.dtsi
index abd01d4..6b124f7 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-fman-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-fman-0.dtsi
@@ -37,12 +37,13 @@ fman0: fman@400000 {
 	#size-cells = <1>;
 	cell-index = <0>;
 	compatible = "fsl,fman";
-	ranges = <0 0x400000 0x100000>;
-	reg = <0x400000 0x100000>;
+	ranges = <0 0x400000 0xfe000>;
+	reg = <0x400000 0xfe000>;
 	interrupts = <96 2 0 0>, <16 2 1 1>;
 	clocks = <&clockgen 3 0>;
 	clock-names = "fmanclk";
 	fsl,qman-channel-range = <0x40 0xc>;
+	ptimer-handle = <&ptp_timer0>;
 
 	muram@0 {
 		compatible = "fsl,fman-muram";
@@ -93,9 +94,10 @@ fman0: fman@400000 {
 		reg = <0x87000 0x1000>;
 		status = "disabled";
 	};
+};
 
-	ptp_timer0: ptp-timer@fe000 {
-		compatible = "fsl,fman-ptp-timer";
-		reg = <0xfe000 0x1000>;
-	};
+ptp_timer0: ptp-timer@4fe000 {
+	compatible = "fsl,fman-ptp-timer";
+	reg = <0x4fe000 0x1000>;
+	interrupts = <96 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman-1.dtsi
index debea75..b80aaf5 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-fman-1.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-fman-1.dtsi
@@ -37,12 +37,13 @@ fman1: fman@500000 {
 	#size-cells = <1>;
 	cell-index = <1>;
 	compatible = "fsl,fman";
-	ranges = <0 0x500000 0x100000>;
-	reg = <0x500000 0x100000>;
+	ranges = <0 0x500000 0xfe000>;
+	reg = <0x500000 0xfe000>;
 	interrupts = <97 2 0 0>, <16 2 1 0>;
 	clocks = <&clockgen 3 1>;
 	clock-names = "fmanclk";
 	fsl,qman-channel-range = <0x60 0xc>;
+	ptimer-handle = <&ptp_timer1>;
 
 	muram@0 {
 		compatible = "fsl,fman-muram";
@@ -93,9 +94,10 @@ fman1: fman@500000 {
 		reg = <0x87000 0x1000>;
 		status = "disabled";
 	};
+};
 
-	ptp_timer1: ptp-timer@fe000 {
-		compatible = "fsl,fman-ptp-timer";
-		reg = <0xfe000 0x1000>;
-	};
+ptp_timer1: ptp-timer@5fe000 {
+	compatible = "fsl,fman-ptp-timer";
+	reg = <0x5fe000 0x1000>;
+	interrupts = <97 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0.dtsi
index 3a20e0d..d3720fd 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0.dtsi
@@ -37,12 +37,13 @@ fman0: fman@400000 {
 	#size-cells = <1>;
 	cell-index = <0>;
 	compatible = "fsl,fman";
-	ranges = <0 0x400000 0x100000>;
-	reg = <0x400000 0x100000>;
+	ranges = <0 0x400000 0xfe000>;
+	reg = <0x400000 0xfe000>;
 	interrupts = <96 2 0 0>, <16 2 1 1>;
 	clocks = <&clockgen 3 0>;
 	clock-names = "fmanclk";
 	fsl,qman-channel-range = <0x800 0x10>;
+	ptimer-handle = <&ptp_timer0>;
 
 	muram@0 {
 		compatible = "fsl,fman-muram";
@@ -98,9 +99,10 @@ fman0: fman@400000 {
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xfd000 0x1000>;
 	};
+};
 
-	ptp_timer0: ptp-timer@fe000 {
-		compatible = "fsl,fman-ptp-timer";
-		reg = <0xfe000 0x1000>;
-	};
+ptp_timer0: ptp-timer@4fe000 {
+	compatible = "fsl,fman-ptp-timer";
+	reg = <0x4fe000 0x1000>;
+	interrupts = <96 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1.dtsi
index 82750ac..ae34c20 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1.dtsi
@@ -37,12 +37,13 @@ fman1: fman@500000 {
 	#size-cells = <1>;
 	cell-index = <1>;
 	compatible = "fsl,fman";
-	ranges = <0 0x500000 0x100000>;
-	reg = <0x500000 0x100000>;
+	ranges = <0 0x500000 0xfe000>;
+	reg = <0x500000 0xfe000>;
 	interrupts = <97 2 0 0>, <16 2 1 0>;
 	clocks = <&clockgen 3 1>;
 	clock-names = "fmanclk";
 	fsl,qman-channel-range = <0x820 0x10>;
+	ptimer-handle = <&ptp_timer1>;
 
 	muram@0 {
 		compatible = "fsl,fman-muram";
@@ -98,9 +99,10 @@ fman1: fman@500000 {
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xfd000 0x1000>;
 	};
+};
 
-	ptp_timer1: ptp-timer@fe000 {
-		compatible = "fsl,fman-ptp-timer";
-		reg = <0xfe000 0x1000>;
-	};
+ptp_timer1: ptp-timer@5fe000 {
+	compatible = "fsl,fman-ptp-timer";
+	reg = <0x5fe000 0x1000>;
+	interrupts = <97 2 0 0>;
 };
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi
index 7f60b60..02f2755 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi
@@ -37,12 +37,13 @@ fman0: fman@400000 {
 	#size-cells = <1>;
 	cell-index = <0>;
 	compatible = "fsl,fman";
-	ranges = <0 0x400000 0x100000>;
-	reg = <0x400000 0x100000>;
+	ranges = <0 0x400000 0xfe000>;
+	reg = <0x400000 0xfe000>;
 	interrupts = <96 2 0 0>, <16 2 1 1>;
 	clocks = <&clockgen 3 0>;
 	clock-names = "fmanclk";
 	fsl,qman-channel-range = <0x800 0x10>;
+	ptimer-handle = <&ptp_timer0>;
 
 	muram@0 {
 		compatible = "fsl,fman-muram";
@@ -86,9 +87,10 @@ fman0: fman@400000 {
 		compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
 		reg = <0xfd000 0x1000>;
 	};
+};
 
-	ptp_timer0: ptp-timer@fe000 {
-		compatible = "fsl,fman-ptp-timer";
-		reg = <0xfe000 0x1000>;
-	};
+ptp_timer0: ptp-timer@4fe000 {
+	compatible = "fsl,fman-ptp-timer";
+	reg = <0x4fe000 0x1000>;
+	interrupts = <96 2 0 0>;
 };
-- 
1.7.1

^ permalink raw reply related

* [v3, 03/10] dt-binding: ptp_qoriq: add DPAA FMan support
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to add bindings description for DPAA
FMan 1588 timer, and also remove its description in
fsl-fman dt-bindings document.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- None.
Changes for v3:
	- None.
---
 Documentation/devicetree/bindings/net/fsl-fman.txt |   25 +-------------------
 .../devicetree/bindings/ptp/ptp-qoriq.txt          |   15 +++++++++--
 2 files changed, 13 insertions(+), 27 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/fsl-fman.txt b/Documentation/devicetree/bindings/net/fsl-fman.txt
index df873d1..74603dd 100644
--- a/Documentation/devicetree/bindings/net/fsl-fman.txt
+++ b/Documentation/devicetree/bindings/net/fsl-fman.txt
@@ -356,30 +356,7 @@ ethernet@e0000 {
 ============================================================================
 FMan IEEE 1588 Node
 
-DESCRIPTION
-
-The FMan interface to support IEEE 1588
-
-
-PROPERTIES
-
-- compatible
-		Usage: required
-		Value type: <stringlist>
-		Definition: A standard property.
-		Must include "fsl,fman-ptp-timer".
-
-- reg
-		Usage: required
-		Value type: <prop-encoded-array>
-		Definition: A standard property.
-
-EXAMPLE
-
-ptp-timer@fe000 {
-	compatible = "fsl,fman-ptp-timer";
-	reg = <0xfe000 0x1000>;
-};
+Refer to Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
 
 =============================================================================
 FMan MDIO Node
diff --git a/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt b/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
index 0f569d8..c5d0e79 100644
--- a/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
+++ b/Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
@@ -2,7 +2,8 @@
 
 General Properties:
 
-  - compatible   Should be "fsl,etsec-ptp"
+  - compatible   Should be "fsl,etsec-ptp" for eTSEC
+                 Should be "fsl,fman-ptp-timer" for DPAA FMan
   - reg          Offset and length of the register set for the device
   - interrupts   There should be at least two interrupts. Some devices
                  have as many as four PTP related interrupts.
@@ -43,14 +44,22 @@ Clock Properties:
   value, which will be directly written in those bits, that is why,
   according to reference manual, the next clock sources can be used:
 
+  For eTSEC,
   <0> - external high precision timer reference clock (TSEC_TMR_CLK
         input is used for this purpose);
   <1> - eTSEC system clock;
   <2> - eTSEC1 transmit clock;
   <3> - RTC clock input.
 
-  When this attribute is not used, eTSEC system clock will serve as
-  IEEE 1588 timer reference clock.
+  For DPAA FMan,
+  <0> - external high precision timer reference clock (TMR_1588_CLK)
+  <1> - MAC system clock (1/2 FMan clock)
+  <2> - reserved
+  <3> - RTC clock oscillator
+
+  When this attribute is not used, the IEEE 1588 timer reference clock
+  will use the eTSEC system clock (for Gianfar) or the MAC system
+  clock (for DPAA).
 
 Example:
 
-- 
1.7.1

^ permalink raw reply related

* [v3, 02/10] ptp: support DPAA FMan 1588 timer in ptp_qoriq
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to support DPAA (Data Path Acceleration Architecture)
1588 timer by adding "fsl,fman-ptp-timer" compatible, sharing
interrupt with FMan, adding FSL_DPAA_ETH dependency, and fixing
up register offset.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- None.
Changes for v3:
	- None.
---
 drivers/ptp/Kconfig           |    2 +-
 drivers/ptp/ptp_qoriq.c       |  104 ++++++++++++++++++++++++++---------------
 include/linux/fsl/ptp_qoriq.h |   38 ++++++++++++---
 3 files changed, 98 insertions(+), 46 deletions(-)

diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 474c988..d137c48 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -43,7 +43,7 @@ config PTP_1588_CLOCK_DTE
 
 config PTP_1588_CLOCK_QORIQ
 	tristate "Freescale QorIQ 1588 timer as PTP clock"
-	depends on GIANFAR
+	depends on GIANFAR || FSL_DPAA_ETH
 	depends on PTP_1588_CLOCK
 	default y
 	help
diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c
index 1468a16..c4e3545 100644
--- a/drivers/ptp/ptp_qoriq.c
+++ b/drivers/ptp/ptp_qoriq.c
@@ -39,11 +39,12 @@
 /* Caller must hold qoriq_ptp->lock. */
 static u64 tmr_cnt_read(struct qoriq_ptp *qoriq_ptp)
 {
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
 	u64 ns;
 	u32 lo, hi;
 
-	lo = qoriq_read(&qoriq_ptp->regs->tmr_cnt_l);
-	hi = qoriq_read(&qoriq_ptp->regs->tmr_cnt_h);
+	lo = qoriq_read(&regs->ctrl_regs->tmr_cnt_l);
+	hi = qoriq_read(&regs->ctrl_regs->tmr_cnt_h);
 	ns = ((u64) hi) << 32;
 	ns |= lo;
 	return ns;
@@ -52,16 +53,18 @@ static u64 tmr_cnt_read(struct qoriq_ptp *qoriq_ptp)
 /* Caller must hold qoriq_ptp->lock. */
 static void tmr_cnt_write(struct qoriq_ptp *qoriq_ptp, u64 ns)
 {
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
 	u32 hi = ns >> 32;
 	u32 lo = ns & 0xffffffff;
 
-	qoriq_write(&qoriq_ptp->regs->tmr_cnt_l, lo);
-	qoriq_write(&qoriq_ptp->regs->tmr_cnt_h, hi);
+	qoriq_write(&regs->ctrl_regs->tmr_cnt_l, lo);
+	qoriq_write(&regs->ctrl_regs->tmr_cnt_h, hi);
 }
 
 /* Caller must hold qoriq_ptp->lock. */
 static void set_alarm(struct qoriq_ptp *qoriq_ptp)
 {
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
 	u64 ns;
 	u32 lo, hi;
 
@@ -70,16 +73,18 @@ static void set_alarm(struct qoriq_ptp *qoriq_ptp)
 	ns -= qoriq_ptp->tclk_period;
 	hi = ns >> 32;
 	lo = ns & 0xffffffff;
-	qoriq_write(&qoriq_ptp->regs->tmr_alarm1_l, lo);
-	qoriq_write(&qoriq_ptp->regs->tmr_alarm1_h, hi);
+	qoriq_write(&regs->alarm_regs->tmr_alarm1_l, lo);
+	qoriq_write(&regs->alarm_regs->tmr_alarm1_h, hi);
 }
 
 /* Caller must hold qoriq_ptp->lock. */
 static void set_fipers(struct qoriq_ptp *qoriq_ptp)
 {
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
+
 	set_alarm(qoriq_ptp);
-	qoriq_write(&qoriq_ptp->regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
-	qoriq_write(&qoriq_ptp->regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
+	qoriq_write(&regs->fiper_regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
+	qoriq_write(&regs->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
 }
 
 /*
@@ -89,16 +94,17 @@ static void set_fipers(struct qoriq_ptp *qoriq_ptp)
 static irqreturn_t isr(int irq, void *priv)
 {
 	struct qoriq_ptp *qoriq_ptp = priv;
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
 	struct ptp_clock_event event;
 	u64 ns;
 	u32 ack = 0, lo, hi, mask, val;
 
-	val = qoriq_read(&qoriq_ptp->regs->tmr_tevent);
+	val = qoriq_read(&regs->ctrl_regs->tmr_tevent);
 
 	if (val & ETS1) {
 		ack |= ETS1;
-		hi = qoriq_read(&qoriq_ptp->regs->tmr_etts1_h);
-		lo = qoriq_read(&qoriq_ptp->regs->tmr_etts1_l);
+		hi = qoriq_read(&regs->etts_regs->tmr_etts1_h);
+		lo = qoriq_read(&regs->etts_regs->tmr_etts1_l);
 		event.type = PTP_CLOCK_EXTTS;
 		event.index = 0;
 		event.timestamp = ((u64) hi) << 32;
@@ -108,8 +114,8 @@ static irqreturn_t isr(int irq, void *priv)
 
 	if (val & ETS2) {
 		ack |= ETS2;
-		hi = qoriq_read(&qoriq_ptp->regs->tmr_etts2_h);
-		lo = qoriq_read(&qoriq_ptp->regs->tmr_etts2_l);
+		hi = qoriq_read(&regs->etts_regs->tmr_etts2_h);
+		lo = qoriq_read(&regs->etts_regs->tmr_etts2_l);
 		event.type = PTP_CLOCK_EXTTS;
 		event.index = 1;
 		event.timestamp = ((u64) hi) << 32;
@@ -130,16 +136,16 @@ static irqreturn_t isr(int irq, void *priv)
 			hi = ns >> 32;
 			lo = ns & 0xffffffff;
 			spin_lock(&qoriq_ptp->lock);
-			qoriq_write(&qoriq_ptp->regs->tmr_alarm2_l, lo);
-			qoriq_write(&qoriq_ptp->regs->tmr_alarm2_h, hi);
+			qoriq_write(&regs->alarm_regs->tmr_alarm2_l, lo);
+			qoriq_write(&regs->alarm_regs->tmr_alarm2_h, hi);
 			spin_unlock(&qoriq_ptp->lock);
 			qoriq_ptp->alarm_value = ns;
 		} else {
-			qoriq_write(&qoriq_ptp->regs->tmr_tevent, ALM2);
+			qoriq_write(&regs->ctrl_regs->tmr_tevent, ALM2);
 			spin_lock(&qoriq_ptp->lock);
-			mask = qoriq_read(&qoriq_ptp->regs->tmr_temask);
+			mask = qoriq_read(&regs->ctrl_regs->tmr_temask);
 			mask &= ~ALM2EN;
-			qoriq_write(&qoriq_ptp->regs->tmr_temask, mask);
+			qoriq_write(&regs->ctrl_regs->tmr_temask, mask);
 			spin_unlock(&qoriq_ptp->lock);
 			qoriq_ptp->alarm_value = 0;
 			qoriq_ptp->alarm_interval = 0;
@@ -153,7 +159,7 @@ static irqreturn_t isr(int irq, void *priv)
 	}
 
 	if (ack) {
-		qoriq_write(&qoriq_ptp->regs->tmr_tevent, ack);
+		qoriq_write(&regs->ctrl_regs->tmr_tevent, ack);
 		return IRQ_HANDLED;
 	} else
 		return IRQ_NONE;
@@ -169,6 +175,7 @@ static int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
 	u32 tmr_add;
 	int neg_adj = 0;
 	struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps);
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
 
 	if (scaled_ppm < 0) {
 		neg_adj = 1;
@@ -186,7 +193,7 @@ static int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
 
 	tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
 
-	qoriq_write(&qoriq_ptp->regs->tmr_add, tmr_add);
+	qoriq_write(&regs->ctrl_regs->tmr_add, tmr_add);
 
 	return 0;
 }
@@ -250,6 +257,7 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
 			      struct ptp_clock_request *rq, int on)
 {
 	struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps);
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
 	unsigned long flags;
 	u32 bit, mask;
 
@@ -266,23 +274,23 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
 			return -EINVAL;
 		}
 		spin_lock_irqsave(&qoriq_ptp->lock, flags);
-		mask = qoriq_read(&qoriq_ptp->regs->tmr_temask);
+		mask = qoriq_read(&regs->ctrl_regs->tmr_temask);
 		if (on)
 			mask |= bit;
 		else
 			mask &= ~bit;
-		qoriq_write(&qoriq_ptp->regs->tmr_temask, mask);
+		qoriq_write(&regs->ctrl_regs->tmr_temask, mask);
 		spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
 		return 0;
 
 	case PTP_CLK_REQ_PPS:
 		spin_lock_irqsave(&qoriq_ptp->lock, flags);
-		mask = qoriq_read(&qoriq_ptp->regs->tmr_temask);
+		mask = qoriq_read(&regs->ctrl_regs->tmr_temask);
 		if (on)
 			mask |= PP1EN;
 		else
 			mask &= ~PP1EN;
-		qoriq_write(&qoriq_ptp->regs->tmr_temask, mask);
+		qoriq_write(&regs->ctrl_regs->tmr_temask, mask);
 		spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
 		return 0;
 
@@ -313,10 +321,12 @@ static int qoriq_ptp_probe(struct platform_device *dev)
 {
 	struct device_node *node = dev->dev.of_node;
 	struct qoriq_ptp *qoriq_ptp;
+	struct qoriq_ptp_registers *regs;
 	struct timespec64 now;
 	int err = -ENOMEM;
 	u32 tmr_ctrl;
 	unsigned long flags;
+	void __iomem *base;
 
 	qoriq_ptp = kzalloc(sizeof(*qoriq_ptp), GFP_KERNEL);
 	if (!qoriq_ptp)
@@ -351,7 +361,7 @@ static int qoriq_ptp_probe(struct platform_device *dev)
 		pr_err("irq not in device tree\n");
 		goto no_node;
 	}
-	if (request_irq(qoriq_ptp->irq, isr, 0, DRIVER, qoriq_ptp)) {
+	if (request_irq(qoriq_ptp->irq, isr, IRQF_SHARED, DRIVER, qoriq_ptp)) {
 		pr_err("request_irq failed\n");
 		goto no_node;
 	}
@@ -368,12 +378,27 @@ static int qoriq_ptp_probe(struct platform_device *dev)
 
 	spin_lock_init(&qoriq_ptp->lock);
 
-	qoriq_ptp->regs = ioremap(qoriq_ptp->rsrc->start,
-				resource_size(qoriq_ptp->rsrc));
-	if (!qoriq_ptp->regs) {
+	base = ioremap(qoriq_ptp->rsrc->start,
+		       resource_size(qoriq_ptp->rsrc));
+	if (!base) {
 		pr_err("ioremap ptp registers failed\n");
 		goto no_ioremap;
 	}
+
+	qoriq_ptp->base = base;
+
+	if (of_device_is_compatible(node, "fsl,fman-ptp-timer")) {
+		qoriq_ptp->regs.ctrl_regs = base + FMAN_CTRL_REGS_OFFSET;
+		qoriq_ptp->regs.alarm_regs = base + FMAN_ALARM_REGS_OFFSET;
+		qoriq_ptp->regs.fiper_regs = base + FMAN_FIPER_REGS_OFFSET;
+		qoriq_ptp->regs.etts_regs = base + FMAN_ETTS_REGS_OFFSET;
+	} else {
+		qoriq_ptp->regs.ctrl_regs = base + CTRL_REGS_OFFSET;
+		qoriq_ptp->regs.alarm_regs = base + ALARM_REGS_OFFSET;
+		qoriq_ptp->regs.fiper_regs = base + FIPER_REGS_OFFSET;
+		qoriq_ptp->regs.etts_regs = base + ETTS_REGS_OFFSET;
+	}
+
 	getnstimeofday64(&now);
 	ptp_qoriq_settime(&qoriq_ptp->caps, &now);
 
@@ -383,13 +408,14 @@ static int qoriq_ptp_probe(struct platform_device *dev)
 
 	spin_lock_irqsave(&qoriq_ptp->lock, flags);
 
-	qoriq_write(&qoriq_ptp->regs->tmr_ctrl,   tmr_ctrl);
-	qoriq_write(&qoriq_ptp->regs->tmr_add,    qoriq_ptp->tmr_add);
-	qoriq_write(&qoriq_ptp->regs->tmr_prsc,   qoriq_ptp->tmr_prsc);
-	qoriq_write(&qoriq_ptp->regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
-	qoriq_write(&qoriq_ptp->regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
+	regs = &qoriq_ptp->regs;
+	qoriq_write(&regs->ctrl_regs->tmr_ctrl,   tmr_ctrl);
+	qoriq_write(&regs->ctrl_regs->tmr_add,    qoriq_ptp->tmr_add);
+	qoriq_write(&regs->ctrl_regs->tmr_prsc,   qoriq_ptp->tmr_prsc);
+	qoriq_write(&regs->fiper_regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
+	qoriq_write(&regs->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
 	set_alarm(qoriq_ptp);
-	qoriq_write(&qoriq_ptp->regs->tmr_ctrl,   tmr_ctrl|FIPERST|RTPE|TE|FRD);
+	qoriq_write(&regs->ctrl_regs->tmr_ctrl,   tmr_ctrl|FIPERST|RTPE|TE|FRD);
 
 	spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
 
@@ -405,7 +431,7 @@ static int qoriq_ptp_probe(struct platform_device *dev)
 	return 0;
 
 no_clock:
-	iounmap(qoriq_ptp->regs);
+	iounmap(qoriq_ptp->base);
 no_ioremap:
 	release_resource(qoriq_ptp->rsrc);
 no_resource:
@@ -419,12 +445,13 @@ static int qoriq_ptp_probe(struct platform_device *dev)
 static int qoriq_ptp_remove(struct platform_device *dev)
 {
 	struct qoriq_ptp *qoriq_ptp = platform_get_drvdata(dev);
+	struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
 
-	qoriq_write(&qoriq_ptp->regs->tmr_temask, 0);
-	qoriq_write(&qoriq_ptp->regs->tmr_ctrl,   0);
+	qoriq_write(&regs->ctrl_regs->tmr_temask, 0);
+	qoriq_write(&regs->ctrl_regs->tmr_ctrl,   0);
 
 	ptp_clock_unregister(qoriq_ptp->clock);
-	iounmap(qoriq_ptp->regs);
+	iounmap(qoriq_ptp->base);
 	release_resource(qoriq_ptp->rsrc);
 	free_irq(qoriq_ptp->irq, qoriq_ptp);
 	kfree(qoriq_ptp);
@@ -434,6 +461,7 @@ static int qoriq_ptp_remove(struct platform_device *dev)
 
 static const struct of_device_id match_table[] = {
 	{ .compatible = "fsl,etsec-ptp" },
+	{ .compatible = "fsl,fman-ptp-timer" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, match_table);
diff --git a/include/linux/fsl/ptp_qoriq.h b/include/linux/fsl/ptp_qoriq.h
index b462d9e..dc3dac4 100644
--- a/include/linux/fsl/ptp_qoriq.h
+++ b/include/linux/fsl/ptp_qoriq.h
@@ -11,9 +11,8 @@
 
 /*
  * qoriq ptp registers
- * Generated by regen.tcl on Thu May 13 01:38:57 PM CEST 2010
  */
-struct qoriq_ptp_registers {
+struct ctrl_regs {
 	u32 tmr_ctrl;     /* Timer control register */
 	u32 tmr_tevent;   /* Timestamp event register */
 	u32 tmr_temask;   /* Timer event mask register */
@@ -28,22 +27,47 @@ struct qoriq_ptp_registers {
 	u8  res1[4];
 	u32 tmroff_h;     /* Timer offset high */
 	u32 tmroff_l;     /* Timer offset low */
-	u8  res2[8];
+};
+
+struct alarm_regs {
 	u32 tmr_alarm1_h; /* Timer alarm 1 high register */
 	u32 tmr_alarm1_l; /* Timer alarm 1 high register */
 	u32 tmr_alarm2_h; /* Timer alarm 2 high register */
 	u32 tmr_alarm2_l; /* Timer alarm 2 high register */
-	u8  res3[48];
+};
+
+struct fiper_regs {
 	u32 tmr_fiper1;   /* Timer fixed period interval */
 	u32 tmr_fiper2;   /* Timer fixed period interval */
 	u32 tmr_fiper3;   /* Timer fixed period interval */
-	u8  res4[20];
+};
+
+struct etts_regs {
 	u32 tmr_etts1_h;  /* Timestamp of general purpose external trigger */
 	u32 tmr_etts1_l;  /* Timestamp of general purpose external trigger */
 	u32 tmr_etts2_h;  /* Timestamp of general purpose external trigger */
 	u32 tmr_etts2_l;  /* Timestamp of general purpose external trigger */
 };
 
+struct qoriq_ptp_registers {
+	struct ctrl_regs __iomem *ctrl_regs;
+	struct alarm_regs __iomem *alarm_regs;
+	struct fiper_regs __iomem *fiper_regs;
+	struct etts_regs __iomem *etts_regs;
+};
+
+/* Offset definitions for the four register groups */
+#define CTRL_REGS_OFFSET	0x0
+#define ALARM_REGS_OFFSET	0x40
+#define FIPER_REGS_OFFSET	0x80
+#define ETTS_REGS_OFFSET	0xa0
+
+#define FMAN_CTRL_REGS_OFFSET	0x80
+#define FMAN_ALARM_REGS_OFFSET	0xb8
+#define FMAN_FIPER_REGS_OFFSET	0xd0
+#define FMAN_ETTS_REGS_OFFSET	0xe0
+
+
 /* Bit definitions for the TMR_CTRL register */
 #define ALM1P                 (1<<31) /* Alarm1 output polarity */
 #define ALM2P                 (1<<30) /* Alarm2 output polarity */
@@ -105,10 +129,10 @@ struct qoriq_ptp_registers {
 #define DRIVER		"ptp_qoriq"
 #define DEFAULT_CKSEL	1
 #define N_EXT_TS	2
-#define REG_SIZE	sizeof(struct qoriq_ptp_registers)
 
 struct qoriq_ptp {
-	struct qoriq_ptp_registers __iomem *regs;
+	void __iomem *base;
+	struct qoriq_ptp_registers regs;
 	spinlock_t lock; /* protects regs */
 	struct ptp_clock *clock;
 	struct ptp_clock_info caps;
-- 
1.7.1

^ permalink raw reply related

* [v3, 01/10] fsl/fman: share the event interrupt
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-kernel, linux-arm-kernel,
	Yangbo Lu
In-Reply-To: <20180607092050.46128-1-yangbo.lu@nxp.com>

This patch is to share fman event interrupt because
the 1588 timer driver will also use this interrupt.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- None.
Changes for v3:
	- None.
---
 drivers/net/ethernet/freescale/fman/fman.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index 9530405..c415ac6 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -2801,7 +2801,8 @@ static irqreturn_t fman_irq(int irq, void *handle)
 	of_node_put(muram_node);
 	of_node_put(fm_node);
 
-	err = devm_request_irq(&of_dev->dev, irq, fman_irq, 0, "fman", fman);
+	err = devm_request_irq(&of_dev->dev, irq, fman_irq, IRQF_SHARED,
+			       "fman", fman);
 	if (err < 0) {
 		dev_err(&of_dev->dev, "%s: irq %d allocation failed (error = %d)\n",
 			__func__, irq, err);
-- 
1.7.1

^ permalink raw reply related

* [v3, 00/10] Support DPAA PTP clock and timestamping
From: Yangbo Lu @ 2018-06-07  9:20 UTC (permalink / raw)
  To: netdev, madalin.bucur, Richard Cochran, Rob Herring, Shawn Guo,
	David S . Miller
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, linux-kernel,
	Yangbo Lu

This patchset is to support DPAA FMAN PTP clock and HW timestamping.
It had been verified on both ARM platform and PPC platform.
- The patch #1 to patch #5 are to support DPAA FMAN 1588 timer in
  ptp_qoriq driver.
- The patch #6 to patch #10 are to add HW timestamping support in
  DPAA ethernet driver.

Yangbo Lu (10):
  fsl/fman: share the event interrupt
  ptp: support DPAA FMan 1588 timer in ptp_qoriq
  dt-binding: ptp_qoriq: add DPAA FMan support
  powerpc/mpc85xx: move ptp timer out of fman in dts
  arm64: dts: fsl: move ptp timer out of fman
  fsl/fman: add set_tstamp interface
  fsl/fman_port: support getting timestamp
  fsl/fman: define frame description command UPD
  dpaa_eth: add support for hardware timestamping
  dpaa_eth: add the get_ts_info interface for ethtool

 Documentation/devicetree/bindings/net/fsl-fman.txt |   25 +-----
 .../devicetree/bindings/ptp/ptp-qoriq.txt          |   15 +++-
 arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi   |   14 ++-
 arch/powerpc/boot/dts/fsl/qoriq-fman-0.dtsi        |   14 ++-
 arch/powerpc/boot/dts/fsl/qoriq-fman-1.dtsi        |   14 ++-
 arch/powerpc/boot/dts/fsl/qoriq-fman3-0.dtsi       |   14 ++-
 arch/powerpc/boot/dts/fsl/qoriq-fman3-1.dtsi       |   14 ++-
 arch/powerpc/boot/dts/fsl/qoriq-fman3l-0.dtsi      |   14 ++-
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c     |   88 ++++++++++++++++-
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.h     |    3 +
 drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c |   39 ++++++++
 drivers/net/ethernet/freescale/fman/fman.c         |    3 +-
 drivers/net/ethernet/freescale/fman/fman.h         |    1 +
 drivers/net/ethernet/freescale/fman/fman_dtsec.c   |   27 +++++
 drivers/net/ethernet/freescale/fman/fman_dtsec.h   |    1 +
 drivers/net/ethernet/freescale/fman/fman_memac.c   |    5 +
 drivers/net/ethernet/freescale/fman/fman_memac.h   |    1 +
 drivers/net/ethernet/freescale/fman/fman_port.c    |   12 +++
 drivers/net/ethernet/freescale/fman/fman_port.h    |    2 +
 drivers/net/ethernet/freescale/fman/fman_tgec.c    |   21 ++++
 drivers/net/ethernet/freescale/fman/fman_tgec.h    |    1 +
 drivers/net/ethernet/freescale/fman/mac.c          |    3 +
 drivers/net/ethernet/freescale/fman/mac.h          |    1 +
 drivers/ptp/Kconfig                                |    2 +-
 drivers/ptp/ptp_qoriq.c                            |  104 ++++++++++++-------
 include/linux/fsl/ptp_qoriq.h                      |   38 ++++++--
 26 files changed, 361 insertions(+), 115 deletions(-)

^ permalink raw reply

* RE: [v2, 09/10] dpaa_eth: add support for hardware timestamping
From: Madalin-cristian Bucur @ 2018-06-07  8:24 UTC (permalink / raw)
  To: Y.b. Lu, netdev@vger.kernel.org, Richard Cochran, Rob Herring,
	Shawn Guo, David S . Miller
  Cc: devicetree@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Y.b. Lu
In-Reply-To: <20180607032256.39802-10-yangbo.lu@nxp.com>

> -----Original Message-----
> From: Yangbo Lu [mailto:yangbo.lu@nxp.com]
> Sent: Thursday, June 7, 2018 6:23 AM
> Subject: [v2, 09/10] dpaa_eth: add support for hardware timestamping
> 
> This patch is to add hardware timestamping support
> for dpaa_eth. On Rx, timestamping is enabled for
> all frames. On Tx, we only instruct the hardware
> to timestamp the frames marked accordingly by the
> stack.
> 
> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> ---
> Changes for v2:
> 	- Removed ifdef for timestamp code.
> 	- Minor fixes for code style.
> ---
>  drivers/net/ethernet/freescale/dpaa/dpaa_eth.c |  101
> ++++++++++++++++++++++-
>  drivers/net/ethernet/freescale/dpaa/dpaa_eth.h |    3 +
>  2 files changed, 99 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> index fd43f98..bd589ac 100644
> --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
> @@ -1168,7 +1168,7 @@ static int dpaa_eth_init_tx_port(struct fman_port
> *port, struct dpaa_fq *errq,
>  	buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
>  	buf_prefix_content.pass_prs_result = true;
>  	buf_prefix_content.pass_hash_result = true;
> -	buf_prefix_content.pass_time_stamp = false;
> +	buf_prefix_content.pass_time_stamp = true;
>  	buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
> 
>  	params.specific_params.non_rx_params.err_fqid = errq->fqid;
> @@ -1210,7 +1210,7 @@ static int dpaa_eth_init_rx_port(struct fman_port
> *port, struct dpaa_bp **bps,
>  	buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
>  	buf_prefix_content.pass_prs_result = true;
>  	buf_prefix_content.pass_hash_result = true;
> -	buf_prefix_content.pass_time_stamp = false;
> +	buf_prefix_content.pass_time_stamp = true;
>  	buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
> 
>  	rx_p = &params.specific_params.rx_params;
> @@ -1592,6 +1592,16 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv
> *priv)
>  	return 0;
>  }
> 
> +static int dpaa_get_tstamp_ns(struct net_device *net_dev, u64 *ns,
> +			      struct fman_port *port, const void *data)
> +{
> +	if (!fman_port_get_tstamp_field(port, data, ns)) {
> +		be64_to_cpus(ns);

Please move this endianness conversion in the fman API.

> +		return 0;
> +	}
> +	return -EINVAL;
> +}
> +
>  /* Cleanup function for outgoing frame descriptors that were built on Tx
> path,
>   * either contiguous frames or scatter/gather ones.
>   * Skb freeing is not handled here.
> @@ -1607,14 +1617,29 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv
> *priv)
>  {
>  	const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
>  	struct device *dev = priv->net_dev->dev.parent;
> +	struct skb_shared_hwtstamps shhwtstamps;
>  	dma_addr_t addr = qm_fd_addr(fd);
>  	const struct qm_sg_entry *sgt;
>  	struct sk_buff **skbh, *skb;
>  	int nr_frags, i;
> +	u64 ns;
> 
>  	skbh = (struct sk_buff **)phys_to_virt(addr);
>  	skb = *skbh;
> 
> +	if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags &
> SKBTX_HW_TSTAMP) {
> +		memset(&shhwtstamps, 0, sizeof(shhwtstamps));
> +
> +		if (!dpaa_get_tstamp_ns(priv->net_dev, &ns,
> +					priv->mac_dev->port[TX],
> +					(void *)skbh)) {
> +			shhwtstamps.hwtstamp = ns_to_ktime(ns);
> +			skb_tstamp_tx(skb, &shhwtstamps);
> +		} else {
> +			dev_warn(dev, "dpaa_get_tstamp_ns failed!\n");
> +		}
> +	}
> +
>  	if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
>  		nr_frags = skb_shinfo(skb)->nr_frags;
>  		dma_unmap_single(dev, addr, qm_fd_get_offset(fd) +
> @@ -2086,6 +2111,11 @@ static int dpaa_start_xmit(struct sk_buff *skb,
> struct net_device *net_dev)
>  	if (unlikely(err < 0))
>  		goto skb_to_fd_failed;
> 
> +	if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags &
> SKBTX_HW_TSTAMP) {
> +		fd.cmd |= FM_FD_CMD_UPD;

The fd.cmd field is big endian, please use this:

+		fd.cmd |= cpu_to_be32(FM_FD_CMD_UPD);

> +		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
> +	}
> +
>  	if (likely(dpaa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0))
>  		return NETDEV_TX_OK;
> 
> @@ -2227,6 +2257,7 @@ static enum qman_cb_dqrr_result
> rx_default_dqrr(struct qman_portal *portal,
>  						struct qman_fq *fq,
>  						const struct qm_dqrr_entry
> *dq)
>  {
> +	struct skb_shared_hwtstamps *shhwtstamps;
>  	struct rtnl_link_stats64 *percpu_stats;
>  	struct dpaa_percpu_priv *percpu_priv;
>  	const struct qm_fd *fd = &dq->fd;
> @@ -2240,6 +2271,7 @@ static enum qman_cb_dqrr_result
> rx_default_dqrr(struct qman_portal *portal,
>  	struct sk_buff *skb;
>  	int *count_ptr;
>  	void *vaddr;
> +	u64 ns;
> 
>  	fd_status = be32_to_cpu(fd->status);
>  	fd_format = qm_fd_get_format(fd);
> @@ -2304,6 +2336,18 @@ static enum qman_cb_dqrr_result
> rx_default_dqrr(struct qman_portal *portal,
>  	if (!skb)
>  		return qman_cb_dqrr_consume;
> 
> +	if (priv->rx_tstamp) {
> +		shhwtstamps = skb_hwtstamps(skb);
> +		memset(shhwtstamps, 0, sizeof(*shhwtstamps));
> +
> +		if (!dpaa_get_tstamp_ns(priv->net_dev, &ns,
> +					priv->mac_dev->port[RX],
> +					vaddr))
> +			shhwtstamps->hwtstamp = ns_to_ktime(ns);
> +		else
> +			dev_warn(net_dev->dev.parent,
> "dpaa_get_tstamp_ns failed!\n");
> +	}
> +
>  	skb->protocol = eth_type_trans(skb, net_dev);
> 
>  	if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use
> &&
> @@ -2523,11 +2567,58 @@ static int dpaa_eth_stop(struct net_device
> *net_dev)
>  	return err;
>  }
> 
> +static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> +{
> +	struct dpaa_priv *priv = netdev_priv(dev);
> +	struct hwtstamp_config config;
> +
> +	if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
> +		return -EFAULT;
> +
> +	switch (config.tx_type) {
> +	case HWTSTAMP_TX_OFF:
> +		/* Couldn't disable rx/tx timestamping separately.
> +		 * Do nothing here.
> +		 */
> +		priv->tx_tstamp = false;
> +		break;
> +	case HWTSTAMP_TX_ON:
> +		priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac,
> true);
> +		priv->tx_tstamp = true;
> +		break;
> +	default:
> +		return -ERANGE;
> +	}
> +
> +	if (config.rx_filter == HWTSTAMP_FILTER_NONE) {
> +		/* Couldn't disable rx/tx timestamping separately.
> +		 * Do nothing here.
> +		 */
> +		priv->rx_tstamp = false;
> +	} else {
> +		priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac,
> true);
> +		priv->rx_tstamp = true;
> +		/* TS is set for all frame types, not only those requested */
> +		config.rx_filter = HWTSTAMP_FILTER_ALL;
> +	}
> +
> +	return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
> +			-EFAULT : 0;
> +}
> +
>  static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
>  {
> -	if (!net_dev->phydev)
> -		return -EINVAL;
> -	return phy_mii_ioctl(net_dev->phydev, rq, cmd);
> +	int ret = -EINVAL;
> +
> +	if (cmd == SIOCGMIIREG) {
> +		if (net_dev->phydev)
> +			return phy_mii_ioctl(net_dev->phydev, rq, cmd);
> +	}
> +
> +	if (cmd == SIOCSHWTSTAMP)
> +		return dpaa_ts_ioctl(net_dev, rq, cmd);
> +
> +	return ret;
>  }
> 
>  static const struct net_device_ops dpaa_ops = {
> diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> index bd94220..af320f8 100644
> --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
> @@ -182,6 +182,9 @@ struct dpaa_priv {
> 
>  	struct dpaa_buffer_layout buf_layout[2];
>  	u16 rx_headroom;
> +
> +	bool tx_tstamp; /* Tx timestamping enabled */
> +	bool rx_tstamp; /* Rx timestamping enabled */
>  };
> 
>  /* from dpaa_ethtool.c */
> --
> 1.7.1

^ permalink raw reply

* Re: [PATCH 0/5] can: enable multi-queue for SocketCAN devices
From: Jonas Mark (BT-FIR/ENG1) @ 2018-06-07  8:06 UTC (permalink / raw)
  To: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: linux-can@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, hs@denx.de,
	ZHU Yi (BT-FIR/ENG1-Zhu)

Hi Oliver,

> > The driver suite consists of three separate drivers. The following
> > diagram illustrates the dependencies in layers.
> >
> >             /dev/companion       SocketCAN                User Space
> > -------------------------------------------------------------------
> >           +----------------+ +---------------+
> >           | companion-char | | companion-can |
> >           +----------------+ +---------------+
> >           +----------------------------------+
> >           |          companion-spi           |
> >           +----------------------------------+
> >           +----------------------------------+
> >           |     standard SPI subsystem       |
> >           +----------------------------------+          Linux Kernel
> > -------------------------------------------------------------------
> >                 | | | |      | |                            Hardware
> >              CS-+ | | |      | +-BUSY
> >              CLK--+ | |      +---REQUEST
> >              MOSI---+ |
> >              MISO-----+
> >
> > companion-spi
> >     core.c: handles SPI, sysfs entry and interface to upper layer
> >     protocol-manager.c: handles protocol with the SPI HW
> >     queue-manager.c: handles buffering and packets scheduling
> >
> > companion-can
> >     makes use of multi-queue support and allows to use tc to configure
> >     the queuing discipline (e.g. mqprio). Together with the SO_PRIORITY
> >     socket option this allows to specify the FIFO a CAN frame shall be
> >     sent to.
> >
> > companion-char
> >     handles messages to other undisclosed functionality beyond CAN.

> >   .../devicetree/bindings/spi/bosch,companion.txt    |   82 ++
> >   drivers/char/Kconfig                               |    7 +
> >   drivers/char/Makefile                              |    2 +
> >   drivers/char/companion-char.c                      |  367 ++++++
> >   drivers/net/can/Kconfig                            |    8 +
> >   drivers/net/can/Makefile                           |    1 +
> >   drivers/net/can/companion-can.c                    |  694 ++++++++++++
> 
> Please place the companion driver in
> 
> drivers/net/can/spi/companion.c
> 
> It also makes more sense in the Kconfig structure.
> 
> Probably this naming scheme also makes sense for
> 
> linux/drivers/char/spi/companion.c
> 
> then ...
> 
> If not it should be named at least
> 
> drivers/char/companion-spi.c
> 
> or
> 
> drivers/char/spi-companion.c

We intentionally left out the spi in the driver path / name because
only the drivers/spi/companion/* driver knows that that it is connected
to SPI. The others (drivers/net/can/companion-can.c and
drivers/char/companion-char.c) only know the API. This could also be
supplied by a driver which talks to the Companion via a different
interface. Actually, we started with a UART connection but switched to
SPI due to latency issues.

Should we still change it?

> >   drivers/net/can/dev.c                              |    8 +-
> >   drivers/spi/Kconfig                                |    2 +
> >   drivers/spi/Makefile                               |    2 +
> >   drivers/spi/companion/Kconfig                      |    5 +
> >   drivers/spi/companion/Makefile                     |    2 +
> >   drivers/spi/companion/core.c                       | 1189 ++++++++++++++++++++
> >   drivers/spi/companion/protocol-manager.c           | 1035 +++++++++++++++++
> >   drivers/spi/companion/protocol-manager.h           |  348 ++++++
> >   drivers/spi/companion/protocol.h                   |  273 +++++
> >   drivers/spi/companion/queue-manager.c              |  146 +++
> >   drivers/spi/companion/queue-manager.h              |  245 ++++
> >   include/linux/can/dev.h                            |    7 +-
> >   include/linux/companion.h                          |  258 +++++
> >   20 files changed, 4677 insertions(+), 4 deletions(-)
> >   create mode 100644
> Documentation/devicetree/bindings/spi/bosch,companion.txt
> >   create mode 100644 drivers/char/companion-char.c
> >   create mode 100644 drivers/net/can/companion-can.c
> >   create mode 100644 drivers/spi/companion/Kconfig
> >   create mode 100644 drivers/spi/companion/Makefile
> >   create mode 100644 drivers/spi/companion/core.c
> >   create mode 100644 drivers/spi/companion/protocol-manager.c
> >   create mode 100644 drivers/spi/companion/protocol-manager.h
> >   create mode 100644 drivers/spi/companion/protocol.h
> >   create mode 100644 drivers/spi/companion/queue-manager.c
> >   create mode 100644 drivers/spi/companion/queue-manager.h
> >   create mode 100644 include/linux/companion.h

Greetings,
Mark

Building Technologies, Panel Software Fire (BT-FIR/ENG1) 
Bosch Sicherheitssysteme GmbH | Postfach 11 11 | 85626 Grasbrunn | GERMANY | www.boschsecurity.com

Sitz: Stuttgart, Registergericht: Amtsgericht Stuttgart HRB 23118 
Aufsichtsratsvorsitzender: Stefan Hartung; Geschäftsführung: Gert van Iperen, Andreas Bartz, Thomas Quante, Bernhard Schuster

^ permalink raw reply

* Re: [PATCH bpf-next 09/11] i40e: implement AF_XDP zero-copy support for Rx
From: Björn Töpel @ 2018-06-07  7:40 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Karlsson, Magnus, Magnus Karlsson, Duyck, Alexander H,
	Alexei Starovoitov, Jesper Dangaard Brouer, Daniel Borkmann,
	Netdev, MykytaI Iziumtsev, Björn Töpel, John Fastabend,
	Willem de Bruijn, Michael S. Tsirkin, michael.lundkvist,
	Brandeburg, Jesse, Singhai, Anjali, Zhang, Qi Z, Francois Ozog
In-Reply-To: <CAKgT0UcWpgZj10J8JC96wqX5DKzaLPpTWnHfNPX4ZK+Ua5V5Vg@mail.gmail.com>

Den mån 4 juni 2018 kl 22:35 skrev Alexander Duyck <alexander.duyck@gmail.com>:
>
> On Mon, Jun 4, 2018 at 5:05 AM, Björn Töpel <bjorn.topel@gmail.com> wrote:
> > From: Björn Töpel <bjorn.topel@intel.com>
> >
> > This commit adds initial AF_XDP zero-copy support for i40e-based
> > NICs. First we add support for the new XDP_QUERY_XSK_UMEM and
> > XDP_SETUP_XSK_UMEM commands in ndo_bpf. This allows the AF_XDP socket
> > to pass a UMEM to the driver. The driver will then DMA map all the
> > frames in the UMEM for the driver. Next, the Rx code will allocate
> > frames from the UMEM fill queue, instead of the regular page
> > allocator.
> >
> > Externally, for the rest of the XDP code, the driver internal UMEM
> > allocator will appear as a MEM_TYPE_ZERO_COPY.
> >
> > The commit also introduces a completely new clean_rx_irq/allocator
> > functions for zero-copy, and means (functions pointers) to set
> > allocators and clean_rx functions.
> >
> > This first version does not support:
> > * passing frames to the stack via XDP_PASS (clone/copy to skb).
> > * doing XDP redirect to other than AF_XDP sockets
> >   (convert_to_xdp_frame does not clone the frame yet).
> >
> > Signed-off-by: Björn Töpel <bjorn.topel@intel.com>
> > ---
> >  drivers/net/ethernet/intel/i40e/Makefile    |   3 +-
> >  drivers/net/ethernet/intel/i40e/i40e.h      |  23 ++
> >  drivers/net/ethernet/intel/i40e/i40e_main.c |  35 +-
> >  drivers/net/ethernet/intel/i40e/i40e_txrx.c | 163 ++-------
> >  drivers/net/ethernet/intel/i40e/i40e_txrx.h | 128 ++++++-
> >  drivers/net/ethernet/intel/i40e/i40e_xsk.c  | 537 ++++++++++++++++++++++++++++
> >  drivers/net/ethernet/intel/i40e/i40e_xsk.h  |  17 +
> >  include/net/xdp_sock.h                      |  19 +
> >  net/xdp/xdp_umem.h                          |  10 -
> >  9 files changed, 789 insertions(+), 146 deletions(-)
> >  create mode 100644 drivers/net/ethernet/intel/i40e/i40e_xsk.c
> >  create mode 100644 drivers/net/ethernet/intel/i40e/i40e_xsk.h
> >
> > diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile
> > index 14397e7e9925..50590e8d1fd1 100644
> > --- a/drivers/net/ethernet/intel/i40e/Makefile
> > +++ b/drivers/net/ethernet/intel/i40e/Makefile
> > @@ -22,6 +22,7 @@ i40e-objs := i40e_main.o \
> >         i40e_txrx.o     \
> >         i40e_ptp.o      \
> >         i40e_client.o   \
> > -       i40e_virtchnl_pf.o
> > +       i40e_virtchnl_pf.o \
> > +       i40e_xsk.o
> >
> >  i40e-$(CONFIG_I40E_DCB) += i40e_dcb.o i40e_dcb_nl.o
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
> > index 7a80652e2500..20955e5dce02 100644
> > --- a/drivers/net/ethernet/intel/i40e/i40e.h
> > +++ b/drivers/net/ethernet/intel/i40e/i40e.h
> > @@ -786,6 +786,12 @@ struct i40e_vsi {
> >
> >         /* VSI specific handlers */
> >         irqreturn_t (*irq_handler)(int irq, void *data);
> > +
> > +       /* AF_XDP zero-copy */
> > +       struct xdp_umem **xsk_umems;
> > +       u16 num_xsk_umems_used;
> > +       u16 num_xsk_umems;
> > +
> >  } ____cacheline_internodealigned_in_smp;
> >
> >  struct i40e_netdev_priv {
> > @@ -1090,6 +1096,20 @@ static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
> >         return !!vsi->xdp_prog;
> >  }
> >
> > +static inline struct xdp_umem *i40e_xsk_umem(struct i40e_ring *ring)
> > +{
> > +       bool xdp_on = i40e_enabled_xdp_vsi(ring->vsi);
> > +       int qid = ring->queue_index;
> > +
> > +       if (ring_is_xdp(ring))
> > +               qid -= ring->vsi->alloc_queue_pairs;
> > +
> > +       if (!ring->vsi->xsk_umems || !ring->vsi->xsk_umems[qid] || !xdp_on)
> > +               return NULL;
> > +
> > +       return ring->vsi->xsk_umems[qid];
> > +}
> > +
> >  int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
> >  int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate);
> >  int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
> > @@ -1098,4 +1118,7 @@ int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
> >  int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
> >                                       struct i40e_cloud_filter *filter,
> >                                       bool add);
> > +int i40e_queue_pair_enable(struct i40e_vsi *vsi, int queue_pair);
> > +int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair);
> > +
> >  #endif /* _I40E_H_ */
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> > index 369a116edaa1..8c602424d339 100644
> > --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> > +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> > @@ -5,6 +5,7 @@
> >  #include <linux/of_net.h>
> >  #include <linux/pci.h>
> >  #include <linux/bpf.h>
> > +#include <net/xdp_sock.h>
> >
> >  /* Local includes */
> >  #include "i40e.h"
> > @@ -16,6 +17,7 @@
> >   */
> >  #define CREATE_TRACE_POINTS
> >  #include "i40e_trace.h"
> > +#include "i40e_xsk.h"
> >
> >  const char i40e_driver_name[] = "i40e";
> >  static const char i40e_driver_string[] =
> > @@ -3071,6 +3073,9 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
> >         i40e_status err = 0;
> >         u32 qtx_ctl = 0;
> >
> > +       if (ring_is_xdp(ring))
> > +               ring->xsk_umem = i40e_xsk_umem(ring);
> > +
> >         /* some ATR related tx ring init */
> >         if (vsi->back->flags & I40E_FLAG_FD_ATR_ENABLED) {
> >                 ring->atr_sample_rate = vsi->back->atr_sample_rate;
> > @@ -3180,13 +3185,30 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
> >         struct i40e_hw *hw = &vsi->back->hw;
> >         struct i40e_hmc_obj_rxq rx_ctx;
> >         i40e_status err = 0;
> > +       int ret;
> >
> >         bitmap_zero(ring->state, __I40E_RING_STATE_NBITS);
> >
> >         /* clear the context structure first */
> >         memset(&rx_ctx, 0, sizeof(rx_ctx));
> >
> > -       ring->rx_buf_len = vsi->rx_buf_len;
> > +       ring->xsk_umem = i40e_xsk_umem(ring);
> > +       if (ring->xsk_umem) {
> > +               ring->clean_rx_irq = i40e_clean_rx_irq_zc;
> > +               ring->alloc_rx_buffers = i40e_alloc_rx_buffers_zc;
> > +               ring->rx_buf_len = ring->xsk_umem->chunk_size_nohr -
> > +                                  XDP_PACKET_HEADROOM;
> > +               ring->zca.free = i40e_zca_free;
> > +               ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
> > +                                                MEM_TYPE_ZERO_COPY,
> > +                                                &ring->zca);
> > +               if (ret)
> > +                       return ret;
> > +       } else {
> > +               ring->clean_rx_irq = i40e_clean_rx_irq;
> > +               ring->alloc_rx_buffers = i40e_alloc_rx_buffers;
> > +               ring->rx_buf_len = vsi->rx_buf_len;
> > +       }
>
> With everything that is going on with retpoline overhead I am really
> wary of this. We may want to look at finding another way to do this
> instead of just function pointers so that we can avoid the extra
> function pointer overhead. We may want to look at a flag for this
> instead of using function pointers.
>
> >         rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
> >                                     BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
> > @@ -3242,7 +3264,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
> >         ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
> >         writel(0, ring->tail);
> >
> > -       i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
> > +       ring->alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
> >
> >         return 0;
> >  }
> > @@ -12022,7 +12044,7 @@ static void i40e_queue_pair_disable_irq(struct i40e_vsi *vsi, int queue_pair)
> >   *
> >   * Returns 0 on success, <0 on failure.
> >   **/
> > -static int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair)
> > +int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair)
> >  {
> >         int err;
> >
> > @@ -12047,7 +12069,7 @@ static int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair)
> >   *
> >   * Returns 0 on success, <0 on failure.
> >   **/
> > -static int i40e_queue_pair_enable(struct i40e_vsi *vsi, int queue_pair)
> > +int i40e_queue_pair_enable(struct i40e_vsi *vsi, int queue_pair)
> >  {
> >         int err;
> >
> > @@ -12095,6 +12117,11 @@ static int i40e_xdp(struct net_device *dev,
> >                 xdp->prog_attached = i40e_enabled_xdp_vsi(vsi);
> >                 xdp->prog_id = vsi->xdp_prog ? vsi->xdp_prog->aux->id : 0;
> >                 return 0;
> > +       case XDP_QUERY_XSK_UMEM:
> > +               return 0;
> > +       case XDP_SETUP_XSK_UMEM:
> > +               return i40e_xsk_umem_setup(vsi, xdp->xsk.umem,
> > +                                          xdp->xsk.queue_id);
> >         default:
> >                 return -EINVAL;
> >         }
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
> > index 5f01e4ce9c92..6b1142fbc697 100644
> > --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
> > +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
> > @@ -5,6 +5,7 @@
> >  #include <net/busy_poll.h>
> >  #include <linux/bpf_trace.h>
> >  #include <net/xdp.h>
> > +#include <net/xdp_sock.h>
> >  #include "i40e.h"
> >  #include "i40e_trace.h"
> >  #include "i40e_prototype.h"
> > @@ -536,8 +537,8 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
> >   * This is used to verify if the FD programming or invalidation
> >   * requested by SW to the HW is successful or not and take actions accordingly.
> >   **/
> > -static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
> > -                                 union i40e_rx_desc *rx_desc, u8 prog_id)
> > +void i40e_fd_handle_status(struct i40e_ring *rx_ring,
> > +                          union i40e_rx_desc *rx_desc, u8 prog_id)
> >  {
> >         struct i40e_pf *pf = rx_ring->vsi->back;
> >         struct pci_dev *pdev = pf->pdev;
> > @@ -1246,25 +1247,6 @@ static void i40e_reuse_rx_page(struct i40e_ring *rx_ring,
> >         new_buff->pagecnt_bias  = old_buff->pagecnt_bias;
> >  }
> >
> > -/**
> > - * i40e_rx_is_programming_status - check for programming status descriptor
> > - * @qw: qword representing status_error_len in CPU ordering
> > - *
> > - * The value of in the descriptor length field indicate if this
> > - * is a programming status descriptor for flow director or FCoE
> > - * by the value of I40E_RX_PROG_STATUS_DESC_LENGTH, otherwise
> > - * it is a packet descriptor.
> > - **/
> > -static inline bool i40e_rx_is_programming_status(u64 qw)
> > -{
> > -       /* The Rx filter programming status and SPH bit occupy the same
> > -        * spot in the descriptor. Since we don't support packet split we
> > -        * can just reuse the bit as an indication that this is a
> > -        * programming status descriptor.
> > -        */
> > -       return qw & I40E_RXD_QW1_LENGTH_SPH_MASK;
> > -}
> > -
> >  /**
> >   * i40e_clean_programming_status - clean the programming status descriptor
> >   * @rx_ring: the rx ring that has this descriptor
> > @@ -1373,31 +1355,35 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
> >         }
> >
> >         /* Free all the Rx ring sk_buffs */
> > -       for (i = 0; i < rx_ring->count; i++) {
> > -               struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
> > -
> > -               if (!rx_bi->page)
> > -                       continue;
> > +       if (!rx_ring->xsk_umem) {
>
> Instead of changing the indent on all this code it would probably be
> easier to just add a goto and a label to skip all this.
>
> > +               for (i = 0; i < rx_ring->count; i++) {
> > +                       struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
> >
> > -               /* Invalidate cache lines that may have been written to by
> > -                * device so that we avoid corrupting memory.
> > -                */
> > -               dma_sync_single_range_for_cpu(rx_ring->dev,
> > -                                             rx_bi->dma,
> > -                                             rx_bi->page_offset,
> > -                                             rx_ring->rx_buf_len,
> > -                                             DMA_FROM_DEVICE);
> > -
> > -               /* free resources associated with mapping */
> > -               dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma,
> > -                                    i40e_rx_pg_size(rx_ring),
> > -                                    DMA_FROM_DEVICE,
> > -                                    I40E_RX_DMA_ATTR);
> > -
> > -               __page_frag_cache_drain(rx_bi->page, rx_bi->pagecnt_bias);
> > +                       if (!rx_bi->page)
> > +                               continue;
> >
> > -               rx_bi->page = NULL;
> > -               rx_bi->page_offset = 0;
> > +                       /* Invalidate cache lines that may have been
> > +                        * written to by device so that we avoid
> > +                        * corrupting memory.
> > +                        */
> > +                       dma_sync_single_range_for_cpu(rx_ring->dev,
> > +                                                     rx_bi->dma,
> > +                                                     rx_bi->page_offset,
> > +                                                     rx_ring->rx_buf_len,
> > +                                                     DMA_FROM_DEVICE);
> > +
> > +                       /* free resources associated with mapping */
> > +                       dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma,
> > +                                            i40e_rx_pg_size(rx_ring),
> > +                                            DMA_FROM_DEVICE,
> > +                                            I40E_RX_DMA_ATTR);
> > +
> > +                       __page_frag_cache_drain(rx_bi->page,
> > +                                               rx_bi->pagecnt_bias);
> > +
> > +                       rx_bi->page = NULL;
> > +                       rx_bi->page_offset = 0;
> > +               }
> >         }
> >
> >         bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count;
> > @@ -1487,27 +1473,6 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
> >         return err;
> >  }
> >
> > -/**
> > - * i40e_release_rx_desc - Store the new tail and head values
> > - * @rx_ring: ring to bump
> > - * @val: new head index
> > - **/
> > -static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
> > -{
> > -       rx_ring->next_to_use = val;
> > -
> > -       /* update next to alloc since we have filled the ring */
> > -       rx_ring->next_to_alloc = val;
> > -
> > -       /* Force memory writes to complete before letting h/w
> > -        * know there are new descriptors to fetch.  (Only
> > -        * applicable for weak-ordered memory model archs,
> > -        * such as IA-64).
> > -        */
> > -       wmb();
> > -       writel(val, rx_ring->tail);
> > -}
> > -
> >  /**
> >   * i40e_rx_offset - Return expected offset into page to access data
> >   * @rx_ring: Ring we are requesting offset of
> > @@ -1576,8 +1541,8 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
> >   * @skb: packet to send up
> >   * @vlan_tag: vlan tag for packet
> >   **/
> > -static void i40e_receive_skb(struct i40e_ring *rx_ring,
> > -                            struct sk_buff *skb, u16 vlan_tag)
> > +void i40e_receive_skb(struct i40e_ring *rx_ring,
> > +                     struct sk_buff *skb, u16 vlan_tag)
> >  {
> >         struct i40e_q_vector *q_vector = rx_ring->q_vector;
> >
> > @@ -1804,7 +1769,6 @@ static inline void i40e_rx_hash(struct i40e_ring *ring,
> >   * order to populate the hash, checksum, VLAN, protocol, and
> >   * other fields within the skb.
> >   **/
> > -static inline
> >  void i40e_process_skb_fields(struct i40e_ring *rx_ring,
> >                              union i40e_rx_desc *rx_desc, struct sk_buff *skb,
> >                              u8 rx_ptype)
> > @@ -1829,46 +1793,6 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,
> >         skb->protocol = eth_type_trans(skb, rx_ring->netdev);
> >  }
> >
> > -/**
> > - * i40e_cleanup_headers - Correct empty headers
> > - * @rx_ring: rx descriptor ring packet is being transacted on
> > - * @skb: pointer to current skb being fixed
> > - * @rx_desc: pointer to the EOP Rx descriptor
> > - *
> > - * Also address the case where we are pulling data in on pages only
> > - * and as such no data is present in the skb header.
> > - *
> > - * In addition if skb is not at least 60 bytes we need to pad it so that
> > - * it is large enough to qualify as a valid Ethernet frame.
> > - *
> > - * Returns true if an error was encountered and skb was freed.
> > - **/
> > -static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb,
> > -                                union i40e_rx_desc *rx_desc)
> > -
> > -{
> > -       /* XDP packets use error pointer so abort at this point */
> > -       if (IS_ERR(skb))
> > -               return true;
> > -
> > -       /* ERR_MASK will only have valid bits if EOP set, and
> > -        * what we are doing here is actually checking
> > -        * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in
> > -        * the error field
> > -        */
> > -       if (unlikely(i40e_test_staterr(rx_desc,
> > -                                      BIT(I40E_RXD_QW1_ERROR_SHIFT)))) {
> > -               dev_kfree_skb_any(skb);
> > -               return true;
> > -       }
> > -
> > -       /* if eth_skb_pad returns an error the skb was freed */
> > -       if (eth_skb_pad(skb))
> > -               return true;
> > -
> > -       return false;
> > -}
> > -
> >  /**
> >   * i40e_page_is_reusable - check if any reuse is possible
> >   * @page: page struct to check
> > @@ -2177,15 +2101,11 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
> >         return true;
> >  }
> >
> > -#define I40E_XDP_PASS 0
> > -#define I40E_XDP_CONSUMED 1
> > -#define I40E_XDP_TX 2
> > -
> >  static int i40e_xmit_xdp_ring(struct xdp_frame *xdpf,
> >                               struct i40e_ring *xdp_ring);
> >
> > -static int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp,
> > -                                struct i40e_ring *xdp_ring)
> > +int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp,
> > +                         struct i40e_ring *xdp_ring)
> >  {
> >         struct xdp_frame *xdpf = convert_to_xdp_frame(xdp);
> >
> > @@ -2214,8 +2134,6 @@ static struct sk_buff *i40e_run_xdp(struct i40e_ring *rx_ring,
> >         if (!xdp_prog)
> >                 goto xdp_out;
> >
> > -       prefetchw(xdp->data_hard_start); /* xdp_frame write */
> > -
> >         act = bpf_prog_run_xdp(xdp_prog, xdp);
> >         switch (act) {
> >         case XDP_PASS:
> > @@ -2263,15 +2181,6 @@ static void i40e_rx_buffer_flip(struct i40e_ring *rx_ring,
> >  #endif
> >  }
> >
> > -static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring)
> > -{
> > -       /* Force memory writes to complete before letting h/w
> > -        * know there are new descriptors to fetch.
> > -        */
> > -       wmb();
> > -       writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail);
> > -}
> > -
> >  /**
> >   * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf
> >   * @rx_ring: rx descriptor ring to transact packets on
> > @@ -2284,7 +2193,7 @@ static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring)
> >   *
> >   * Returns amount of work completed
> >   **/
> > -static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
> > +int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
> >  {
> >         unsigned int total_rx_bytes = 0, total_rx_packets = 0;
> >         struct sk_buff *skb = rx_ring->skb;
> > @@ -2576,7 +2485,7 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
> >         budget_per_ring = max(budget/q_vector->num_ringpairs, 1);
> >
> >         i40e_for_each_ring(ring, q_vector->rx) {
> > -               int cleaned = i40e_clean_rx_irq(ring, budget_per_ring);
> > +               int cleaned = ring->clean_rx_irq(ring, budget_per_ring);
> >
> >                 work_done += cleaned;
> >                 /* if we clean as many as budgeted, we must not be done */
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
> > index 820f76db251b..cddb185cd2f8 100644
> > --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
> > +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
> > @@ -296,13 +296,22 @@ struct i40e_tx_buffer {
> >
> >  struct i40e_rx_buffer {
> >         dma_addr_t dma;
> > -       struct page *page;
> > +       union {
> > +               struct {
> > +                       struct page *page;
> >  #if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
> > -       __u32 page_offset;
> > +                       __u32 page_offset;
> >  #else
> > -       __u16 page_offset;
> > +                       __u16 page_offset;
> >  #endif
> > -       __u16 pagecnt_bias;
> > +                       __u16 pagecnt_bias;
> > +               };
> > +               struct {
> > +                       /* for umem */
> > +                       void *addr;
> > +                       u64 handle;
> > +               };
>
> It might work better to just do this as a pair of unions. One for
> page/addr and another for handle, page_offset, and pagecnt_bias.
>
> > +       };
> >  };
> >
> >  struct i40e_queue_stats {
> > @@ -414,6 +423,12 @@ struct i40e_ring {
> >
> >         struct i40e_channel *ch;
> >         struct xdp_rxq_info xdp_rxq;
> > +
> > +       int (*clean_rx_irq)(struct i40e_ring *ring, int budget);
> > +       bool (*alloc_rx_buffers)(struct i40e_ring *ring, u16 n);
> > +       struct xdp_umem *xsk_umem;
> > +
> > +       struct zero_copy_allocator zca; /* ZC allocator anchor */
> >  } ____cacheline_internodealigned_in_smp;
> >
> >  static inline bool ring_uses_build_skb(struct i40e_ring *ring)
> > @@ -490,6 +505,7 @@ bool __i40e_chk_linearize(struct sk_buff *skb);
> >  int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
> >                   u32 flags);
> >  void i40e_xdp_flush(struct net_device *dev);
> > +int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget);
> >
> >  /**
> >   * i40e_get_head - Retrieve head from head writeback
> > @@ -576,4 +592,108 @@ static inline struct netdev_queue *txring_txq(const struct i40e_ring *ring)
> >  {
> >         return netdev_get_tx_queue(ring->netdev, ring->queue_index);
> >  }
> > +
> > +#define I40E_XDP_PASS 0
> > +#define I40E_XDP_CONSUMED 1
> > +#define I40E_XDP_TX 2
> > +
> > +/**
> > + * i40e_release_rx_desc - Store the new tail and head values
> > + * @rx_ring: ring to bump
> > + * @val: new head index
> > + **/
> > +static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
> > +{
> > +       rx_ring->next_to_use = val;
> > +
> > +       /* update next to alloc since we have filled the ring */
> > +       rx_ring->next_to_alloc = val;
> > +
> > +       /* Force memory writes to complete before letting h/w
> > +        * know there are new descriptors to fetch.  (Only
> > +        * applicable for weak-ordered memory model archs,
> > +        * such as IA-64).
> > +        */
> > +       wmb();
> > +       writel(val, rx_ring->tail);
> > +}
> > +
> > +/**
> > + * i40e_rx_is_programming_status - check for programming status descriptor
> > + * @qw: qword representing status_error_len in CPU ordering
> > + *
> > + * The value of in the descriptor length field indicate if this
> > + * is a programming status descriptor for flow director or FCoE
> > + * by the value of I40E_RX_PROG_STATUS_DESC_LENGTH, otherwise
> > + * it is a packet descriptor.
> > + **/
> > +static inline bool i40e_rx_is_programming_status(u64 qw)
> > +{
> > +       /* The Rx filter programming status and SPH bit occupy the same
> > +        * spot in the descriptor. Since we don't support packet split we
> > +        * can just reuse the bit as an indication that this is a
> > +        * programming status descriptor.
> > +        */
> > +       return qw & I40E_RXD_QW1_LENGTH_SPH_MASK;
> > +}
> > +
> > +/**
> > + * i40e_cleanup_headers - Correct empty headers
> > + * @rx_ring: rx descriptor ring packet is being transacted on
> > + * @skb: pointer to current skb being fixed
> > + * @rx_desc: pointer to the EOP Rx descriptor
> > + *
> > + * Also address the case where we are pulling data in on pages only
> > + * and as such no data is present in the skb header.
> > + *
> > + * In addition if skb is not at least 60 bytes we need to pad it so that
> > + * it is large enough to qualify as a valid Ethernet frame.
> > + *
> > + * Returns true if an error was encountered and skb was freed.
> > + **/
> > +static inline bool i40e_cleanup_headers(struct i40e_ring *rx_ring,
> > +                                       struct sk_buff *skb,
> > +                                       union i40e_rx_desc *rx_desc)
> > +
> > +{
> > +       /* XDP packets use error pointer so abort at this point */
> > +       if (IS_ERR(skb))
> > +               return true;
> > +
> > +       /* ERR_MASK will only have valid bits if EOP set, and
> > +        * what we are doing here is actually checking
> > +        * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in
> > +        * the error field
> > +        */
> > +       if (unlikely(i40e_test_staterr(rx_desc,
> > +                                      BIT(I40E_RXD_QW1_ERROR_SHIFT)))) {
> > +               dev_kfree_skb_any(skb);
> > +               return true;
> > +       }
> > +
> > +       /* if eth_skb_pad returns an error the skb was freed */
> > +       if (eth_skb_pad(skb))
> > +               return true;
> > +
> > +       return false;
> > +}
> > +
> > +static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring)
> > +{
> > +       /* Force memory writes to complete before letting h/w
> > +        * know there are new descriptors to fetch.
> > +        */
> > +       wmb();
> > +       writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail);
> > +}
> > +
> > +void i40e_fd_handle_status(struct i40e_ring *rx_ring,
> > +                          union i40e_rx_desc *rx_desc, u8 prog_id);
> > +int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp,
> > +                         struct i40e_ring *xdp_ring);
> > +void i40e_process_skb_fields(struct i40e_ring *rx_ring,
> > +                            union i40e_rx_desc *rx_desc, struct sk_buff *skb,
> > +                            u8 rx_ptype);
> > +void i40e_receive_skb(struct i40e_ring *rx_ring,
> > +                     struct sk_buff *skb, u16 vlan_tag);
> >  #endif /* _I40E_TXRX_H_ */
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> > new file mode 100644
> > index 000000000000..9d16924415b9
> > --- /dev/null
> > +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> > @@ -0,0 +1,537 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/* Copyright(c) 2018 Intel Corporation. */
> > +
> > +#include <linux/bpf_trace.h>
> > +#include <net/xdp_sock.h>
> > +#include <net/xdp.h>
> > +
> > +#include "i40e.h"
> > +#include "i40e_txrx.h"
> > +
> > +static int i40e_alloc_xsk_umems(struct i40e_vsi *vsi)
> > +{
> > +       if (vsi->xsk_umems)
> > +               return 0;
> > +
> > +       vsi->num_xsk_umems_used = 0;
> > +       vsi->num_xsk_umems = vsi->alloc_queue_pairs;
> > +       vsi->xsk_umems = kcalloc(vsi->num_xsk_umems, sizeof(*vsi->xsk_umems),
> > +                                GFP_KERNEL);
> > +       if (!vsi->xsk_umems) {
> > +               vsi->num_xsk_umems = 0;
> > +               return -ENOMEM;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int i40e_add_xsk_umem(struct i40e_vsi *vsi, struct xdp_umem *umem,
> > +                            u16 qid)
> > +{
> > +       int err;
> > +
> > +       err = i40e_alloc_xsk_umems(vsi);
> > +       if (err)
> > +               return err;
> > +
> > +       vsi->xsk_umems[qid] = umem;
> > +       vsi->num_xsk_umems_used++;
> > +
> > +       return 0;
> > +}
> > +
> > +static void i40e_remove_xsk_umem(struct i40e_vsi *vsi, u16 qid)
> > +{
> > +       vsi->xsk_umems[qid] = NULL;
> > +       vsi->num_xsk_umems_used--;
> > +
> > +       if (vsi->num_xsk_umems == 0) {
> > +               kfree(vsi->xsk_umems);
> > +               vsi->xsk_umems = NULL;
> > +               vsi->num_xsk_umems = 0;
> > +       }
> > +}
> > +
> > +static int i40e_xsk_umem_dma_map(struct i40e_vsi *vsi, struct xdp_umem *umem)
> > +{
> > +       struct i40e_pf *pf = vsi->back;
> > +       struct device *dev;
> > +       unsigned int i, j;
> > +       dma_addr_t dma;
> > +
> > +       dev = &pf->pdev->dev;
> > +       for (i = 0; i < umem->npgs; i++) {
> > +               dma = dma_map_page_attrs(dev, umem->pgs[i], 0, PAGE_SIZE,
> > +                                        DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR);
> > +               if (dma_mapping_error(dev, dma))
> > +                       goto out_unmap;
> > +
> > +               umem->pages[i].dma = dma;
> > +       }
> > +
> > +       return 0;
> > +
> > +out_unmap:
> > +       for (j = 0; j < i; j++) {
> > +               dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE,
> > +                                    DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR);
> > +               umem->pages[i].dma = 0;
> > +       }
> > +
> > +       return -1;
> > +}
> > +
> > +static void i40e_xsk_umem_dma_unmap(struct i40e_vsi *vsi, struct xdp_umem *umem)
> > +{
> > +       struct i40e_pf *pf = vsi->back;
> > +       struct device *dev;
> > +       unsigned int i;
> > +
> > +       dev = &pf->pdev->dev;
> > +
> > +       for (i = 0; i < umem->npgs; i++) {
> > +               dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE,
> > +                                    DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR);
> > +
> > +               umem->pages[i].dma = 0;
> > +       }
> > +}
> > +
> > +static int i40e_xsk_umem_enable(struct i40e_vsi *vsi, struct xdp_umem *umem,
> > +                               u16 qid)
> > +{
> > +       bool if_running;
> > +       int err;
> > +
> > +       if (vsi->type != I40E_VSI_MAIN)
> > +               return -EINVAL;
> > +
> > +       if (qid >= vsi->num_queue_pairs)
> > +               return -EINVAL;
> > +
> > +       if (vsi->xsk_umems && vsi->xsk_umems[qid])
> > +               return -EBUSY;
> > +
> > +       err = i40e_xsk_umem_dma_map(vsi, umem);
> > +       if (err)
> > +               return err;
> > +
> > +       if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi);
> > +
> > +       if (if_running) {
> > +               err = i40e_queue_pair_disable(vsi, qid);
> > +               if (err)
> > +                       return err;
> > +       }
> > +
> > +       err = i40e_add_xsk_umem(vsi, umem, qid);
> > +       if (err)
> > +               return err;
> > +
> > +       if (if_running) {
> > +               err = i40e_queue_pair_enable(vsi, qid);
> > +               if (err)
> > +                       return err;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int i40e_xsk_umem_disable(struct i40e_vsi *vsi, u16 qid)
> > +{
> > +       bool if_running;
> > +       int err;
> > +
> > +       if (!vsi->xsk_umems || qid >= vsi->num_xsk_umems ||
> > +           !vsi->xsk_umems[qid])
> > +               return -EINVAL;
> > +
> > +       if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi);
> > +
> > +       if (if_running) {
> > +               err = i40e_queue_pair_disable(vsi, qid);
> > +               if (err)
> > +                       return err;
> > +       }
> > +
> > +       i40e_xsk_umem_dma_unmap(vsi, vsi->xsk_umems[qid]);
> > +       i40e_remove_xsk_umem(vsi, qid);
> > +
> > +       if (if_running) {
> > +               err = i40e_queue_pair_enable(vsi, qid);
> > +               if (err)
> > +                       return err;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +int i40e_xsk_umem_setup(struct i40e_vsi *vsi, struct xdp_umem *umem,
> > +                       u16 qid)
> > +{
> > +       if (umem)
> > +               return i40e_xsk_umem_enable(vsi, umem, qid);
> > +
> > +       return i40e_xsk_umem_disable(vsi, qid);
> > +}
> > +
> > +static struct sk_buff *i40e_run_xdp_zc(struct i40e_ring *rx_ring,
> > +                                      struct xdp_buff *xdp)
> > +{
> > +       int err, result = I40E_XDP_PASS;
> > +       struct i40e_ring *xdp_ring;
> > +       struct bpf_prog *xdp_prog;
> > +       u32 act;
> > +       u16 off;
> > +
> > +       rcu_read_lock();
> > +       xdp_prog = READ_ONCE(rx_ring->xdp_prog);
> > +       act = bpf_prog_run_xdp(xdp_prog, xdp);
> > +       off = xdp->data - xdp->data_hard_start;
> > +       xdp->handle += off;
> > +       switch (act) {
> > +       case XDP_PASS:
> > +               break;
> > +       case XDP_TX:
> > +               xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index];
> > +               result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
> > +               break;
> > +       case XDP_REDIRECT:
> > +               err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
> > +               result = !err ? I40E_XDP_TX : I40E_XDP_CONSUMED;
> > +               break;
> > +       default:
> > +               bpf_warn_invalid_xdp_action(act);
> > +       case XDP_ABORTED:
> > +               trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
> > +               /* fallthrough -- handle aborts by dropping packet */
> > +       case XDP_DROP:
> > +               result = I40E_XDP_CONSUMED;
> > +               break;
> > +       }
> > +
> > +       rcu_read_unlock();
> > +       return ERR_PTR(-result);
> > +}
> > +
> > +static bool i40e_alloc_frame_zc(struct i40e_ring *rx_ring,
> > +                               struct i40e_rx_buffer *bi)
> > +{
> > +       struct xdp_umem *umem = rx_ring->xsk_umem;
> > +       void *addr = bi->addr;
> > +       u64 handle;
> > +
> > +       if (addr) {
> > +               rx_ring->rx_stats.page_reuse_count++;
> > +               return true;
> > +       }
> > +
> > +       if (!xsk_umem_peek_addr(umem, &handle)) {
> > +               rx_ring->rx_stats.alloc_page_failed++;
> > +               return false;
> > +       }
> > +
> > +       bi->dma = xdp_umem_get_dma(umem, handle);
> > +       bi->addr = xdp_umem_get_data(umem, handle);
> > +
> > +       bi->dma += umem->headroom + XDP_PACKET_HEADROOM;
> > +       bi->addr += umem->headroom + XDP_PACKET_HEADROOM;
> > +       bi->handle = handle + umem->headroom;
> > +
> > +       xsk_umem_discard_addr(umem);
> > +       return true;
> > +}
> > +
> > +bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 cleaned_count)
> > +{
> > +       u16 ntu = rx_ring->next_to_use;
> > +       union i40e_rx_desc *rx_desc;
> > +       struct i40e_rx_buffer *bi;
> > +
> > +       rx_desc = I40E_RX_DESC(rx_ring, ntu);
> > +       bi = &rx_ring->rx_bi[ntu];
> > +
> > +       do {
> > +               if (!i40e_alloc_frame_zc(rx_ring, bi))
> > +                       goto no_buffers;
> > +
> > +               /* sync the buffer for use by the device */
> > +               dma_sync_single_range_for_device(rx_ring->dev, bi->dma, 0,
> > +                                                rx_ring->rx_buf_len,
> > +                                                DMA_BIDIRECTIONAL);
> > +
> > +               /* Refresh the desc even if buffer_addrs didn't change
> > +                * because each write-back erases this info.
> > +                */
> > +               rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
> > +
> > +               rx_desc++;
> > +               bi++;
> > +               ntu++;
> > +               if (unlikely(ntu == rx_ring->count)) {
> > +                       rx_desc = I40E_RX_DESC(rx_ring, 0);
> > +                       bi = rx_ring->rx_bi;
> > +                       ntu = 0;
> > +               }
> > +
> > +               /* clear the status bits for the next_to_use descriptor */
> > +               rx_desc->wb.qword1.status_error_len = 0;
> > +
> > +               cleaned_count--;
> > +       } while (cleaned_count);
> > +
> > +       if (rx_ring->next_to_use != ntu)
> > +               i40e_release_rx_desc(rx_ring, ntu);
> > +
> > +       return false;
> > +
> > +no_buffers:
> > +       if (rx_ring->next_to_use != ntu)
> > +               i40e_release_rx_desc(rx_ring, ntu);
> > +
> > +       /* make sure to come back via polling to try again after
> > +        * allocation failure
> > +        */
> > +       return true;
> > +}
> > +
> > +static struct i40e_rx_buffer *i40e_get_rx_buffer_zc(struct i40e_ring *rx_ring,
> > +                                                   const unsigned int size)
> > +{
> > +       struct i40e_rx_buffer *rx_buffer;
> > +
> > +       rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
> > +
> > +       /* we are reusing so sync this buffer for CPU use */
> > +       dma_sync_single_range_for_cpu(rx_ring->dev,
> > +                                     rx_buffer->dma, 0,
> > +                                     size,
> > +                                     DMA_BIDIRECTIONAL);
> > +
> > +       return rx_buffer;
> > +}
> > +
> > +static void i40e_reuse_rx_buffer_zc(struct i40e_ring *rx_ring,
> > +                                   struct i40e_rx_buffer *old_buff)
> > +{
> > +       u64 mask = rx_ring->xsk_umem->props.chunk_mask;
> > +       u64 hr = rx_ring->xsk_umem->headroom;
> > +       u16 nta = rx_ring->next_to_alloc;
> > +       struct i40e_rx_buffer *new_buff;
> > +
> > +       new_buff = &rx_ring->rx_bi[nta];
> > +
> > +       /* update, and store next to alloc */
> > +       nta++;
> > +       rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
> > +
> > +       /* transfer page from old buffer to new buffer */
> > +       new_buff->dma           = old_buff->dma & mask;
> > +       new_buff->addr          = (void *)((u64)old_buff->addr & mask);
> > +       new_buff->handle        = old_buff->handle & mask;
> > +
> > +       new_buff->dma += hr + XDP_PACKET_HEADROOM;
> > +       new_buff->addr += hr + XDP_PACKET_HEADROOM;
> > +       new_buff->handle += hr;
> > +}
> > +
> > +/* Called from the XDP return API in NAPI context. */
> > +void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle)
> > +{
> > +       struct i40e_rx_buffer *new_buff;
> > +       struct i40e_ring *rx_ring;
> > +       u64 mask;
> > +       u16 nta;
> > +
> > +       rx_ring = container_of(alloc, struct i40e_ring, zca);
> > +       mask = rx_ring->xsk_umem->props.chunk_mask;
> > +
> > +       nta = rx_ring->next_to_alloc;
> > +
> > +       new_buff = &rx_ring->rx_bi[nta];
> > +
> > +       /* update, and store next to alloc */
> > +       nta++;
> > +       rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
> > +
> > +       handle &= mask;
> > +
> > +       new_buff->dma           = xdp_umem_get_dma(rx_ring->xsk_umem, handle);
> > +       new_buff->addr          = xdp_umem_get_data(rx_ring->xsk_umem, handle);
> > +       new_buff->handle        = (u64)handle;
> > +
> > +       new_buff->dma += rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM;
> > +       new_buff->addr += rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM;
> > +       new_buff->handle += rx_ring->xsk_umem->headroom;
> > +}
> > +
> > +static struct sk_buff *i40e_zc_frame_to_skb(struct i40e_ring *rx_ring,
> > +                                           struct i40e_rx_buffer *rx_buffer,
> > +                                           struct xdp_buff *xdp)
> > +{
> > +       /* XXX implement alloc skb and copy */
> > +       i40e_reuse_rx_buffer_zc(rx_ring, rx_buffer);
> > +       return NULL;
> > +}
> > +
> > +static void i40e_clean_programming_status_zc(struct i40e_ring *rx_ring,
> > +                                            union i40e_rx_desc *rx_desc,
> > +                                            u64 qw)
> > +{
> > +       struct i40e_rx_buffer *rx_buffer;
> > +       u32 ntc = rx_ring->next_to_clean;
> > +       u8 id;
> > +
> > +       /* fetch, update, and store next to clean */
> > +       rx_buffer = &rx_ring->rx_bi[ntc++];
> > +       ntc = (ntc < rx_ring->count) ? ntc : 0;
> > +       rx_ring->next_to_clean = ntc;
> > +
> > +       prefetch(I40E_RX_DESC(rx_ring, ntc));
> > +
> > +       /* place unused page back on the ring */
> > +       i40e_reuse_rx_buffer_zc(rx_ring, rx_buffer);
> > +       rx_ring->rx_stats.page_reuse_count++;
> > +
> > +       /* clear contents of buffer_info */
> > +       rx_buffer->addr = NULL;
> > +
> > +       id = (qw & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >>
> > +                 I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
> > +
> > +       if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
> > +               i40e_fd_handle_status(rx_ring, rx_desc, id);
> > +}
> > +
> > +int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
> > +{
> > +       unsigned int total_rx_bytes = 0, total_rx_packets = 0;
> > +       u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
> > +       bool failure = false, xdp_xmit = false;
> > +       struct sk_buff *skb;
> > +       struct xdp_buff xdp;
> > +
> > +       xdp.rxq = &rx_ring->xdp_rxq;
> > +
> > +       while (likely(total_rx_packets < (unsigned int)budget)) {
> > +               struct i40e_rx_buffer *rx_buffer;
> > +               union i40e_rx_desc *rx_desc;
> > +               unsigned int size;
> > +               u16 vlan_tag;
> > +               u8 rx_ptype;
> > +               u64 qword;
> > +               u32 ntc;
> > +
> > +               /* return some buffers to hardware, one at a time is too slow */
> > +               if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
> > +                       failure = failure ||
> > +                                 i40e_alloc_rx_buffers_zc(rx_ring,
> > +                                                          cleaned_count);
> > +                       cleaned_count = 0;
> > +               }
> > +
> > +               rx_desc = I40E_RX_DESC(rx_ring, rx_ring->next_to_clean);
> > +
> > +               /* status_error_len will always be zero for unused descriptors
> > +                * because it's cleared in cleanup, and overlaps with hdr_addr
> > +                * which is always zero because packet split isn't used, if the
> > +                * hardware wrote DD then the length will be non-zero
> > +                */
> > +               qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
> > +
> > +               /* This memory barrier is needed to keep us from reading
> > +                * any other fields out of the rx_desc until we have
> > +                * verified the descriptor has been written back.
> > +                */
> > +               dma_rmb();
> > +
> > +               if (unlikely(i40e_rx_is_programming_status(qword))) {
> > +                       i40e_clean_programming_status_zc(rx_ring, rx_desc,
> > +                                                        qword);
> > +                       cleaned_count++;
> > +                       continue;
> > +               }
> > +               size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
> > +                      I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
> > +               if (!size)
> > +                       break;
> > +
> > +               rx_buffer = i40e_get_rx_buffer_zc(rx_ring, size);
> > +
> > +               /* retrieve a buffer from the ring */
> > +               xdp.data = rx_buffer->addr;
> > +               xdp_set_data_meta_invalid(&xdp);
> > +               xdp.data_hard_start = xdp.data - XDP_PACKET_HEADROOM;
> > +               xdp.data_end = xdp.data + size;
> > +               xdp.handle = rx_buffer->handle;
> > +
> > +               skb = i40e_run_xdp_zc(rx_ring, &xdp);
> > +
> > +               if (IS_ERR(skb)) {
> > +                       if (PTR_ERR(skb) == -I40E_XDP_TX)
> > +                               xdp_xmit = true;
> > +                       else
> > +                               i40e_reuse_rx_buffer_zc(rx_ring, rx_buffer);
> > +                       total_rx_bytes += size;
> > +                       total_rx_packets++;
> > +               } else {
> > +                       skb = i40e_zc_frame_to_skb(rx_ring, rx_buffer, &xdp);
> > +                       if (!skb) {
> > +                               rx_ring->rx_stats.alloc_buff_failed++;
> > +                               break;
> > +                       }
> > +               }
> > +
> > +               rx_buffer->addr = NULL;
> > +               cleaned_count++;
> > +
> > +               /* don't care about non-EOP frames in XDP mode */
> > +               ntc = rx_ring->next_to_clean + 1;
> > +               ntc = (ntc < rx_ring->count) ? ntc : 0;
> > +               rx_ring->next_to_clean = ntc;
> > +               prefetch(I40E_RX_DESC(rx_ring, ntc));
> > +
> > +               if (i40e_cleanup_headers(rx_ring, skb, rx_desc)) {
> > +                       skb = NULL;
> > +                       continue;
> > +               }
> > +
> > +               /* probably a little skewed due to removing CRC */
> > +               total_rx_bytes += skb->len;
> > +
> > +               qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
> > +               rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
> > +                          I40E_RXD_QW1_PTYPE_SHIFT;
> > +
> > +               /* populate checksum, VLAN, and protocol */
> > +               i40e_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
> > +
> > +               vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
> > +                          le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0;
> > +
> > +               i40e_receive_skb(rx_ring, skb, vlan_tag);
> > +               skb = NULL;
> > +
> > +               /* update budget accounting */
> > +               total_rx_packets++;
> > +       }
> > +
> > +       if (xdp_xmit) {
> > +               struct i40e_ring *xdp_ring =
> > +                       rx_ring->vsi->xdp_rings[rx_ring->queue_index];
> > +
> > +               i40e_xdp_ring_update_tail(xdp_ring);
> > +               xdp_do_flush_map();
> > +       }
> > +
> > +       u64_stats_update_begin(&rx_ring->syncp);
> > +       rx_ring->stats.packets += total_rx_packets;
> > +       rx_ring->stats.bytes += total_rx_bytes;
> > +       u64_stats_update_end(&rx_ring->syncp);
> > +       rx_ring->q_vector->rx.total_packets += total_rx_packets;
> > +       rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
> > +
> > +       /* guarantee a trip back through this routine if there was a failure */
> > +       return failure ? budget : (int)total_rx_packets;
> > +}
> > +
>
> You should really look at adding comments to the code you are adding.
> From what I can tell almost all of the code comments were just copied
> exactly from the original functions in the i40e_txrx.c file.
>
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.h b/drivers/net/ethernet/intel/i40e/i40e_xsk.h
> > new file mode 100644
> > index 000000000000..757ac5ca8511
> > --- /dev/null
> > +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.h
> > @@ -0,0 +1,17 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/* Copyright(c) 2018 Intel Corporation. */
> > +
> > +#ifndef _I40E_XSK_H_
> > +#define _I40E_XSK_H_
> > +
> > +struct i40e_vsi;
> > +struct xdp_umem;
> > +struct zero_copy_allocator;
> > +
> > +int i40e_xsk_umem_setup(struct i40e_vsi *vsi, struct xdp_umem *umem,
> > +                       u16 qid);
> > +void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle);
> > +bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 cleaned_count);
> > +int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget);
> > +
> > +#endif /* _I40E_XSK_H_ */
> > diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
> > index 9fe472f2ac95..ec8fd3314097 100644
> > --- a/include/net/xdp_sock.h
> > +++ b/include/net/xdp_sock.h
> > @@ -94,6 +94,25 @@ static inline bool xsk_is_setup_for_bpf_map(struct xdp_sock *xs)
> >  {
> >         return false;
> >  }
> > +
> > +static inline u64 *xsk_umem_peek_addr(struct xdp_umem *umem, u64 *addr)
> > +{
> > +       return NULL;
> > +}
> > +
> > +static inline void xsk_umem_discard_addr(struct xdp_umem *umem)
> > +{
> > +}
> >  #endif /* CONFIG_XDP_SOCKETS */
> >
> > +static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
> > +{
> > +       return umem->pages[addr >> PAGE_SHIFT].addr + (addr & (PAGE_SIZE - 1));
> > +}
> > +
> > +static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr)
> > +{
> > +       return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1));
> > +}
> > +
> >  #endif /* _LINUX_XDP_SOCK_H */
> > diff --git a/net/xdp/xdp_umem.h b/net/xdp/xdp_umem.h
> > index f11560334f88..c8be1ad3eb88 100644
> > --- a/net/xdp/xdp_umem.h
> > +++ b/net/xdp/xdp_umem.h
> > @@ -8,16 +8,6 @@
> >
> >  #include <net/xdp_sock.h>
> >
> > -static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
> > -{
> > -       return umem->pages[addr >> PAGE_SHIFT].addr + (addr & (PAGE_SIZE - 1));
> > -}
> > -
> > -static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr)
> > -{
> > -       return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1));
> > -}
> > -
> >  int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
> >                         u32 queue_id, u16 flags);
> >  bool xdp_umem_validate_queues(struct xdp_umem *umem);
> > --
> > 2.14.1
> >

Apologies for the late response, Alex.

We'll address all the items above, and also your Tx ZC related
comments. Thanks for the quick reply!


Björn

^ permalink raw reply

* Re: [PATCH 0/5] can: enable multi-queue for SocketCAN devices
From: Oliver Hartkopp @ 2018-06-07  7:22 UTC (permalink / raw)
  To: Mark Jonas, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: linux-can, netdev, linux-kernel, hs, yi.zhu5
In-Reply-To: <1528224240-30786-1-git-send-email-mark.jonas@de.bosch.com>



On 06/05/2018 08:43 PM, Mark Jonas wrote:
> Upon request by Marc Kleine-Budde this patch series does not only
> contain our patch to enable enable multi-queue for SocketCAN devices
> but also a driver (Companion driver suite) which makes active use of
> this feature.
> 
> The driver suite implements
>    - two CAN interfaces
>    - one generic command interfaces
> and offers a SocketCAN as well as a char device interface. The
> SocketCAN interface supports multi-queue.
> 
> The functionality bases on an external peripheral chip named Companion.
> It offers two CAN interfaces, each has 8 prioritized transmit FIFOs as
> well as one receive FIFO. Besides CAN, undisclosed additional functions
> can be accessed through the char device.
> 
> A standard SPI interface with two additional lines for flow control is
> used. The Companion chip is the SPI slave.
> 
> The driver suite consists of three separate drivers. The following
> diagram illustrates the dependencies in layers.
> 
>             /dev/companion       SocketCAN                User Space
> -------------------------------------------------------------------
>           +----------------+ +---------------+
>           | companion-char | | companion-can |
>           +----------------+ +---------------+
>           +----------------------------------+
>           |          companion-spi           |
>           +----------------------------------+
>           +----------------------------------+
>           |     standard SPI subsystem       |
>           +----------------------------------+          Linux Kernel
> -------------------------------------------------------------------
>                 | | | |      | |                            Hardware
>              CS-+ | | |      | +-BUSY
>              CLK--+ | |      +---REQUEST
>              MOSI---+ |
>              MISO-----+
> 
> companion-spi
>     core.c: handles SPI, sysfs entry and interface to upper layer
>     protocol-manager.c: handles protocol with the SPI HW
>     queue-manager.c: handles buffering and packets scheduling
> 
> companion-can
>     makes use of multi-queue support and allows to use tc to configure
>     the queuing discipline (e.g. mqprio). Together with the SO_PRIORITY
>     socket option this allows to specify the FIFO a CAN frame shall be
>     sent to.
> 
> companion-char
>     handles messages to other undisclosed functionality beyond CAN.
> 
> Zhu Yi (5):
>    can: enable multi-queue for SocketCAN devices
>    spi: implement companion-spi driver
>    char: implement companion-char driver
>    can: implement companion-can driver
>    spi,can,char: add companion DT binding documentation
> 
>   .../devicetree/bindings/spi/bosch,companion.txt    |   82 ++
>   drivers/char/Kconfig                               |    7 +
>   drivers/char/Makefile                              |    2 +
>   drivers/char/companion-char.c                      |  367 ++++++
>   drivers/net/can/Kconfig                            |    8 +
>   drivers/net/can/Makefile                           |    1 +
>   drivers/net/can/companion-can.c                    |  694 ++++++++++++

Please place the companion driver in

drivers/net/can/spi/companion.c

It also makes more sense in the Kconfig structure.

Probably this naming scheme also makes sense for

linux/drivers/char/spi/companion.c

then ...

If not it should be named at least

drivers/char/companion-spi.c

or

drivers/char/spi-companion.c

BR Oliver

>   drivers/net/can/dev.c                              |    8 +-
>   drivers/spi/Kconfig                                |    2 +
>   drivers/spi/Makefile                               |    2 +
>   drivers/spi/companion/Kconfig                      |    5 +
>   drivers/spi/companion/Makefile                     |    2 +
>   drivers/spi/companion/core.c                       | 1189 ++++++++++++++++++++
>   drivers/spi/companion/protocol-manager.c           | 1035 +++++++++++++++++
>   drivers/spi/companion/protocol-manager.h           |  348 ++++++
>   drivers/spi/companion/protocol.h                   |  273 +++++
>   drivers/spi/companion/queue-manager.c              |  146 +++
>   drivers/spi/companion/queue-manager.h              |  245 ++++
>   include/linux/can/dev.h                            |    7 +-
>   include/linux/companion.h                          |  258 +++++
>   20 files changed, 4677 insertions(+), 4 deletions(-)
>   create mode 100644 Documentation/devicetree/bindings/spi/bosch,companion.txt
>   create mode 100644 drivers/char/companion-char.c
>   create mode 100644 drivers/net/can/companion-can.c
>   create mode 100644 drivers/spi/companion/Kconfig
>   create mode 100644 drivers/spi/companion/Makefile
>   create mode 100644 drivers/spi/companion/core.c
>   create mode 100644 drivers/spi/companion/protocol-manager.c
>   create mode 100644 drivers/spi/companion/protocol-manager.h
>   create mode 100644 drivers/spi/companion/protocol.h
>   create mode 100644 drivers/spi/companion/queue-manager.c
>   create mode 100644 drivers/spi/companion/queue-manager.h
>   create mode 100644 include/linux/companion.h
> 

^ permalink raw reply


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